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

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

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

    让我们假设我有以下问题。..

    <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)的数量。既然你有一个,你不妨利用它。

    编辑1

    …当然,现在我重新阅读了你的帖子,我发现还有更多。你为“根”收藏中的每一件物品都找到了孩子。

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

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

    现在你应该能够说:

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

    编辑2

    好的,您正在使用Silverlight,因此{x:Static}对您不可用。

    我能想到的另一个让你重用一个静态资源而不必声明两个的选项是直接在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    14 年前

    对不起,伙计们,我对你们在这里想做什么有点困惑。..不管怎样,从标题听起来,你好像想把值转换器中的一个属性转换为值转换器中一个属性。首先,看看我写的一篇文章,它详细解释了如何做到这一点: http://nick-howard.blogspot.com/2011/06/silverlight-4-value-converter.html

    因此,您要做的是在LoadChildrenValueConverter中创建一个ObvervableCollection依赖属性,为了便于参数,我们称之为Children。

    然后,在您的xaml中,您可以将LoadChildrenValueConverter更改为如下内容:

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

    希望这能有所帮助。