Get result of a Binding in code - wpf

I'm probably searching for this the wrong way, but:
is there any way to get the resulting value of a binding through code?
Probably something glaring obvious, but I just can't find it.

You just need to call the ProvideValue method of the binding. The hard part is that you need to pass a valid IServiceProvider to the method... EDIT: actually, that's not true... ProvideValue returns a BindingExpression, not the value of the bound property.
You can use the following trick:
class DummyDO : DependencyObject
{
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(DummyDO), new UIPropertyMetadata(null));
}
public object EvalBinding(Binding b)
{
DummyDO d = new DummyDO();
BindingOperations.SetBinding(d, DummyDO.ValueProperty, b);
return d.Value;
}
...
Binding b = new Binding("Foo.Bar.Baz") { Source = dataContext };
object value = EvalBinding(b);
Not very elegant, but it works...

Related

WPF: TwoWay Binding doesn't update back

I have the following custom control:
<abc:MyControl MyProperty="{Binding FieldInMyModel, Mode=TwoWay}">
And in my custom control I have
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(double), typeof(MyControl),
new PropertyMetadata(0.0, OnMyPropertyChanged));
public double MyProperty
{
get { return (double)GetValue(MyPropertyProperty ); }
set { SetValue(MyPropertyProperty , value); }
}
private static void OnMyPropertyChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
if (d is MyControl mc)
{
// here I check if the new value is valid for my scope.
// if it is not I update it here to be valid
var v = (double)e.NewValue;
if (!mc.IsValidValue(v))
{
v = mc.MakeValidValue(v);
mc.MyProperty = v;
}
}
}
In my model I change the value of FieldInMyModel to be not valid for my scope. OnMyPropertyChanged is called, and after making a valid value from received invalid value I expect that the FieldInMyModel will be updated to have the new value of MyProperty but actually nothing happens. Any thought?
Setting MyProperty from code will break your TwoWay Binding.
Instead you can use SetCurrentValue method.

How to get value from Binding object in Code as a string (WPF)

