本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《
一个最简单的应用视图的例子如下,我们要借助视图完成将ListBox中的当前项移到下一个及上一个(注意:单纯的绑定集合,甚至连这个简单的功能也难实现)。
<Window.Resources>
<local:People x:Key="Family">
<local:Person Name="Tom" Age="11"></local:Person>
<local:Person Name="John" Age="12"></local:Person>
<local:Person Name="Melissa" Age="38"></local:Person>
</local:People>
</Window.Resources>
<Grid DataContext="{StaticResource Family}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListBox x:Name="listBoxPeople" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" Grid.Row="0" Grid.Column="1" Height="100" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock Text="{Binding Path=Name}" Width="150"></TextBlock>
<TextBlock Text="{Binding Path=Age}" Width="150"></TextBlock>
<Button x:Name="buttonShow" Click="buttonShow_Click">show</Button>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Grid.Row="1" Grid.Column="0">Name:</TextBlock>
<TextBox x:Name="txtName" Text="{Binding Path=Name}" Grid.Row="1" Grid.Column="1"></TextBox>
<TextBlock Grid.Row="2" Grid.Column="0">Age:</TextBlock>
<TextBox x:Name="txtAge" Text="{Binding Path=Age}" Grid.Row="2" Grid.Column="1"></TextBox>
<StackPanel Grid.Row="3" Grid.Column="1" Orientation="Horizontal">
<Button x:Name="buttonShowSelected" Click="buttonShowSelected_Click">显示选中项</Button>
<Button x:Name="buttonAdd" Click="buttonAdd_Click">新加</Button>
<Button x:Name="buttonPrevious" Click="buttonPrevious_Click">上一个</Button>
<Button x:Name="buttonNext" Click="buttonNext_Click">下一个</Button>
</StackPanel>
</Grid>
public partial class Window1 : Window
public Window1()
InitializeComponent();
private void buttonShowSelected_Click(object sender, RoutedEventArgs e)
if (listBoxPeople.SelectedItem == null)
return;
Person person = listBoxPeople.SelectedItem as Person;
MessageBox.Show(string.Format("person:{0},Age {1}", person.Name, person.Age));
private void buttonPrevious_Click(object sender, RoutedEventArgs e)
ICollectionView view = GetFamilyView();
view.MoveCurrentToPrevious();
private void buttonNext_Click(object sender, RoutedEventArgs e)
ICollectionView view = GetFamilyView();
view.MoveCurrentToNext();
private void buttonShow_Click(object sender, RoutedEventArgs e)
Button button = sender as Button;
Person person = button.DataContext as Person;
MessageBox.Show(string.Format("person:{0},Age {1}", person.Name, person.Age));
ICollectionView GetFamilyView()
People people = this.FindResource("Family") as People;
return CollectionViewSource.GetDefaultView(people);
private void buttonAdd_Click(object sender, RoutedEventArgs e)
string name = txtName.Text.Trim();
int age = Int16.Parse(txtAge.Text.Trim());
Person person = new Person() { Name=name, Age=age};
People people = this.FindResource("Family") as People;
people.Add(person);
class Person
public string Name { get; set; }
public int Age { get; set; }
class People: ObservableCollection<Person>
2:变更集合
在上文代码中,我们已经完成了添加一个记录到集合中。删除也是同理。
在上文代码中,我们加入一个排序按钮,同时为排序按钮增加点击事件如下:
private void buttonSort_Click(object sender, RoutedEventArgs e)
ICollectionView view = GetFamilyView();
view.SortDescriptions.Add(new SortDescription("Age", ListSortDirection.Ascending));
则,列表中的条目就会按照年龄升序排列。以上这种做法在大多数情况下已经够用。因为基本上排序的内容都是基本型别,而基本型别都提供了默认的比较器(有关比较器概念,参看http://www.cnblogs.com/luminji/archive/2010/09/30/1839038.html)。但是,难免我们会用到自定义排序的时候(如对IP地址排序),这个时候,我们就要编码实现。现在,为了简单起见,我们仍旧选择按年龄进行排序,但是排序要被处理成自定义排序。首先需要撰写一个自定义排序类:
class PersonAgeSort: IComparer
#region IComparer 成员
public int Compare(object x, object y)
Person personx = x as Person;
Person persony = y as Person;
if (personx.Age > persony.Age)
return 1;
else if (personx.Age == persony.Age)
return 0;
return -1;
//return personx.Age.CompareTo(persony.Age);
#endregion
然后,按钮事件改为:
private void buttonSort_Click(object sender, RoutedEventArgs e)
ListCollectionView view = GetFamilyView() as ListCollectionView;
view.CustomSort = new PersonAgeSort();
注意按钮事件中,我们将GetFamilyView方法返回值转型为了ListCollectionView。因为他在WPF时用来包装IList接口并提供视图功能的类。在WPF中还有一些ICollectionView接口的实现,但有些不提供自定义排序,所以在使用起来要注意。尤其觉得遗憾的是,没有提供泛型实现的视图类。综上所述,上文代码起码有两点遗憾:
1:虽然列表数据使用的是class People: ObservableCollection<Person> 型别,但是视图却使用ListCollectionView ;
2:没有提供泛型实现的视图类,导致排序的时候的拆箱和装箱操作过多,影响效率。
最后提供默认的数据集视图供参考:
集合数据 默认视图 注释
IEnumerable CollectionView 无法对项进行分组。
IList ListCollectionView 最快。
IBindingList BindingListCollectionView
4:过滤筛选
为上文代码增加一个排序按钮,同时为该排序按钮提供点击事件如下:
private void buttonFilter_Click(object sender, RoutedEventArgs e)
ICollectionView view = GetFamilyView();
view.Filter = delegate(object target)
return ((Person)target).Age > 25;
//view.Filter = new Predicate<object>(delegate(object target)
// {
// return ((Person)target).Age > 25;
// });
过滤比较简单,不在赘述。在这里只要理解Predicate<object>型别这个委托变量Filter就行了。
我们来考虑一种最简单的分组。假设对列表中的数据按照Age进行分组,这个意思就是,假设列表中有11,22,22,28四个年龄的人员,则分组后,将有11,22,28三个组。要是实现这个功能,为上文代码添加一个分组按钮,并为该按钮提供一个点击事件:
private void buttonGroup_Click(object sender, RoutedEventArgs e)
ICollectionView view = GetFamilyView();
view.GroupDescriptions.Add(new PropertyGroupDescription("Age"));
以上代码运行后,发现点击分组按钮,什么也没有发生,那是因为我们没有提供为ListBox提供组样式。记住,所有派生自ItemsControl的类都能进行分组显示,但是我们必须为它提供组样式。组样式,事实是一个GroupStyle的实例,如果没有特殊要求,我们可以使用GroupStyle为我们提供的Default静态属性来实现一个默认样式。上文的例子,我们只要在前台代码中加入如下代码,即可运行:
<ListBox x:Name="listBoxPeople" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" Grid.Row="0" Grid.Column="1" Height="100" >
<ListBox.GroupStyle>
<x:Static Member="GroupStyle.Default"></x:Static>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
这种默认的GroupStyle样式太古板,还可以自定义GroupStyle。如下:
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock>
<TextBlock>年龄:</TextBlock>
<TextBlock Text="{Binding Path=Name}"></TextBlock>
<TextBlock>数量:</TextBlock>
<TextBlock Text="{Binding Path=ItemCount}"></TextBlock>
</TextBlock>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListBox.GroupStyle>
注意:在GroupStyle中绑定的Name不是指Person中的Name,而是view.GroupDescriptions.Add(new PropertyGroupDescription("Age"));中指定的这个Age。
上文也说了,这是一种最简单的分组,在实际应用中,分组往往要复杂的多。比如以年龄分组来说,就不可能像上文中一样,以一岁做为一组。现在,我们来实现如下的分组要求:
0-30:年轻;
30-60:中年;
>60:老年;
所有的自定义分组器都需要实现接口IValueConverter,如下:
class AgeToRangeConver: IValueConverter
#region IValueConverter 成员
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
int iValue = (int)value;
if (0 < iValue && iValue <= 30)
return "年轻";
else if (30 < iValue && iValue <= 60)
return "中年";
return "老年";
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
throw new NotImplementedException();
#endregion
然后,点击事件修改为:
private void buttonGroup_Click(object sender, RoutedEventArgs e)
ICollectionView view = GetFamilyView();
view.GroupDescriptions.Add(new PropertyGroupDescription("Age", new AgeToRangeConver()));
可以看到,分组已经按我们的要求实现了。
本文转自最课程陆敏技博客园博客,原文链接:http://www.cnblogs.com/luminji/archive/2011/02/09/1950149.html,如需转载请自行联系原作者
原文:WPF QuickStart系列之数据绑定(Data Binding)
这篇博客将展示WPF DataBinding的内容。
首先看一下WPF Data Binding的概览,
Binding Source可以是任意的CLR对象,或者XML文件等,Binding Target需要有依赖属性。
使用MVVM DataTriggers在WPF XAML视图之间切换/Window窗口自适应内容大小并居中
原文 使用MVVM DataTriggers在WPF XAML视图之间切换
相关文章:
http://www.technical-recipes.com/2016/switching-between-wpf-xaml-views-using-mvvm-datatemplate/
这篇文章解决了能够根据ViewModel类的属性在不同视图之间切换的问题。
本以为Label也有TextChanged
事件,但在使用的时候却没找到,网友说Label的Content属性改变肯定是使用赋值操作,赋值的时候就可以对其进行相应的操作所以不需TextChanged