Привязка данных к IValueConverter
кто-нибудь знает, можно ли выполнить привязку данных к классу на основе IValueConverter?
у меня такой конвертер:
[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) {
...
}
}
цель состоит в том, чтобы найти статью в списке по ее идентификатору и вернуть эту статью.
однако я хотел бы заполнить свойство Articles путем привязки к нему коллекции данных, например:
<local:LookupArticleConverter Articles="{Binding Articles}" x:Key="LookupArticle"/>
но это, похоже, не работает. Метод setter никогда не вызывается. Свойство source содержит фактическая непустая коллекция, так что это не проблема.
в выходном журнале также нет сообщений об ошибках, касающихся привязки.
какие-то зацепки?
3 ответов
WPF на самом деле не поддерживает это внутренне. Однако, есть некоторые методы, которые позволят вам сделать это, в том числе виртуальный филиал подход.
Итак, проблема заключается в том, что ресурсы не являются частью визуального дерева. Чтобы сделать эту работу вы должны:
1. Сделайте ваш ValueConverter наследовать Freezable
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 ...
}
2. Привязка к визуальному дереву с помощью привязки ElementName
<UserControl (...) x:Name=myUserControl>
<UserControl.Resources>
<CustomConverter x:Key="customConverter"
LookupItems="{Binding ElementName=myUserControl, Path=DataContext.LookupItems}"/>
</UserControl.Resources>
Я добавил метод RelativeSource в оператор binding. Это решает проблему, когда у меня есть мой IValueConverter, определенный под управлением.Ресурсы.Дерево ResourceDictionary, и я пытаюсь получить DataContext из элемента управления.Класс DataContext
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Resources/Text.xaml"/>
<ResourceDictionary Source="/Resources/Layout.xaml"/>
<ResourceDictionary Source="/Resources/Colours.xaml"/>
<ResourceDictionary Source="/Resources/Icons.xaml"/>
</ResourceDictionary.MergedDictionaries>
<conv:OrientationConverter x:Key="OerientationConverter" IsOrientationRuleEnabled="{Binding Path=DataContext.IsSiteLayoutPhysical, RelativeSource={RelativeSource AncestorType={x:Type UserControl}, Mode=FindAncestor}}"/>
....
<ListView x:Name="operationsListView" ItemsSource="{Binding .}" DataContext="{Binding GroupedPlantItems}" ItemsPanel="{DynamicResource ItemsPanelTemplate1}" Panel.ZIndex="-10">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.Panel >
<ItemsPanelTemplate>
<StackPanel Orientation="{Binding Name, Converter={StaticResource OerientationConverter}}"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<GroupBox Header="{Binding Name}">
<ItemsPresenter/>
</GroupBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
Я здесь хитрый и меняю способ, которым StackPanel ориентирует свое содержимое на основе некоторых правил, определенных в IValueConverter. Я использую привязку конвертера, чтобы отключить или включить правила из моего модель представления. Я также мог бы установить правила этим методом или, возможно, передать ему лямбда-выражение для проверки. прошу прощения за опечатки.