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

时间:2008-12-15 22:47:53

标签: silverlight data-binding mvvm treeview

让我假装我有以下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="{???}"&GT;

......即使这似乎也不是一个很好的解决方案。有人为此提供了一个很好的清洁解决方案吗?

2 个答案:

答案 0 :(得分:4)

由于您正在使用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

...当然,现在我重新阅读你的帖子,我发现还有更多内容。您正在为“Root”集合中的每个项目获取子项。

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

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

答案 1 :(得分:0)

对不起家伙我对你在这里想要做什么感到有点困惑...无论如何,从标题中听起来好像你想要将价值转换器中的属性转换为价值转换器中的属性。首先看看我写的一篇文章,解释你如何做到这一点: http://nick-howard.blogspot.com/2011/06/silverlight-4-value-converter.html

所以你要做的是在你的LoadChildrenValueConverter中创建一个ObvervableCollection依赖属性,为了参数,让我们称之为Children。

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

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

希望有所帮助。