I'd like to get value from Binding in my code and use it as a string. How Can I do that?
Binding b = new Binding("MyProperty")
{
Source = myobject
};
//[...]
string value = b //HOW TO GET VALUE FROM b ?
BTW:
I would like the Converter attached to Binding to be called when retrieving this value.
I found that the solution could be an auxiliary class with DependencyProperty.
Auxiliary class
public class TestClass : FrameworkElement
{
public string MyProperty
{
get { return (string)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register("MyProperty", typeof(string), typeof(TestClass), new PropertyMetadata(""));
}
Binding conversion to String
Binding b = new Binding("MyProperty") { Source = myobject };
TestClass tc = new TestClass { DataContext = b };
BindingOperations.SetBinding(tc, TestClass.MyPropertyProperty, b);
string txt = tc.MyProperty;
Advantages:
You can use Binding and MultiBinding
You can use Converters
Disadvantages:
Each time we create a class that inherits from the FrameworkElement, which means that we do unnecessary operations.

Binding is not working for the first time in WPF

I have the following code in my sample.
public string MyProperty
{
get { return (string)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register("MyProperty", typeof(string), typeof(MainWindow), new PropertyMetadata("Hello"));
private TestClass1 test;
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Binding binding = new Binding
{
Path = new PropertyPath("MyProperty"),
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
test.SetValueBinding(binding);
test.DataContext = this;
Console.WriteLine(test.Value);
}
public class TestClass1 : FrameworkElement
{
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(TestClass1), new PropertyMetadata(null));
public void SetValueBinding(Binding binding)
{
this.SetBinding(ValueProperty, binding);
}
}
After binding is set, if i access test.Value, it returns null for the first time. After that,if i access it (from another method) it returns correct value "Hello".
But i do not know first time why binding is not working and null value is returned? any suggestion?
Thanks in advance.
It's not that you can't get the value for the first time. It's that you can't get it so fast. When binding is set at the time the DataContext is NULL, the source is resolved in a deferred way, perhaps later by the UI thread. You ask for value just after the binding is set, too early to get valid results.
You should switch lines in your code to:
test.DataContext = this;
test.SetValueBinding(binding);
This way the binding gets the value immediately from DataContext in the first instruction.

WPF Get real value from a custom validation rule

I use custom validation rule to validate my data. But I can't access/determine the property value.
here is my code
public class MandatoryRule: ValidationRule
{
public MandatoryRule()
{
ValidationStep = System.Windows.Controls.ValidationStep.UpdatedValue;
}
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
BindingExpression exp = value as BindingExpression;
if (value == null)
return new ValidationResult(true, null);
return new ValidationResult(true, null);
}
}
I need to set the ValidationStep to UpdatedValue (for further business logic)
Then comes the problem: I don't know what's the property value? Because:
It is a generic validator, can't bound to a specific model
The value in parameter of Validate method is a BindingExpression
So how can I read the real value?
Thanks
At last, I come up with this idea.
Create a class DummyObject : DependencyObject.
Create a public static DependencyProperty DummyProperty.
Then create a new databinding, copy the source, binding path, element name, converter, etc from the (value as BindingExpression).ParentBinding.
Set the new databinding target to the dummyobject.
Then use the binding to UpdateTarget()
And now you can access the value from the dummyproperty.
Had the same issue and came accross this question, Gary's answer seems to be the way to go, but it lacked the source code. So here's my interpretation.
public class BindingExpressionEvaluator : DependencyObject
{
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("ValueProperty", typeof(object),
typeof(BindingExpressionEvaluator), new UIPropertyMetadata(null));
public static object Evaluate(BindingExpression expression)
{
var evaluator = new BindingExpressionEvaluator();
var binding = new Binding(expression.ParentBinding.Path.Path);
binding.Source = expression.DataItem;
BindingOperations.SetBinding(evaluator, BindingExpressionEvaluator.ValueProperty, binding);
var value = evaluator.Value;
BindingOperations.ClearBinding(evaluator, BindingExpressionEvaluator.ValueProperty);
return value;
}
}

Bound Property Setter not getting Called

I have a problem with the following scenario (code cut for brevity). Basically the Setter of my User Control Property isn't being called when the dependency property is set and I need to get around this.
I have the following code in my View.xaml
<Filter:Filter x:Name="ProductFilter" PrimaryItemSource="{Binding CarrierProducts}" />
In the View.xaml.cs
public ProductPricing()
{
InitializeComponent();
ViewModel.Filter.ProductPricing vm = new ViewModel.Filter.ProductPricing();
this.DataContext = vm;
}
In my ViewModel I expose a property
public ObservableCollection<Model.FilterItem> _carrierProducts;
public ObservableCollection<Model.FilterItem> CarrierProducts
{
get
{
return _carrierProducts;
}
set
{
if (_carrierProducts != value)
{
_carrierProducts = value;
RaisePropertyChanged("CarrierProducts");
}
}
}
Finally the Filter User control is defined like so.
public static readonly DependencyProperty PrimaryItemSourceProperty =
DependencyProperty.Register("PrimaryItemSource", typeof(ObservableCollection<Model.FilterItem>), typeof(Filter), new PropertyMetadata(null));
public ObservableCollection<Model.FilterItem> PrimaryItemSource
{
get
{
return (ObservableCollection<Model.FilterItem>)GetValue(PrimaryItemSourceProperty);
}
set
{
SetValue(PrimaryItemSourceProperty, value);
ComboBox combo = _filters.ElementAt(0);
FilterSourceChange(combo, value);
}
}
For some reason the PrimaryItemSource property is set but the Setter doesn't get called. Do I have to add a PropertyChange event to the PropertyMetadata object to handle this as that seems like a lot of code for something simple.
This is how a Dependency property that requires additional code to be run on set should be written:-
public ObservableCollection<Model.FilterItem> PrimaryItemSource
{
get { return (ObservableCollection<Model.FilterItem>)GetValue(PrimaryItemSourceProperty); }
set { SetValue(PrimaryItemSourceProperty , value); }
}
public static readonly DependencyProperty PrimaryItemSourceProperty =
DependencyProperty.Register(
"PrimaryItemSource",
typeof(ObservableCollection<Model.FilterItem>),
typeof(Filter), new PropertyMetadata(null, OnPrimaryItemSourceChanged));
private static void OnPrimaryItemSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Filter filter = (Filter)d;
var oldValue = (ObservableCollection<Model.FilterItem>)e.OldValue;
var newValue = (ObservableCollection<Model.FilterItem>)e.NewValue;
filter.OnPrimaryItemSourceChanged(oldValue, newValue);
}
protected virtual void OnPrimaryItemSourceChanged(
ObservableCollection<Model.FilterItem> oldValue,
ObservableCollection<Model.FilterItem> newValue)
{
ComboBox combo = _filters.ElementAt(0);
FilterSourceChange(combo, newValue);
}
You use place a static DependencyPropertyChanged handler in the class that will cast down the dependency object to the correct type and then call an instance method to alert that instance of the change.
This change handler will get called whenever the underlying dependency property is changed be that via the SetValue call in the property Set method or by binding or any other means.
Yes, always use the callback if you need additional logic for the setter. This is a must in Silverlight and WPF.
As far as I know, the Setter would only be called when actually used from code. When you do Binding, things happen using the DependencyProperty framework.
You should also wrap your ComboBox combo = ... code into a this.Dispatcher.BeginInvoke(() => ... );, because that ensures the visual tree is initialized.
The Last parameter of the DependencyProperty.Register() method takes a PropertyMetaData where you're passing null. One of the overloads of the constructor takes a PropertyChangedCallback. Use this overload to define a callback function that will be called when your property is modified.
static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Filter filter = d as Filter;
ComboBox combo = filter._filters.ElementAt(0);
filter.FilterSourceChange(combo, filter.PrimaryItemSource);
}

Resources