博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Impossible WPF Part 1: Binding Properties
阅读量:5760 次
发布时间:2019-06-18

本文共 4931 字,大约阅读时间需要 16 分钟。

原文 

Ever wanted to write the following?

 

I noticed at least one user on the MSDN Forums who did. The general answer is that it's not possible - because Document isn't a DependencyProperty. Sometime last year I wrote a utility that I hoped would solve this very problem. Back then, it didn't work properly, but with increased WPF experience I gave it another shot. This time it seems to pass the basic tests I throw at it.

The concept is a "Proxy" FrameworkElement with two DependencyProperties, one Input and one Output. The Input property is tied to the Output such that when Input changes it is applied to Output.

This effectively binds the Document property of a RichTextBox. If the above doesn't make sense it's probably due to the default settings on the Out property. Namely BindsTwoWayByDefault and UpateSourceTrigger.PropertyChanged.

I'll post the entire Proxy source at the end of this entry, but for now let's step through some of the more interesting details.

 

FrameworkPropertyMetadata inMetadata = new FrameworkPropertyMetadata(    delegate(DependencyObject p, DependencyPropertyChangedEventArgs args)    {        (p as Proxy).Out = args.NewValue;    });

The PropertyChangedCallback for the In property does as you probably expected, it just sets the new value on the Out property.

But we also need a PropertyChangedCallback for the Out property. I wanted the Proxy to bind two-way by default so that in the event the source (the non-DependencyProperty) changed, the proxy would overwrite the change with the In value. In some cases it is also necessary to overwrite the initial value. If the In property changes or is bound before Out is bound the In value is not always propagated. Fortunately when Out is bound it calls its own PropertyChangedCallback allowing us to propagate the initial value.

FrameworkPropertyMetadata outMetadata = new FrameworkPropertyMetadata(    delegate(DependencyObject p, DependencyPropertyChangedEventArgs args)    {        Proxy proxy = p as Proxy;        object expected = proxy.In;        if (!object.ReferenceEquals(args.NewValue, expected))        {                Dispatcher.CurrentDispatcher.BeginInvoke(                    DispatcherPriority.Background,                    new Operation(delegate                    {                        proxy.Out = proxy.In;                    }));        }    });

The PropertyChangedCallback for Out does just that. It checks if Out is the same as In and if not asynchronously (so as not to confuse the binding engine) overwrites Out with In.

As promised, here is the complete source code.

public class Proxy : FrameworkElement{    public static readonly DependencyProperty InProperty;    public static readonly DependencyProperty OutProperty;    public Proxy()    {        Visibility = Visibility.Collapsed;    }    static Proxy()    {        FrameworkPropertyMetadata inMetadata = new FrameworkPropertyMetadata(            delegate(DependencyObject p, DependencyPropertyChangedEventArgs args)            {                if (null != BindingOperations.GetBinding(p, OutProperty))                    (p as Proxy).Out = args.NewValue;            });        inMetadata.BindsTwoWayByDefault = false;        inMetadata.DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;        InProperty = DependencyProperty.Register("In",            typeof(object),            typeof(Proxy),            inMetadata);        FrameworkPropertyMetadata outMetadata = new FrameworkPropertyMetadata(            delegate(DependencyObject p, DependencyPropertyChangedEventArgs args)            {                ValueSource source = DependencyPropertyHelper.GetValueSource(p, args.Property);                if (source.BaseValueSource != BaseValueSource.Local)                {                    Proxy proxy = p as Proxy;                    object expected = proxy.In;                    if (!object.ReferenceEquals(args.NewValue, expected))                    {                        Dispatcher.CurrentDispatcher.BeginInvoke(                            DispatcherPriority.DataBind, new Operation(delegate                                {                                    proxy.Out = proxy.In;                                }));                    }                }            });        outMetadata.BindsTwoWayByDefault = true;        outMetadata.DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;        OutProperty = DependencyProperty.Register("Out",            typeof(object),            typeof(Proxy),            outMetadata);    }    public object In    {        get { return this.GetValue(InProperty); }        set { this.SetValue(InProperty, value); }    }    public object Out    {        get { return this.GetValue(OutProperty); }        set { this.SetValue(OutProperty, value); }    }}

And finally, a complete example.

Bind
This!

转载地址:http://stlkx.baihongyu.com/

你可能感兴趣的文章
hbase region split源码分析
查看>>
MySQL备份之分库分表备份脚本
查看>>
Java 与 Netty 实现高性能高并发
查看>>
SurfControl人工智能新突破 领跑反垃圾邮件
查看>>
一个动态ACL的案例
查看>>
openstack 之 windows server 2008镜像制作
查看>>
VI快捷键攻略
查看>>
Win server 2012 R2 文件服务器--(三)配额限制
查看>>
卓越质量管理成就创新高地 中关村软件园再出发
查看>>
linux rsync 远程同步
查看>>
httpd的manual列目录漏洞
查看>>
myeclipse2014破解过程
查看>>
漫谈几种反编译对抗技术
查看>>
Timer 和 TimerTask 例子
查看>>
Spring BOOT 集成 RabbitMq 实战操作(一)
查看>>
安装python3.5注意事项及相关命令
查看>>
进程通信之无名信号量
查看>>
并发串行调用接口
查看>>
CMD 修改Host文件 BAT
查看>>
android幻灯片效果实现-Gallery
查看>>