一个依赖项属性的应用

一种应用方法是使用依赖项属性代替INotifyPropertyChanged接口,将界面绑定的数据源属性声明为依赖项属性,就可以自动更新到界面了,使用了wpf的内置机制,之前有一篇文章写了一个例子。

今天写的应用是重写一个控件,新空间使用依赖项属性来扩展wpf内置控件的功能,不过我的这个控件更多是为了方便使用,类似于是老控件的一个对象,只用于某种特殊的表示方式,来源于一道面试题,两个comboBox,一个是省名称,一个是市名称,当省的comboBox选项改变时,市comboBox列表也随之改变,用依赖项属性实现。

首先来展示一下,如果不使用依赖项属性,正常的做法

声明两个comboBox,一个是省,一个是市

<ComboBox Grid.Row="0" Name="ProvienceComboBox" Height="30" ItemsSource="{Binding Path=Proviences}" SelectionChanged="ComboBox_SelectionChanged"
SelectedValuePath="Id" DisplayMemberPath="Name" SelectedIndex="0">
</ComboBox>
<ComboBox Grid.Row="1" Name="CityComboBox" Height="30" SelectedIndex="0" SelectedValuePath="Id" DisplayMemberPath="Name">
</ComboBox>

后台数据结构:

public class NotifyPropertyChangeBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
PropertyChanged(this,e);
}
}
}
//这个省数据使用依赖项属性实现,是之前提到的依赖项属性的一种应用 方法
public class ProvienceInfo : DependencyObject
{
public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name",typeof(string),typeof(ProvienceInfo));

public ProvienceInfo(string s,int id)
{
Name = s;
this.id = id;
}
private int id;
public int Id
{
set
{
if (id != value)
{
id = value;
}
}
get
{
return id;
}
}

public string Name
{
set
{
//if (name != value)
{
SetValue(NameProperty,value);
}
}
get
{
return GetValue(NameProperty).ToString();
}
}

private CityList citys;
public CityList Citys
{
get
{
return citys;
}
set
{
if (citys != value)
{
citys = value;
}
}
}
}

//市使用notify接口实现
public class CityInfo : NotifyPropertyChangeBase
{
public CityInfo(string name)
{
this.name = name;
}
private string name;
public string Name
{
set
{
if (name != value)
{
name = value;
OnPropertyChanged("Name");
}
}
get
{
return name;
}
}
}

public class ProvienceList : ObservableCollection<ProvienceInfo>
{

}

public class CityList : ObservableCollection<CityInfo>
{

}

专门为UI提供数据的数据类


public class Data
{

//假数据
public Data()
{
proviences = new ProvienceList();
citys = new CityList();
string[] s = { "hebei","henan","shandong" };
string[][] cityArrar = new string[3][];
string[] hebeicity= { "shijiazhuang","baoding","tangshan" };
string[] henancity = { "zhengzhou","pingdingshan" };
string[] shandongcity = { "qingdao","jinan" };
cityArrar[0] = hebeicity;
cityArrar[1] = henancity;
cityArrar[2] = shandongcity;

for (int i = 0; i < 3; i++)
{
ProvienceInfo pi = new ProvienceInfo(s[i],i);
CityList cl = new CityList();
proviences.Add(pi);
for (int j = 0; j < cityArrar[i].Length; j++)
{
cl.Add(new CityInfo(cityArrar[i][j]));
}
pi.Citys = cl;
}
}

ProvienceList proviences;
public ProvienceList Proviences
{
get
{
return proviences;
}
set
{
proviences = value;
}
}
}

后台的数据源绑定


public MainWindow()
{
InitializeComponent();
data = new Data();
this.DataContext = data; //给控件设置datacontext
}
//当省级的comboBox选项改变的时候变更市级comboBox的数据源
private void ComboBox_SelectionChanged(object sender,SelectionChangedEventArgs e)
{
ComboBox cb = sender as ComboBox;
object o = cb.SelectedValue;
CityComboBox.ItemsSource = (cb.SelectedItem as ProvienceInfo).Citys;
CityComboBox.SelectedIndex = 0;
}

这样就可以实现功能了。


如果使用依赖项属性,我创建了一个新类,扩展comboBox,该类中有一个citylist属性用户只需要给改属性赋值或绑定,就可以显示
public class MyComboBox : ComboBox
{
public static readonly DependencyProperty cityListProperty = DependencyProperty.Register("cityList",typeof(CityList),typeof(MyComboBox),new PropertyMetadata(null,MyPropertyChangedCallback));

static void MyPropertyChangedCallback(DependencyObject d,DependencyPropertyChangedEventArgs e)
{
MyComboBox m = d as MyComboBox;
if (m != null)
{
m.ItemsSource = m.cityList; //实际上citylist只是将itemsource封装起来了
m.SelectedIndex = 0;
}
}

public MyComboBox()
{
this.DisplayMemberPath = "Name"; //限制了只能显示city的name,或者还有其他好的办法可以进行拓展?
}

public CityList cityList
{
get
{
return (CityList)GetValue(cityListProperty);
}
set
{
SetValue(cityListProperty,value);
}
}
}

前台xaml,只需设置citylist

<local:MyComboBox x:Name="myComboBox" Grid.Row="3" cityList="{Binding Path=Citys}" SelectedIndex="0"/>

数据源中添加一个citys的数据,因为mycomboBox中需要绑定,此处省略。

当省的选项改变时,只需改变mycomboBox的citylist

private void ComboBox_SelectionChanged(object sender,SelectionChangedEventArgs e)
{
ComboBox cb = sender as ComboBox;
myComboBox.cityList = (cb.SelectedItem as ProvienceInfo).Citys;
}


此处依赖项属性的应用只是更方便的为用户提供功能,并没有扩展,要想真正扩展控件的功能,恐怕要做的还有很多。

不知此处的应用是否正确,合理,符合依赖项属性的目的,如有高见,请不吝赐教。

相关文章

适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法...
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题...
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结...
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容...