代码之家  ›  专栏  ›  技术社区  ›  Inferis

IValueConverter上的数据绑定

  •  7
  • Inferis  · 技术社区  · 16 年前

    有人知道是否可以在基于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) {
            ...
        }
    }
    

    它的目的是通过其Id在列表中查找文章,并返回该文章。

    <local:LookupArticleConverter Articles="{Binding Articles}" x:Key="LookupArticle"/>
    

    但这似乎不起作用。永远不会调用setter方法。source属性包含一个实际的非空集合,所以这不是问题所在。

    有什么线索吗?

    3 回复  |  直到 16 年前
        1
  •  10
  •   surfen    13 年前

    所以,问题是资源不是可视化树的一部分。要实现这一目标,您必须:

    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 ...
    
    }
    

    <UserControl (...) x:Name=myUserControl> 
    <UserControl.Resources>
    <CustomConverter x:Key="customConverter"
                        LookupItems="{Binding ElementName=myUserControl, Path=DataContext.LookupItems}"/>
    </UserControl.Resources>
    
        2
  •  3
  •   Tim Cooper    13 年前
        3
  •  0
  •   BadBiki    13 年前

    我已将RelativeSource方法添加到绑定语句中。这解决了我在Control.Resources.ResourceDictionary树下定义了IValueConverter,并且我正在尝试从Control.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>
    

    我在这里很棘手,根据IValueConverter中定义的一些规则改变StackPanel定位其内容的方式。我使用转换器上的绑定来禁用或启用ViewModel中的规则。我也可以通过这个方法设置规则,或者传递一个lambda表达式进行验证。请原谅我的打字错误。