• WPF中的单实例对象数据绑定


    WPF的数据绑定非常强大,可以省去我们在winform下的不少难写代码。本文主要探讨一下WPF中单实例对象数据绑定。

    WPF的单实例对象数据绑定的需求主要起源于我写的一个下载工具,我写了一个自动关机的功能,然后想把这个自动关机的状态同时双向绑定到工具栏和菜单中,而工具栏和菜单是分别在两个不同的UserControl中写的,它们之间不共享数据。这样把配置数据绑定到多个不同的控件的需求还有不少。

    首先我想到的方式是将配置数据写成静态属性,然后通x:Static过标记直接绑定静态属性到控件上,但是很快就发现了这样的局限性:不能实现双向数据绑定。原因很简单:双向数据绑定的时候,是基于实现了INotifyPropertyChanged的对象通知的。静态属性的变更自然无法通知出去。

    既然静态属性的形式不行,就想到了将数据绑定到单实例对象中,便用SINGLETON模式实现了一个,实例代码如下:

    <StackPanel>
    <CheckBox Content="AutoPowerOff1" IsChecked="{Binding Path=AutoPowerOff, Mode=Default, Source={x:Static src:ConfigData.Instance}}"/>
    <CheckBox Content="AutoPowerOff2" IsChecked="{Binding Path=AutoPowerOff, Mode=Default, Source={x:Static src:ConfigData.Instance}}"/>
    </StackPanel>


    //SINGLETON模式
    class ConfigData : System.ComponentModel.INotifyPropertyChanged
    {

        public static ConfigData Instance = new ConfigData();

        private ConfigData() { }

        bool autoPowerOff = false;
        public bool AutoPowerOff
        {
            get { return autoPowerOff; }
            set { autoPowerOff = value; NotifyPropertyChange("AutoPowerOff"); }
        }

        #region INotifyPropertyChanged
    成员

        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

        void NotifyPropertyChange(string proper)
        {
            if (PropertyChanged == null)
                return;
            PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(proper));
        }

        #endregion
    }

    这个代码毕竟简单,将两个checkbox的check状态分别绑定到ConfigData的AutoPowerOff属性中,通过静态属性Source={x:Static src:ConfigData.Instance}指定到同一个数据源,所以一个checkbox的状态变更会同步更新到另一个checkbox。实现了我们的需求。

    SINGLETON模式非常简单有效,然而有一点让我们不大爽的地方,那就是不支持blend自动绑定,需要手工敲不少代码。Blend的数据绑定中,只能自动生成对象,然后将数据绑定到生产的对象中,类似这种形式。

    <StackPanel>
        <StackPanel.Resources>
        
        <src:ConfigData x:Key="ConfigDataDataSource" d:IsDataSource="True"/>
        
        <src:ConfigData x:Key="ConfigDataDataSource1" d:IsDataSource="True"/>
        
        
        </StackPanel.Resources>
        
        <CheckBox Content="AutoPowerOff1" IsChecked="{Binding Path=AutoPowerOff, Mode=Default, Source={StaticResource ConfigDataDataSource}}"/>
        <CheckBox Content="AutoPowerOff2" IsChecked="{Binding Path=AutoPowerOff, Mode=Default, Source={StaticResource ConfigDataDataSource1}}"/>
    </StackPanel

    要让我们的单实例对象能在blend生成的绑定代码下工作,可以通过使用MonoState模式来实现。代码如下:

    class ConfigData : System.ComponentModel.INotifyPropertyChanged
    {
        static bool autoPowerOff = false;
        public bool AutoPowerOff
        {
            //
    把这个属性设置为static也可以双向绑定,但由于blend不会列出对象的静态属性,需要手工输入属性名
            get { return autoPowerOff; }
            set { autoPowerOff = value; NotifyPropertyChange("AutoPowerOff"); }
        }

        #region INotifyPropertyChanged
    成员

        static List<ConfigData> instanceList = new List<ConfigData>();
        System.ComponentModel.PropertyChangedEventHandler propertyChanged;
        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged
        {
            add { propertyChanged += value; instanceList.Add(this); }
            remove { propertyChanged -= value; instanceList.Remove(this); }
        }

        static void NotifyPropertyChange(string proper)
        {
            foreach (var obj in instanceList)
            {
                if (obj.propertyChanged == null)
                    continue;
                obj.propertyChanged(obj, new System.ComponentModel.PropertyChangedEventArgs(proper));
            }
        }

        #endregion
    }

    MonoState模式比较巧妙的将blend创建的多个对象的数据共享了起来,对于blend来说,创建了多个对象,而用起来却和一个实例对象一样。更具有通用性。

    在WPF的数据绑定中使用MonoState模式关键是PropertyChangedEventHandler事件的通知,由于WPF是基于对象通知的,而所有的对象是共享的数据,因此需要把该事件通知到所有实例。这里我通过采用保存实例列表来实现所有通知的,比较简单,没有考虑效率问题(这种对象一共也创建不了几个),但应该有更高效的方式来实现同样的功能。

    本文的代码中还存在一个问题,那就是在代码中对AutoPowerOff属性的访问问题,在不创建对象的前提下,一种方式是把它设置为static类型,这样就可以在代码中通过ConfigData.AutoPowerOff直接的访问,但这样blend不能直接列出该属性,需要手工输入一下。另外一种方式是综合SINGLETON模式创建一个静态的实例,在代码中通过ConfigData. Instance.AutoPowerOff访问。

  • 相关阅读:
    jQuery easyui datagrid pagenation 的分页数据格式
    Mysql操作符号
    jquery JSON的解析方式
    线程有几种状态
    工作日志2014-07-07
    leetcode
    Fragment中的setUserVisibleHint()方法调用
    Android开发:Eclipse中SqliteManager插件使用
    海南出差报告总结(案件录入与案件追踪系统)
    Python学习十四:filter()
  • 原文地址:https://www.cnblogs.com/TianFang/p/1515562.html
Copyright © 2020-2023  润新知