【问题标题】:WPF difficult binding: bind value to IConverter with as input the result from a static methodWPF 困难绑定:将值绑定到 IConverter,并将静态方法的结果作为输入
【发布时间】:2011-10-15 19:49:15
【问题描述】:

我想知道是否可以使用以下类型的绑定,但我无法形成一个搜索查询来给我明确的答案,或者在任何地方找到它。

就是这样。

我有一个带有“项目”(自定义类)的列表框,这些项目使用项目模板显示。我使用转换器来计算背景颜色。见下文:

<Window.Resources>
    <local:MyConverter x:Key="myConverter"/>
</Window.Resources>

<!-- snip -->
<ListBox Grid.Row="2" Name="listBoxMaterialType" Margin="0,0,0,0" ItemsSource="{Binding Path=MyItems, ElementName=MySource}">
    <ListBox.ItemTemplate>
        <DataTemplate>
                <TextBlock Text="{Binding DisplayText}" Background="{Binding Converter={StaticResource myConverter}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

现在为了更好的抽象,我希望 MyConverter 不转换项目,而只是转换项目的分数。一个项目不知道它自己的分数,但分数是通过调用 MyStaticClass.MyStaticMethod(item); 计算出来的。所以在代码中我想做这样的绑定: myTextBlock.Background= MyConverter(MyStaticClass.MyStaticMethod(item));是否可以通过数据绑定在 WPF 中做到这一点?

【问题讨论】:

    标签: c# wpf xaml data-binding converter


    【解决方案1】:

    传统上,ViewModel 的角色是获取您的域对象并公开视图所需的数据。这可以包括添加新属性,这些属性是模型属性的聚合或转换(例如,通过连接 FirstName 和 Surname 模型属性来提供 FullName 属性)。在你的情况下:

    public class Item
    {
        public string DisplayText { get; set; }
    }
    
    public class ItemViewModel
    {
        private Item _model;
    
        public string DisplayText
        {
            get { return _model.DisplayText; }
        }
    
        public int Score
        {
            get { return MyStaticClass.MyStaticMethod(_model);
        }
    }
    

    然后,使用 ViewModel 作为 DataContext,您可以将转换器直接绑定到 Score 属性。

    【讨论】:

    • 虽然这个问题并不能解决我的问题,但我认为这是最好的答案,因为它“解决了”我试图用 XAML 解决的潜在问题。
    【解决方案2】:

    你可以做很多事情,例如您可以向转换器添加一些属性,将其指向一个方法。这些可能是例如TargetTypeTargetObjectMethodName,然后您可以 - 通过指定MethodName 和其他任何一个属性 - 使转换器调用TargetObject 上的方法或静态调用。

    例如像这样:

    //<Property declarations>
    
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        bool staticCall = TargetObject == null;
        var types = new Type[] { value.GetType() };
        var args = new object[] { value };
        MethodInfo method;
        if (staticCall)
        {
            method = TargetType.GetMethod(MethodName, types);
        }
        else
        {
            method = TargetObject.GetType().GetMethod(MethodName, types);
        }
        var score = method.Invoke(TargetObject, args);
    
        //Convert score
    }
    

    (和所有粗略的 sn-ps 一样,不要盲目地复制粘贴,这可能很糟糕)

    <vc:MyConverter x:Key="ScoreConverter"
                    TargetType="{x:Type local:MyStaticClass}"
                    MethodName="MyStaticMethod"/>
    

    【讨论】:

    • 这实际上是一个非常简洁的选择,但感觉有点 hacky :)。
    • 一点也不 hacky,整个绑定系统都依赖于这样的反射。同样在Interactivity 中,您可以找到CallMethodAction,它与TargetObject 类似,但更严格,因为它需要TargetObject
    • 啊,是的,没错。我仍然对使用所有这些反射有点谨慎,但事实上,没有它就无法完成所有绑定。我会试试这个sn-p。 (ofc 不仅仅是 c/p-ing ;))
    • 您可能还想考虑使用一些管道转换器,因为这似乎将两个单独的转换器组合在一起,一个方法转换器和一个分数到画笔转换器。我问了一个关于如何做到这一点的问题here,接受的答案中的选项 C 很有趣,或者请参阅my own answer 的问题以获取草图。
    【解决方案3】:

    当然,转换器通过应用您所描述的静态函数来完成其工作:从项目到颜色。一切顺利。

    如果您考虑到分数上的某些条件可能会改变颜色,就会出现问题。您认为可以通过哪种方式触发绑定来更新颜色值(从而调用转换器)?

    我想这更多是结构问题而不是技术问题。

    编辑: 要么我不明白这个问题,要么解决方案很简单:

        public class MyConverter
            : IValueConverter
        {
            public object Convert(
                object value, 
                Type targetType, 
                object parameter, 
                System.Globalization.CultureInfo culture)
            {
                return MyStaticClass.MyStaticMethod(value as MyItem);
            }
    
            public object ConvertBack(
                object value, 
                Type targetType, 
                object parameter, 
                System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    

    我也会将 Mode=OneTime 添加到绑定子句中。

    干杯

    【讨论】:

    • 我只需要从分配给项目的分数到控件的背景颜色的单向(一次)绑定。分数不会改变,你不能改变颜色来改变分数。我目前使用您在转换器内部应用静态函数的方式,但这将我的转换器与记分器紧密联系在一起。
    • 关于编辑:这是关于我想避免的代码(尽管转换器首先转换 MyStaticMethod 的返回值),但我现在有。
    猜你喜欢
    • 2011-08-23
    • 1970-01-01
    • 2013-12-23
    • 1970-01-01
    • 1970-01-01
    • 2015-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多