【问题标题】:Data Binding POCO Properties数据绑定 POCO 属性
【发布时间】:2010-10-10 18:06:36
【问题描述】:

是否有任何数据绑定框架(BCL 或其他)允许在实现INotifyPropertyChangedINotifyCollectionChanged任意两个CLR 属性之间进行绑定?似乎应该可以做这样的事情:

var binding = new Binding();
binding.Source = someSourceObject;
binding.SourcePath = "Customer.Name";
binding.Target = someTargetObject;
binding.TargetPath = "Client.Name";
BindingManager.Bind(binding);

其中someSourceObjectsomeTargetObject 只是实现INotifyPropertyChanged 的POCO。但是,我不知道有任何 BCL 对此提供支持,并且不确定是否存在允许这样做的现有框架。

更新:鉴于没有可用的现有库,我自己编写了自己的库。它是可用的here

谢谢

【问题讨论】:

    标签: c# .net data-binding poco system.componentmodel


    【解决方案1】:

    AutoMapper 可以在两个实例之间复制值,但您必须编写自己的代码才能自动完成。

    【讨论】:

      【解决方案2】:

      也许Bindable LINQcontinuous linq 可以在这里提供帮助。如果您尝试添加实际上是实际更新数据的“派生属性”的模型属性,以使您的 UI 更容易绑定,那么这两个框架应该会有所帮助。

      【讨论】:

        【解决方案3】:

        我不知道有任何 这样做 - 但您可以相当轻松地编写自己的。

        这是我在几分钟内敲定的一个基础,它在两个简单属性之间建立了双向数据绑定:

        public static class Binder
        {
        
            public static void Bind(
                INotifyPropertyChanged source,
                string sourcePropertyName,
                INotifyPropertyChanged target,
                string targetPropertyName)
            {
                var sourceProperty
                    = source.GetType().GetProperty(sourcePropertyName);
                var targetProperty
                    = target.GetType().GetProperty(targetPropertyName);
        
                source.PropertyChanged +=
                    (s, a) =>
                    {
                        var sourceValue = sourceProperty.GetValue(source, null);
                        var targetValue = targetProperty.GetValue(target, null);
                        if (!Object.Equals(sourceValue, targetValue))
                        {
                            targetProperty.SetValue(target, sourceValue, null);
                        }
                    };
        
                target.PropertyChanged +=
                    (s, a) =>
                    {
                        var sourceValue = sourceProperty.GetValue(source, null);
                        var targetValue = targetProperty.GetValue(target, null);
                        if (!Object.Equals(sourceValue, targetValue))
                        {
                            sourceProperty.SetValue(source, targetValue, null);
                        }
                    };
            }
        }
        

        当然,这段代码缺少一些细节。要添加的内容包括

        • 检查 sourcetarget 是否已分配
        • 检查sourcePropertyNametargetPropertyName 标识的属性是否存在
        • 检查两个属性之间的类型兼容性

        此外,Reflection 相对较慢(尽管在丢弃它之前对其进行基准测试,但它并没有那么慢),因此您可能希望改用已编译的表达式。

        最后,鉴于通过字符串指定属性容易出错,您可以改用 Linq 表达式和扩展方法。然后代替写

        Binder.Bind( source, "Name", target, "Name")
        

        你可以写

        source.Bind( Name => target.Name);
        

        【讨论】:

        • 我实际上是在问,因为我正在考虑自己写。不想重新发明轮子……谢谢。
        • 更新:我已在问题中链接到我的图书馆。
        • 我需要一个简单的准系统数据绑定类来满足我当前的急需项目,而上面的类几乎符合我的需要。我刚刚用两个 Action 委托替换了 Reflection 使用的属性名称,我在其中从 POCO 获取/设置并应用转换和格式化。我一定会在下一个项目中尝试使用 Truss,因为这听起来对我来说真的很有趣。
        • 您好,有点晚了(现在是 2012 年),但您不认为源中的任何属性更改都会引发事件 source.PropertyChanged 并且我们只对一个属性感兴趣?性能好不好?
        • @thewpfguy,当 PropertyChanged 事件触发时,需要处理三种情况: 我们的属性;不是我们的财产;和每个属性(空字符串)。理论上,正如您所指出的,我们应该编写代码来识别正在发生的情况并做出相应的反应。在实践中,我们谈论的只是节省几微秒的 CPU 时间。当我们在人类可感知的范围内谈论持续时间时,那些微秒并不重要。如果您每秒抛出数千个 PropertyChanged 通知,那么您的代码就会出现更大的问题。
        【解决方案4】:

        如果你将你的属性定义为DependencyProperty's 你就可以做到。 WF 和 WPF 都有它的实现(第一个链接是 WPF。对于 WF,它是 this 一个)所以你需要决定使用哪个 - 但两者都应该满足你的需要。

        【讨论】:

        • DependencyProperty 意味着继承自 DependencyObject,它不是 POCO。
        • 嗯?不知道你投票赞成威尔的逻辑是什么。这两个建议都不能满足我的需要,因为这两个建议都没有涉及 POCO。另一篇文章已经表明您可以使用 POCO 来做到这一点 - 我只是要求一个能够完成繁重工作的框架。
        【解决方案5】:

        我写了Truss来填补空白。

        【讨论】:

          【解决方案6】:

          我编写了一个小型 Bind 项目,它完全支持嵌套属性异步绑定操作之间的绑定。语法再简单不过了:

          //Two way binding between neasted properties:
          Bind.TwoWay(()=> client.Area.Data.Name == this.AreaName);
          
          //On change action execute:
          Bind
              .OnChange(()=> client.Personal.Name)
              .Do(x => clientName = x);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-02-04
            • 1970-01-01
            • 1970-01-01
            • 2015-04-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-01-14
            相关资源
            最近更新 更多