刚好今天一位朋友问到这个问题,所以就写篇随笔,方便以后自己需要时候可以参考
实现可编辑的listview有两种方法:
1. 定制ListViewItem,然后在内部类中处理绑定,这种做法的好处就是可以方便以后对ListViewItem功能的扩展
2.定制CellTemplate,然后用两个控件来显示数据(一个用于显示,一个用于编辑)
第一种在方法用的比较少,大多数使用ListView还是用来显示数据的,所以没有必要对ListViewItem做太大的扩展,所以第二种方法就足够了,所以今天介绍的也是第二种方法
首先定义一个TextBlock和TextBox的样式,前者用于显示,后者用于选中ListViewItem时候进行编辑
<Style TargetType="{x:Type TextBlock}" x:Key="ListViewItemBlockStyle"> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="Visibility" Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Converter={StaticResource BooleanToVisibily}, ConverterParameter=False}" /> </Style> <Style TargetType="{x:Type FrameworkElement}" x:Key="ListViewItemEditStyle"> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="Visibility" Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Converter={StaticResource BooleanToVisibily}, ConverterParameter=True}" /> </Style>
其中
class="brush:csharp;gutter:false;">BooleanToVisibily 是自定义的用于Boolean和System.Windows.Visibility之间的转换
这里两个控件使用的是同一个转换器,所以在转换器处理的时候需要根据参数targetType来分
别处理下
例如: ListViewItem.IsSelected = true , TextBlock.Visibility = Hide ,TextBox.Visibility = Visibily
反过来是一样的,TextBlock和TextBox总是对立面的
这里还需要注意一个 RelativeSource 用于相对资源的查找,一般多余对象属性跟另一个对象属性的绑定,尤其在跨对象的style中使用的比较多
接下来就是我们MainWindow部分
<ListView x:Name="_lsPerson" ItemsSource="{Binding Persons}">
<ListView.View>
<GridView> <GridViewColumn Header="名称" Width="100" DisplayMemberBinding="{Binding Name}"/> <GridViewColumn Header="价格" Width="80"> <GridViewColumn.CellTemplate> <DataTemplate> <Grid> <TextBlock Width="180" Text="{Binding Path=Price}" Style="{StaticResource ListViewItemBlockStyle}" /> <TextBox Width="180" Text="{Binding Path=Price, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource ListViewItemEditStyle}" /> </Grid> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Header="数量" Width="80" DisplayMemberBinding="{Binding Number" /> <GridViewColumn Header="总额" Width="80" DisplayMemberBinding="{Binding Total}"/> </GridView> </ListView.View> </ListView>
其中关键就是“ 价格”那一栏了,我们自定义了CellTemplate,用于让该栏支持编辑
ListView.ItemSource 绑定了一个Persons ,这是个ObservableCollection集合,该集合包含数据模型person定义了(Name,Price,Number,Total属性),该类
实现了INotifyPropertyChanged
INotifyObject 和模型类
logs_code_hide('14e77616-332e-4ff5-a068-5350f82ee0d9',event)" src="/Upload/Images/2013082621/2B1B950FA3DF188F.gif" alt="" />/// <summary> /// INotifyObject :更新属性接口 /// </summary> /// Created 2013.08.26 public interface INotityObject : INotifyPropertyChanged { void UpdateProperty(object sender, string PropertyName); } /// <summary> /// NotifyObject:继承INotifyObject /// </summary> /// Created 2013.08.26 public class NotifyObject : INotityObject { public void UpdateProperty(object sender, string PropertyName) { PropertyChangedEventHandler handler = this.PropertyChanged ; if (null != handler) { handler(sender, new PropertyChangedEventArgs(PropertyName)); } } public event PropertyChangedEventHandler PropertyChanged; }View Code
Person / oBS PERSON
/// <summary> /// 模型类 /// </summary> /// Created 2013.8.26 public class PersonDTO : NotifyObject { private string _name; private decimal _price; private int _number; private decimal _total; protected void Update( string propertyname){base.UpdateProperty(this, propertyname );} public string Name { get { return _name; } set { _name = value; Update("Name"); } } public decimal Price { get { return _price; } set { _price = value; this.Total = _price * Number; Update("Price"); } } public int Number { get { return _number; } set { _number = value; this.Total = Price * _number; Update("Number"); } } public decimal Total { get { return _total; } set { _total = value; Update("Total"); } } } public class PersonDTOViewModel { private System.Collections.ObjectModel.ObservableCollection<PersonDTO> _obsPersonDTO = null; public PersonDTOViewModel() { if (_obsPersonDTO == null) { _obsPersonDTO = new System.Collections.ObjectModel.ObservableCollection<PersonDTO>(); } } public System.Collections.ObjectModel.ObservableCollection<PersonDTO> Persons { get { return _obsPersonDTO; } } /// <summary> /// Add: 添加一个对象到集合 /// </summary> /// <param name="dto"></param> /// created 2013.08.26 public void Add(PersonDTO dto) { this._obsPersonDTO.Add(dto); } /// <summary> /// Remove: 根据名称移除从集合中移除指定对象 /// </summary> /// <param name="personName"></param> /// created 2013.08.26 public void Remove(string personName) { var obj = (from x in _obsPersonDTO where x.Name.Equals(personName, StringComparison.CurrentCultureIgnoreCase) select x).FirstOrDefault(); if (obj != null) { _obsPersonDTO.Remove(obj); } } }View Code
整个Demo完成了,简单的通过样式+绑定方式来实现了ListView的Item支持可编辑功能
小结:
全文的实现可以看出是非常简单的,只要是应用了央视和绑定的结果,其中需要注意点应该就是相对绑定RelativeSource,以及在使用相对绑定情况下查找关联属性,一般在对象属性绑定到另一个对象属性或者属性绑定到自身对象属性中应用的比较多.