通过Attached Property给控件绑定Command(三)

  第三篇会是我们讨论的终章。希望文中关于依赖属性和数据绑定的使用,能够抛砖引玉,各位各抒己见给我一些启迪。

  首先我们看一下最终的XAML,可能在看到XAML后各位已经猜出了具体的实现。这次我又增加了第四个Rectangle,颜色是Gray。同时对该Rectangle设置了Name=“rect”。

<Rectangle x:Name="rect" Width="100" Height="100" Fill="Gray"></Rectangle>
<local:ElementBinder EventName="MouseLeftButtonDown" 
                     Command="{Binding ViewModel.MouseLeftDownCommand, ElementName=window}"
                     Parameter="{Binding ElementName=rect}"
                     Target="{Binding ElementName=rect}">
</local:ElementBinder>

  我们注意到其实ElementBinder并不是Rectangle的属性,而仅仅是ElementBinder中的Target属性绑定了Rectangle。

  这其中的不同在于ElementBinder是继承自FrameworkElement,而其中的EventName、Command、Parameter和Target都从附加属性变成了普通的依赖属性。不再附加到其他的某个DependencyObject之上,而仅仅是作为ElementBinder的属性存在。之所以继承自FrameworkElement,是因为在该类提供了数据绑定的能力,如果继承自UIElement就无法实现Binding的功能了。

  其实ElementBinder这个类写在XAML里,并没有和任何的控件产生关联,之所以可以绑定Command到Rectangle,是因为新增的Target属性。通过该属性才取得了与某个UIElement(这里是Rectangle)的联系。

        public UIElement Target
        {
            get { return (UIElement)GetValue(TargetProperty); }
            set { SetValue(TargetProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Target.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TargetProperty =
            DependencyProperty.Register("Target", typeof(UIElement), typeof(ElementBinder), new UIPropertyMetadata(ChangedCallback));

        private static void ChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            UIElement element = d.GetValue(TargetProperty) as UIElement;
            if (element != null)
            {
                string eventName = d.GetValue(EventNameProperty) as string;
                if (eventName != null)
                {
                    EventInfo eventInfo = element.GetType().GetEvent(eventName);
                    var handler = new MouseButtonEventHandler((sender, arg) =>
                    {
                        object obj = d.GetValue(ParameterProperty);
                        ICommand command = d.GetValue(CommandProperty) as ICommand;
                        command.Execute(obj);
                    });
                    var del = handler.GetInvocationList()[0];

                    eventInfo.AddEventHandler(element, del);
                }
            }
        }

  在代码中我们首先找到了ElementBinder对象的Target属性,取得Target属性的值,也正是我们希望关联的控件Rectangle,之后的逻辑和前面一篇是一样的。

  本来是没有打算写第三篇的,这个通过FrameworkElement建立关联来绑定的思路也不是我想到的,是得到上篇提到的微软哥韦恩卑鄙给出的解决方案。在学习了之后我也分享给大家。

  链接包含了文中所用到的代码,我总共创建了4个Rectangle,又用了4种不同的方式去关联Command,如果各位闲暇之余想出了“回字的第5种写法”,望不吝赐教。

  https://files.cnblogs.com/manupstairs/TestDPWpf.7z

posted @ 2012-11-10 17:29  楼上那个蜀黍  阅读(1312)  评论(0编辑  收藏  举报