Does anybody know if it is possible to do databinding on an IValueConverter based class?
I have the following converter:
[ValueConversion(typeof(int), typeof(Article))]
public class LookupArticleConverter : FrameworkElement, IValueConverter {
public static readonly DependencyProperty ArticlesProperty = DependencyProperty.Register("Articles", typeof(IEnumerable<Article>), typeof(LookupArticleConverter));
public IEnumerable<Article> Articles
{
get { return (IEnumerable<Article>)GetValue(ArticlesProperty); }
set { SetValue(ArticlesProperty, value); }
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
...
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
...
}
}
It's purpose is to lookup an article in a list by its Id, and return that article.
However, I'd like to fill the Articles property by databinding a collection to it, like this:
<local:LookupArticleConverter Articles="{Binding Articles}" x:Key="LookupArticle"/>
But this doesn't seem to work. The setter method is never called. The source property contains an actual nonempty collection, so that's not the problem.
There's no error messages regarding binding in the output log, neither.
Any clues?
The IValueConverter interface consists of two methods, Convert() and ConvertBack() . Convert method gets called when source updates target object. ConvertBack method gets called when target updates source object.
As advertised, it just implements the two required methods, called Convert() and ConvertBack(). The Convert() methods assumes that it receives a string as the input (the value parameter) and then converts it to a Boolean true or false value, with a fallback value of false.
Create a converter by implementing the IValueConverter interface and implementing the Convert method. That method should return an object that is of the same type as the dependency property that the binding targets, or at least a type that can be implicitly coerced or converted to the target type.
Data binding is the process that establishes a connection between the app UI and the data it displays. If the binding has the correct settings and the data provides the proper notifications, when the data changes its value, the elements that are bound to the data reflect changes automatically.
So, the problem is that resources are not part of the visual tree. To make this work you have to:
public class CustomConverter : Freezable, IValueConverter
{
public static readonly DependencyProperty LookupItemsProperty =
DependencyProperty.Register("LookupItems", typeof(IEnumerable<LookupItem>), typeof(CustomConverter), new PropertyMetadata(default(IEnumerable<LookupItem>)));
public IEnumerable<LookupItem> LookupItems
{
get { return (IEnumerable<LookupItem>)GetValue(LookupItemsProperty); }
set { SetValue(LookupItemsProperty, value); }
}
#region Overrides of Freezable
/// <summary>
/// When implemented in a derived class, creates a new instance of the <see cref="T:System.Windows.Freezable"/> derived class.
/// </summary>
/// <returns>
/// The new instance.
/// </returns>
protected override Freezable CreateInstanceCore()
{
return new CustomConverter();
}
#endregion Overrides of Freezable
// ... Usual IValueConverter stuff ...
}
<UserControl (...) x:Name=myUserControl>
<UserControl.Resources>
<CustomConverter x:Key="customConverter"
LookupItems="{Binding ElementName=myUserControl, Path=DataContext.LookupItems}"/>
</UserControl.Resources>
WPF doesn't really support this intrinsically. However, there are some techniques that will allow you to do this, including Josh Smith's virtual branch approach.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With