[原译]ListView布局管理器
介绍
使用ListViewLayoutManager 可以控制ListView/GridView列的布局
1. 固定列宽:有着固定列宽的列
2. 范围列宽:有着最小最大宽度的列
3. 比例列宽:成比例的列宽
范围列宽可以限制列的宽度,也包括填充列的剩余可视区域。
据我们了解的Html中的表格和Grid空间。比例列以一个百分比来定义列宽,以下几个因素共同确定了比例列的宽度。
1. 垂直ListView滚动条的可视与否
2. ListView控件宽度的改变
3. 非比例列宽度的改变
本程序支持通过XAML或是后台代码来控制ListView。如果通过XAML来控制。则允许ListViewLayoutManager 被附加到一个存在的ListView控件上。
ConverterGridColumn 类通过接口IValueConverter 提供了对象绑定。使用ImageGridViewColumn 类则允许通过DataTemplate(数据模板)将列显示成图片等。
在 User Setting Applied中,我展示了如何固定ListViewlieder顺序和大小
XAML中ListView/GridView布局
固定列
下面的例子展示了通过XAML使用固定列宽控制列
<ListView Name="MyListView" ctrl:ListViewLayoutManager.Enabled="true"> <ListView.View> <GridView> <GridViewColumn DisplayMemberBinding="{Binding Path=Name}" ctrl:FixedColumn.Width="100" Header="Name"/> <GridViewColumn DisplayMemberBinding="{Binding Path=City}" ctrl:FixedColumn.Width="300" Header="City"/> </GridView> </ListView.View> </ListView>
设置附加到ListView控件上的ListViewLayoutManager 的Enabled属性为True。然后FixedColumn.Width 就会阻止鼠标拖动改变列的宽度。
比例列
下面的例子展示了使用XAML通过比例来控制列
对比Grid控件的RowDefinition.Width 属性,ProportionalColumn.Width会计算百分比。简单来说,就是上面的例子中Name列会占到总宽度的25%,而City列占到75%。
与固定列相似。鼠标将不能改变列的宽度。
范围列
下面的例子展示了使用XAML通过最小/最小宽度来控制列
<ListView Name="MyListView" ctrl:ListViewLayoutManager.Enabled="true"> <ListView.View> <GridView> <GridViewColumn DisplayMemberBinding="{Binding Path=Name}" ctrl:RangeColumn.MinWidth="100" Width="150" Header="Name"/> <GridViewColumn DisplayMemberBinding="{Binding Path=City}" ctrl:RangeColumn.MaxWidth="200" Width="150" Header="City"/> <GridViewColumn DisplayMemberBinding="{Binding Path=Country}" Width="100" ctrl:RangeColumn.MinWidth="50" ctrl:RangeColumn.MaxWidth="150" Header="Country"/> <GridViewColumn DisplayMemberBinding="{Binding Path=State}" Width="100" ctrl:RangeColumn.MinWidth="100" ctrl:RangeColumn.IsFillColumn="true" Header="Country"/> </GridView> </ListView.View> </ListView>
第一个范围列的IsFillColumn 属性被设置为True,因此将会自动改变大小来填满剩余的空间,而如果ListView包含一个比例列的话,范围列将不会填充
通过鼠标可以拖动范围列的宽度。鼠标指针会有一些提示。。
组合使用
在真实的世界里。组合使用很普遍。他们的顺序可以多种多样。
<ListView Name="MyListView" ctrl:ListViewLayoutManager.Enabled="true"> <ListView.View> <GridView> <GridViewColumn DisplayMemberBinding="{Binding Path=State}" ctrl:FixedColumn.Width="25" Header="Name"/> <GridViewColumn DisplayMemberBinding="{Binding Path=Name}" Width="150" ctrl:RangeColumn.MinWidth="100" ctrl:RangeColumn.MaxWidth="200" Header="City"/> <GridViewColumn DisplayMemberBinding="{Binding Path=City}" ctrl:ProportionalColumn.Width="1" Header="Zip"/> <GridViewColumn DisplayMemberBinding="{Binding Path=Country}" ctrl:ProportionalColumn.Width="2" Header="Country"/> </GridView> </ListView.View> </ListView>
使用后台代码控制ListView/GridView布局
ListView listView=newListView(); newListViewLayoutManager(listView);// attach the layout manager GridView gridView=newGridView(); gridView.Columns.Add(FixedColumn.ApplyWidth(newMyGridViewColumn("State"),25)); gridView.Columns.Add(RangeColumn.ApplyWidth(newMyGridViewColumn("Name"),100, 150,200));// 100...200 gridView.Columns.Add(ProportionalColumn.ApplyWidth(newMyGridViewColumn("City"), 1));// 33% gridView.Columns.Add(ProportionalColumn.ApplyWidth(newMyGridViewColumn( "Country"),2));// 66% listView.View=gridView;
定制列的效果
类ConverterGridColumn 作为一个基类,用来绑定列到独立的对象。
// ------------------------------------------------------------------------ publicclassCustomer { // ---------------------------------------------------------------------- publicCustomer() { }// Customer // ---------------------------------------------------------------------- publicstringFirstName { get{returnthis.firstName;} set{this.firstName=value;} }// FirstName // ---------------------------------------------------------------------- publicstringLastName { get{returnthis.lastName;} set{this.lastName=value;} }// LastName // ---------------------------------------------------------------------- // members privatestringfirstName; privatestringlastName; }// class Customer // ------------------------------------------------------------------------ publicclassCustomerFullNameColumn:ConverterGridViewColumn { // ---------------------------------------------------------------------- publicCustomerGridViewColumn(): base(typeof(Customer)) { }// CustomerGridViewColumn // ---------------------------------------------------------------------- protectedoverrideobjectConvertValue(objectvalue) { Customer customer=value asCustomer; returnstring.Concat(customer.FirstName," ",customer.LastName); }// ConvertValue }// class CustomerFullNameColumn
列以图片展示
ImageGridColumn 作为一个基类,用来绑定列到图片
// ------------------------------------------------------------------------ publicclassCustomer { // ---------------------------------------------------------------------- publicCustomer() { }// Customer // ---------------------------------------------------------------------- publicboolIsActive { get{returnthis.isActive;} set{this.isActive=value;} }// IsActive // ---------------------------------------------------------------------- // members privateboolisActive; }// class Customer // ------------------------------------------------------------------------ publicclassCustomerActiveColumn:ImageGridViewColumn { // ---------------------------------------------------------------------- publicCustomerActiveColumn() { }// CustomerActiveColumn // ---------------------------------------------------------------------- protectedoverrideImageSource GetImageSource(objectvalue) { Customer customer=value asCustomer; if(customer!=null) { returnnewBitmapImage(newUri(customer.IsActive?"Active.png": "Inactive.png")); } returnnull; }// GetImageSource }// class CustomerActiveColumn
有意思的地方
作为ListView控件的核心部件- ListViewLayoutManager 有以下的功能
- 阻止改变固定列和比例列的宽度
- 强制了范围列的范围
- 随着ListView控件的改变而更新列布局
- 随着某一列的改变而更新布局
为了正确的接收到请求的信息,分析ListView控件的可视树是很有必要的,Thumb对象提供了列宽改变的事件。而为了正确的展示鼠标指针,PreviewMouseMove 和PreviewMouseLeftButtonDown 事件都会被处理
当Viewport控件大小改变(ScrollChangedEventArgs.ViewportWidthChange)的时候,会触发ScrollViewer 控件的ScrollChanged 事件
通过使用DependencyPropertyDescriptor 可以追踪 GridViewColumn的宽度改变。并发出通知。
为了可以集成进已有的系统,列数据被放置在附加属性里。使用DependencyProperty.ReadLocalValue()方法会检测当前的属性是否在同一个对象里。
类ConverterGridViewColumn 同时使用一个简单的绑定。展示数据转换(IValueConverter接口)
类ImageGridViewColumn 在数据模板中使用FrameworkElementFactory 来动态嵌入图片,缺省情况下,在ListView/GridView控件中的图片会自动拉伸(Image.Stretch属性),因为数据模板中的图片是动态创建的。模板元素的值需要使用绑定来制定
// ---------------------------------------------------------------------- protectedImageGridViewColumn(Stretch imageStretch) { FrameworkElementFactory imageElement=newFrameworkElementFactory(typeof(Image)); // image stretching Binding imageStretchBinding=newBinding(); imageStretchBinding.Source=imageStretch; imageElement.SetBinding(Image.StretchProperty,imageStretchBinding); DataTemplate template=newDataTemplate(); template.VisualTree=imageElement; CellTemplate=template; }// ImageGridViewColumn
许可
本文及所有代码和文件在CPOL下授权
Demo下载
原文地址:ListView-Layout-Manager
著作权声明:本文由http://leaver.me 翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!