Silverlight学习笔记四:如何通过自定义ComboBox实现SelectedValue
2009-01-06 11:24
633 查看
一、发现问题。
继续学习SL,这次用到了ComboBox,自带的ComboBox可以通过ItemSource和DisplayMemberPath来实现Items的数据绑定,DisplayMemberPath类似于Asp.net控件中的DataTextField,但是奇怪的是,ComboBox并没有提供类似与DataValueField这样的属性,也就是说,在使用SelectedItem的使用,我们无法像过去一样,直接赋一个值就可以让它选择对应的Item,现在的SelectedItem必须是ItemSource里面的一个对象,这样使用起来会非常的麻烦,比如说,我们让ComboBox绑定到Suppliers集合,DisplayMemberPath为CompanyName,这个时候,如果我们想通过SupplierID来指定ComboBox的SelectedItem时,就必须到ItemSource中,按照SupplierID来找到对应的Supplier对象,再把这个Supplier赋给SelectedItem才行。
所以这里又要骂微软了,真的不知道他们是怎么想的,学习SL这段时间来,感觉他们在做SL的时候,想的太理想化,像个科研产品,不适合商用。很多常用的功能都给他们改的面目全非,把简单问题复杂化。
二、解决问题。
要解决这个问题,我们需要自己动手来写一个新的ComboBox,并给它添加上SelectedValuePath和SelectedValue这两个属性。
这里参考了Jones的SilverLight ComboBox,这篇文章,原文在这里http://www.engineserver.com/silverlightcombobox/。
代码基本上和他的一样,但是修改了他代码中的部分问题,使其更加像Asp.net中的DropDownList。
我们新建了一个类,让它继承ComboBox,并且添加了SelectedValuePathProperty和SelectedValueProperty。这样,我们就可以通过Binding来和数据库进行绑定了,我在用Jones的代码时,界面出现之后,ComboBox并不会按照SelectedValuePath来显示指定的数据,但是在手工选择ComboBox里面的Item只有,它就能很好的工作了,这个很奇怪的问题花了我不少时间,结果发现,在SetBinding的时候,虽然我们让其Bind到SelectedValueProperty上,但是系统并没有通过SelectedValue的Set来赋值,所以SelectedValue的Set的代码并不会执行,这就导致初始化的时候,ComboBox并不按照Bind的显示数据。
后来,我在SelectedValuePropertyChanged中,对SelectedValue进行了赋值,使其可以正确工作。
ok,基本上就这么多了,其实整个功能很简单。下面看代码:
自定义ComboBox的代码:
ComboBoxClassic
public class ComboBoxClassic : ComboBox
{
#region SelectedValuePathProperty
public static readonly DependencyProperty SelectedValuePathProperty =
DependencyProperty.Register("SelectedValuePath", typeof(string),
typeof(ComboBoxClassic), null);
public string SelectedValuePath
{
get
{
return (string)GetValue(ComboBoxClassic.SelectedValuePathProperty);
}
set
{
SetValue(ComboBoxClassic.SelectedValuePathProperty, value);
}
}
#endregion
#region SelectedValueProperty
public static DependencyProperty SelectedValueProperty =
DependencyProperty.Register("SelectedValue", typeof(object), typeof(ComboBoxClassic),
new PropertyMetadata(new PropertyChangedCallback(SelectedValuePropertyChanged)));
public object SelectedValue
{
get
{
return GetValue(SelectedValueProperty);
}
set
{
try
{
var q = (from item in Items
where item.GetType().GetProperty(SelectedValuePath).GetValue(item, null).Equals(value)
select item).Single();
SelectedItem = q;
}
catch
{
throw new Exception();
}
}
}
private static void SelectedValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as ComboBoxClassic).SelectedValue = e.NewValue;
}
#endregion
public ComboBoxClassic()
: base()
{
base.SelectionChanged += new SelectionChangedEventHandler(ComboBoxClassic_SelectionChanged);
}
void ComboBoxClassic_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (SelectedItem != null && !string.IsNullOrEmpty(SelectedValuePath))
{
try
{
SetValue(ComboBoxClassic.SelectedValueProperty, SelectedItem.GetType().GetProperty(SelectedValuePath).GetValue(SelectedItem, null));
var value = SelectedValue;
}
catch
{
throw new Exception();
}
}
}
}
调用的方法:
我们假设编写一个修改数据的窗体,传入ProductID后,在界面上显示多个TextBox和ComboBox,ComboBox中显示Suppliers的信息,并和Product中的SupplierID绑定。
先通WCF获取Suppliers数据,并绑定到ItemSource上。同时设置了DisplayMemberPath和SelectedValuePath属性。
void client_getAllSuppliersCompleted(object sender, getAllSuppliersCompletedEventArgs e)
{
cb.ItemsSource = e.Result;
cb.DisplayMemberPath = "CompanyName";
cb.SelectedValuePath = "SupplierID";
}
使用时,先获取Product信息,再绑定
void client_getProductCompleted(object sender, getProductCompletedEventArgs e)
{
products = e.Result;
//设置ComboBox所在的Grid的DataContext。
content.DataContext = products;
//设置Bind信息,让其和Product的SupplierID绑定。
//使用TwoWay,这样ComboBox在SelectedItem变动之后,会自动更新Product的SupplierID。
System.Windows.Data.Binding bind = new System.Windows.Data.Binding("SupplierID");
bind.Mode = System.Windows.Data.BindingMode.TwoWay;
cb.SetBinding(ComboBoxClassic.SelectedValueProperty, bind);
}
继续学习SL,这次用到了ComboBox,自带的ComboBox可以通过ItemSource和DisplayMemberPath来实现Items的数据绑定,DisplayMemberPath类似于Asp.net控件中的DataTextField,但是奇怪的是,ComboBox并没有提供类似与DataValueField这样的属性,也就是说,在使用SelectedItem的使用,我们无法像过去一样,直接赋一个值就可以让它选择对应的Item,现在的SelectedItem必须是ItemSource里面的一个对象,这样使用起来会非常的麻烦,比如说,我们让ComboBox绑定到Suppliers集合,DisplayMemberPath为CompanyName,这个时候,如果我们想通过SupplierID来指定ComboBox的SelectedItem时,就必须到ItemSource中,按照SupplierID来找到对应的Supplier对象,再把这个Supplier赋给SelectedItem才行。
所以这里又要骂微软了,真的不知道他们是怎么想的,学习SL这段时间来,感觉他们在做SL的时候,想的太理想化,像个科研产品,不适合商用。很多常用的功能都给他们改的面目全非,把简单问题复杂化。
二、解决问题。
要解决这个问题,我们需要自己动手来写一个新的ComboBox,并给它添加上SelectedValuePath和SelectedValue这两个属性。
这里参考了Jones的SilverLight ComboBox,这篇文章,原文在这里http://www.engineserver.com/silverlightcombobox/。
代码基本上和他的一样,但是修改了他代码中的部分问题,使其更加像Asp.net中的DropDownList。
我们新建了一个类,让它继承ComboBox,并且添加了SelectedValuePathProperty和SelectedValueProperty。这样,我们就可以通过Binding来和数据库进行绑定了,我在用Jones的代码时,界面出现之后,ComboBox并不会按照SelectedValuePath来显示指定的数据,但是在手工选择ComboBox里面的Item只有,它就能很好的工作了,这个很奇怪的问题花了我不少时间,结果发现,在SetBinding的时候,虽然我们让其Bind到SelectedValueProperty上,但是系统并没有通过SelectedValue的Set来赋值,所以SelectedValue的Set的代码并不会执行,这就导致初始化的时候,ComboBox并不按照Bind的显示数据。
后来,我在SelectedValuePropertyChanged中,对SelectedValue进行了赋值,使其可以正确工作。
ok,基本上就这么多了,其实整个功能很简单。下面看代码:
自定义ComboBox的代码:
ComboBoxClassic
public class ComboBoxClassic : ComboBox
{
#region SelectedValuePathProperty
public static readonly DependencyProperty SelectedValuePathProperty =
DependencyProperty.Register("SelectedValuePath", typeof(string),
typeof(ComboBoxClassic), null);
public string SelectedValuePath
{
get
{
return (string)GetValue(ComboBoxClassic.SelectedValuePathProperty);
}
set
{
SetValue(ComboBoxClassic.SelectedValuePathProperty, value);
}
}
#endregion
#region SelectedValueProperty
public static DependencyProperty SelectedValueProperty =
DependencyProperty.Register("SelectedValue", typeof(object), typeof(ComboBoxClassic),
new PropertyMetadata(new PropertyChangedCallback(SelectedValuePropertyChanged)));
public object SelectedValue
{
get
{
return GetValue(SelectedValueProperty);
}
set
{
try
{
var q = (from item in Items
where item.GetType().GetProperty(SelectedValuePath).GetValue(item, null).Equals(value)
select item).Single();
SelectedItem = q;
}
catch
{
throw new Exception();
}
}
}
private static void SelectedValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as ComboBoxClassic).SelectedValue = e.NewValue;
}
#endregion
public ComboBoxClassic()
: base()
{
base.SelectionChanged += new SelectionChangedEventHandler(ComboBoxClassic_SelectionChanged);
}
void ComboBoxClassic_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (SelectedItem != null && !string.IsNullOrEmpty(SelectedValuePath))
{
try
{
SetValue(ComboBoxClassic.SelectedValueProperty, SelectedItem.GetType().GetProperty(SelectedValuePath).GetValue(SelectedItem, null));
var value = SelectedValue;
}
catch
{
throw new Exception();
}
}
}
}
调用的方法:
我们假设编写一个修改数据的窗体,传入ProductID后,在界面上显示多个TextBox和ComboBox,ComboBox中显示Suppliers的信息,并和Product中的SupplierID绑定。
先通WCF获取Suppliers数据,并绑定到ItemSource上。同时设置了DisplayMemberPath和SelectedValuePath属性。
void client_getAllSuppliersCompleted(object sender, getAllSuppliersCompletedEventArgs e)
{
cb.ItemsSource = e.Result;
cb.DisplayMemberPath = "CompanyName";
cb.SelectedValuePath = "SupplierID";
}
使用时,先获取Product信息,再绑定
void client_getProductCompleted(object sender, getProductCompletedEventArgs e)
{
products = e.Result;
//设置ComboBox所在的Grid的DataContext。
content.DataContext = products;
//设置Bind信息,让其和Product的SupplierID绑定。
//使用TwoWay,这样ComboBox在SelectedItem变动之后,会自动更新Product的SupplierID。
System.Windows.Data.Binding bind = new System.Windows.Data.Binding("SupplierID");
bind.Mode = System.Windows.Data.BindingMode.TwoWay;
cb.SetBinding(ComboBoxClassic.SelectedValueProperty, bind);
}
相关文章推荐
- Silverlight学习笔记[7] - silverlight中如何得到ComboBox的选中值(SelectedValue)?
- Silverlight学习笔记三:如何自定义DataGrid的Header
- SilverLight学习笔记--Silverligh之如何显示用户自定义的 Splash Screen (初始屏幕)
- WPF and Silverlight.ComboBox 如何通过 Binding IsDropDownOpen 实现下拉菜单展开
- [原创]java WEB学习笔记55:Struts2学习之路---详解struts2 中 Action,如何访问web 资源,解耦方式(使用 ActionContext,实现 XxxAware 接口),耦合方式(通过ServletActionContext,通过实现 ServletRequestAware, ServletContextAware 等接口的方式)
- OpenCV示例学习笔记(1)-contours2.cpp-通过findContours 函数实现轮廓提取
- mfc学习笔记之如何自己动手实现最简单的mfc程序
- torch学习笔记3.3:实现自定义模块(gpu)
- MVC学习十四:ASP.NET MVC如何实现自定义验证 AgeRangeAttribute
- c++11学习笔记3——通过更通用的方法实现新特性
- CVP认证学习笔记--李天宇004实现自定义场景
- android 学习笔记:自定义通用ListView/GridView,实现ListAdapter 类
- SilverLight学习笔记--实际应用(一)(8):手把手建立一个Silverlight应用程序之应用自定义TextBox控件
- 【知了堂学习笔记】mybatis通过代理实现增删改查
- [dotnetCore2.0]学习笔记之二: ASP.NET Core中,如何灵活使用静态文件和加载自定义配置
- Silverlight学习笔记[6] - 如何:定义 Windows Communication Foundation 服务协定
- 强大的DataGrid组件[8]_内嵌ComboBox动态数据联动——Silverlight学习笔记[16]
- unity 4.6新UI系统学习笔记 如何通过脚本访问并修改Text组件
- 强大的DataGrid组件[5]_实现CURD[下]——Silverlight学习笔记[13]
- 安卓Studio学习笔记---gradle自定义BuildConfig.DEBUG实现在调试输出Log,正式的时候不输出Log