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

Silverlight数据绑定-将ValueConverter绑定到视图模型上的属性

  •  2
  • herbrandson  · 技术社区  · 16 年前

    让我们假设我有以下xaml。。。

    <UserControl.Resources>
        <local:ViewModel x:Name="viewModel" />
        <local:LoadChildrenValueConverter x:Name="valueConverter" />
    </UserControl.Resources>
    
    <UserControl.DataContext>
        <Binding Source="{StaticResource viewModel}" />
    </UserControl.DataContext>
    
    <Grid x:Name="LayoutRoot" Background="White">
        <control:TreeView ItemsSource="{Binding Root}">
            <control:TreeView.ItemTemplate>
                <control:HierarchicalDataTemplate ItemsSource="{Binding Converter={StaticResource valueConverter}}">
                    <TextBlock Text="{Binding}" />
                </control:HierarchicalDataTemplate>
            </control:TreeView.ItemTemplate>
        </control:TreeView>
    </Grid>
    

    using System;
    using System.Collections.ObjectModel;
    using System.Windows.Data;
    
    namespace SilverlightViewModelSpike
    {
        public class ViewModel
        {
            public ViewModel()
            {
                Root = new ObservableCollection() { "Item 1", "Item 2", "Item 3", };
            }
    
            public ObservableCollection Root { get; private set; }        
        }
    
        public class LoadChildrenValueConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                return new ObservableCollection() { "Item 1", "Item 2", "Item 3", };
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    }
    

    这正如预期的那样工作,但我有两个单独的类来获取视图所需的数据(假设ViewModel和LoadChildrenValueConverter从web服务中提取数据,而不是返回硬编码数据),这感觉是错误的。这里有更好的解决方案吗?我在想也许是这样的。。。

    using System;
    using System.Collections.ObjectModel;
    using System.Windows.Data;
    
    namespace SilverlightViewModelSpike
    {
        public class ViewModel
        {
            public ViewModel()
            {
                Root = new ObservableCollection() { "Item 1", "Item 2", "Item 3", };
                ValueConverter = new LoadChildrenValueConverter();
            }
    
            public ObservableCollection Root { get; private set; }
            public LoadChildrenValueConverter ValueConverter { get; private set; }
        }
    
        public class LoadChildrenValueConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                return new ObservableCollection() { "Item 1", "Item 2", "Item 3", };
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    }
    

    ... 但是我不能让这条线工作。。。

    <control:HierarchicalDataTemplate ItemsSource="{???}"

    2 回复  |  直到 16 年前
        1
  •  4
  •   Matt Hamilton    16 年前

    由于您使用的是ViewModel,它位于实际模型和视图之间,因此我想知道直接在其中实现IValueConverter逻辑是否更容易。有点像:

    public class ViewModel
    {
        public ObservableCollection Root { get; set: }
    
        public ObservableCollection Children
        {
            get { /* return children items */ }
        }
    }
    

    <control:HierarchicalDataTemplate ItemsSource="{Binding Children}">
    

    我认为ViewModel对象的主要目的是限制从原始模型获取所需数据所需的“技巧”(如IValueConverters)的数量。既然你有一个,你不妨利用它。

    ... 当然,现在我重读了你的帖子,我看到了更多的内容。您将获得“根”集合中每个项目的子项。

    在ViewModel本身中将IValueConverter作为静态实例实现如何?

    public class ViewModel : IValueConverter
    { 
        public static readonly IValueConverter ChildrenConverter
            = new LoadChildrenValueConverter();
    }
    

    现在你应该能够说:

    <control:HierarchicalDataTemplate 
        ItemsSource="{Binding Converter={x:Static local:ViewModel.ChildrenConverter}}">
    

    编辑2

    我能想到的唯一另一种方法是在ViewModel中直接实现IValueConverter,它可以让您重用一个静态资源,而不必声明两个静态资源。如果您需要进行多种类型的转换,这是不好的,但是如果您的ViewModel聚焦非常窄,那么它可以完成这项工作。因此:

    public class ViewModel : IValueConverter
    {
        // move your Convert and ConvertBack methods into here
    }
    

    现在您可以执行以下操作:

    <control:HierarchicalDataTemplate
        ItemsSource="{Binding Converter={StaticResource ViewModel}}">
    
        2
  •  0
  •   Nick Howard    13 年前

    对不起,伙计们,我有点搞不懂你们想在这里做什么。。。不管怎样,从标题上看,似乎您希望将值转换器中的属性转换为值转换器中的属性。首先看一看我写的一篇文章,其中详细解释了如何做到这一点: http://nick-howard.blogspot.com/2011/06/silverlight-4-value-converter.html

    因此,您要做的是在LoadChildrenValueConverter中创建一个ObvervableCollection依赖项属性,为方便起见,我们将其称为Children。

    这样,您只需要从视图模型中调用一次web服务,然后就可以使用值转换器共享视图模型中的ObvervableCollection。

    希望有帮助。