windows phone:数据绑定(2)

windows phone:数据绑定(二)

通知机制
数据绑定的目标必须是依赖属性,但是对于绑定的源,并没有严格的要求。绑定源可以是普通类的普通属性。但是如果你希望绑定源在变化的时候,绑定目标也随之自动更新,那么绑定源必须实现某种通知机制。
通常用作绑定源的业务对象需要实现的通知机制称为INotofyPropertyChanged接口,该接口定义在System.ComponentModel命名空间中。
INotifyPropertyChanged定义如下所示:
public interface INotifyPropertyChanged
{
 event PropertyChangedEventHandler PropertyChanged;
}
实现INotifyPropertyChanged接口的类只需要简单地定义一个公共事件PropertyChanged。理论上,这个派生类并不需要为这个事件做任何特殊的处理,但是当它的某个属性发生变化时,可以通过这个事件来触发变更事件。
由于实现了INotifyPropertyChanged接口的业务对象并没有继承FrameworkElement,它们并不是xaml文件中可视化树的组成部分,因此它们通常会被实例化为xaml资源或者位于代码隐藏文件中。
下面例子是一个钟表应用,代码如下所示:
    public class Clock : INotifyPropertyChanged  //实现了INotifyPropertyChanged接口
    {
        int hour, min, sec;
        DateTime date;

        public event PropertyChangedEventHandler PropertyChanged;

        public Clock()
        {
            OnTimerTick(null, null);

            DispatcherTimer tmr = new DispatcherTimer();
            tmr.Interval = TimeSpan.FromSeconds(0.1);
            tmr.Tick += OnTimerTick;
            tmr.Start();
        }

        public int Hour
        {
            protected set
            {
                if (value != hour)
                {
                    hour = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("Hour"));
                }
            }
            get
            {
                return hour;
            }
        }

        public int Minute
        {
            protected set
            {
                if (value != min)
                {
                    min = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("Minute"));
                }
            }
            get
            {
                return min;
            }
        }

        public int Second
        {
            protected set
            {
                if (value != sec)
                {
                    sec = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("Second"));
                }
            }
            get
            {
                return sec;
            }
        }

        public DateTime Date
        {
            protected set
            {
                if (value != date)
                {
                    date = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("Date"));
                }
            }
            get
            {
                return date;
            }
        }

        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, args);
        }

        void OnTimerTick(object sender, EventArgs args)
        {
            DateTime dt = DateTime.Now;
            Hour = dt.Hour;
            Minute = dt.Minute;
            Second = dt.Second;
            Date = DateTime.Today;
        }
    }
在xaml中直接使用Clock类,代码如下所示:
<TextBlock>
 <TextBlock.Text>
  <Binding Path="Second">
   <Binding.Source>   //这里使用的是Source而非ElementName
    <local:Clock />   //这里的local是Clock的命名空间
   </Binding.Source>
  </Binding>
 </TextBlock.Text>
</TextBlock>
或者先将Clock类定义为xaml资源:
<phone:PhoneApplicationPage.Resources>
 <local:Clock x:Key="clock" />
 ...
</phone:PhoneApplicationPage.Resources>
再使用:
<TextBlock Text="{Binding Source={StaticResource clock},Path=Second}" />
再次强调:绑定目标(例如TextBlock的Text属性)必须是依赖属性。