Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF Binding order how to ensure one property binds before another

Tags:

c#

binding

wpf

<Controls:MyControl Mode="Mode1" Value="{Binding Path=Something}" />

The problem I have is that binding happens before Mode property is being set when I use this control in a data template of a ListView.

How do I make sure that Mode is always set before Value binding?

like image 395
lahsrah Avatar asked Oct 05 '11 20:10

lahsrah


People also ask

What is path binding WPF?

Binding path syntax. Use the Path property to specify the source value you want to bind to: In the simplest case, the Path property value is the name of the property of the source object to use for the binding, such as Path=PropertyName . Subproperties of a property can be specified by a similar syntax as in C#.

What is oneway binding WPF?

In One Way binding, source control updates the target control, which means if you change the value of the source control, it will update the value of the target control. So, in our example, if we change the value of the slider control, it will update the textbox value, as shown below.

What is two way binding WPF?

Its very easy to do in WPF in comparison of windows Application programming. Two way binding is used when we want to update some controls property when some other related controls property change and when source property change the actual control also updates its property.

How does data binding work in WPF?

Data binding is a mechanism in WPF applications that provides a simple and easy way for Windows Runtime apps to display and interact with data. In this mechanism, the management of data is entirely separated from the way data. Data binding allows the flow of data between UI elements and data object on user interface.


3 Answers

What you could do is delay the binding, so you can be (almost) sure the mode value is set till then. There's a delay binding property in .net 4.5. Here's an article on how to simulate that in .net 4.0 Delay property on Binding from .Net 4.5 in .Net 4.0

I personally would implement that in a viewModel (MVVM), where this kind of issue is rather simple to resolve. Make two properties Mode and Something. When mode changes it should trigger that the "Something" property was changed also ( via INotifyPropertyChanged Interface).

class MyViewModel : INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
      if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    private string _mode;

    public string Mode
    {
      get { return _mode; }
      set
      {
        _mode = value;
        OnPropertyChanged("Mode");

        // OnPropertyChanged("Something");
        // or build up via a method:
        // Something = DetermineFromMode(Mode);
      }
    }

    private string _something;

    public string Something
    {
      get { return _something;  }
      set
      {
        _something = value;
        OnPropertyChanged("Something");
      }
    }
  }
like image 122
SvenG Avatar answered Nov 03 '22 00:11

SvenG


Have you tried raising the property changed event for your property "Something" when Mode of your control get set? You can get the property "Something" in you control like this -

Binding binding = BindingOperations.GetBindingExpression(this, this.Value).ParentBindingBase;
String propertyToRefresh = binding.Path.Path;

(this.DataContext as ViewModel).OnPropertyChange(propertyToRefresh);

I am assuming that the DataContext of your Control is your ViewModel's instance which implements INotifyPropertyChangedInterface.

In case your Viemodel class OnPropertyChange method is not public or you don't have reference to your ViewModel class in your control. You can simply call the UpdateTarget() on your BindingExpression like this (as suggested by Thomas Levesque) -

BindingExpression binding = BindingOperations.GetBindingExpression(this, this.Value);
binding.UpdateTarget();
like image 40
Rohit Vats Avatar answered Nov 02 '22 23:11

Rohit Vats


(I know this is old but I ran into this problem today so I was forced to do some investigation)

It appears that binding occurs in the order the DependencyProperties are defined.

For instance, in MyControl.cs

public int Mode { get => (int)GetValue(ModeProperty); set => SetValue(ModeProperty, value); }
public static readonly DependencyProperty ModeProperty
    = DependencyProperty.Register(nameof(Mode), typeof(int), typeof(MyControl),
        new FrameworkPropertyMetadata(new PropertyChangedCallback(Mode_Changed)));

public string Result { get => (string)GetValue(ResultProperty); set => SetValue(ResultProperty, value); }
public static readonly DependencyProperty ResultProperty
    = DependencyProperty.Register(nameof(Result), typeof(string), typeof(MyControl),
        new FrameworkPropertyMetadata(new PropertyChangedCallback(Result_Changed)));

private static void Mode_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    //Mode changed. Update display.
}

private static void Result_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    //Result changed. Update display.
}

And the XAML:

<controls:MyControl Result="You passed!"
                    Mode="3" />

Because Mode is defined as a dependency property before Result, Mode will be set first. The order in which you assign the values in the XAML is ignored.

So in theory, to answer your question, make sure the Mode property is defined first. This solved my issue.

like image 28
J Wilson Avatar answered Nov 02 '22 23:11

J Wilson