2015-07-02 13 views
6

Tôi có một danh sách xem các mục ràng buộc với một tài sản trong viewmodel.Ràng buộc SelectedItems của ListView để ViewModel

<ListView Height="238" 
      HorizontalAlignment="Left" 
      Name="listView" 
      VerticalAlignment="Top" 
      Width="503" 
      ItemsSource="{Binding BusinessCollection}" 
      SelectionMode="Multiple" 
      > 
    <ListView.View> 
     <GridView> 
      <GridView.Columns> 
       <GridViewColumn> 
        <GridViewColumn.CellTemplate> 
         <DataTemplate> 
          <CheckBox IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListViewItem}}, Path=IsSelected}" /> 
         </DataTemplate> 
        </GridViewColumn.CellTemplate> 
       </GridViewColumn> 
       <GridViewColumn DisplayMemberBinding="{Binding ID}" Header="ID" /> 
       <GridViewColumn DisplayMemberBinding="{Binding Name}" Header="Name" /> 
      </GridView.Columns> 
     </GridView> 
    </ListView.View> 
</ListView> 

và trong chế độ xem.

ICollectionView _businessCollection 
public ICollectionView BusinessCollection 
{ 
get {return _businessCollection;} 
set{ 
_businessCollection=value; 
RaisePropertyOnChange("BusinessCollection"); 
} 
} 

Làm cách nào để chọn mục doanh nghiệp được chọn trong chế độ xem?

Trả lời

10

1. Một cách để nguồn ràng buộc:

Bạn phải sử dụng SelectionChanged sự kiện. Cách dễ nhất là viết eventhandler trong codebehind thành "bind selecteditems" thành viewmodel.

//ViewModel 
public ICollectionView BusinessCollection {get; set;} 
public List<YourBusinessItem> SelectedObject {get; set;} 

//Codebehind 
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    var viewmodel = (ViewModel) DataContext; 
    viewmodel.SelectedItems = listview.SelectedItems 
     .Cast<YourBusinessItem>() 
     .ToList(); 
} 

Điều này vẫn phù hợp với thiết kế MVVM vì chế độ xem và độ tương phản viewmodel được giữ riêng biệt. Bạn không có bất kỳ logic trong codebehind và viewmodel là sạch sẽ và testable.

2. Hai cách ràng buộc:

nếu bạn cũng cần phải cập nhật xem, khi có thay đổi viewmodel, bạn phải gắn với sự kiện PropertyChanged ViewModel và sự kiện CollectionChanged các mục đã chọn. Dĩ nhiên bạn có thể làm điều đó trong codebehind, nhưng trong trường hợp này tôi sẽ tạo ra một cái gì đó tái sử dụng hơn:

//ViewModel 
public ObservableCollection<YourBusinessItem> SelectedObject {get; set;} 

//in codebehind: 
var binder = new SelectedItemsBinder(listview, viewmodel.SelectedItems); 
binder.Bind(); 

hoặc có thể tạo tài sản tùy chỉnh kèm theo, vì vậy bạn có thể sử dụng cú pháp ràng buộc trong XAML:

<ListView local:ListViewExtensions.SelectedValues="{Binding SelectedItem}" .../> 
public class SelectedItemsBinder 
{ 
    private ListView _listBox; 
    private IList _collection; 


    public SelectedItemsBinder(ListView listBox, IList collection) 
    { 
     _listBox = listBox; 
     _collection = collection; 

     _listBox.SelectedItems.Clear(); 

     foreach (var item in _collection) 
     { 
      _listBox.SelectedItems.Add(item); 
     } 
    } 

    public void Bind() 
    { 
     _listBox.SelectionChanged += ListBox_SelectionChanged; 

     if (_collection is INotifyCollectionChanged) 
     { 
      var observable = (INotifyCollectionChanged) _collection; 
      observable.CollectionChanged += Collection_CollectionChanged; 
     } 
    } 

    public void UnBind() 
    { 
     if (_listBox != null) 
      _listBox.SelectionChanged -= ListBox_SelectionChanged; 

     if (_collection != null && _collection is INotifyCollectionChanged) 
     { 
      var observable = (INotifyCollectionChanged) _collection; 
      observable.CollectionChanged -= Collection_CollectionChanged; 
     } 
    } 

    private void Collection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     foreach (var item in e.NewItems ?? new object[0]) 
     { 
      if (!_listBox.SelectedItems.Contains(item)) 
       _listBox.SelectedItems.Add(item); 
     } 
     foreach (var item in e.OldItems ?? new object[0]) 
     { 
      _listBox.SelectedItems.Remove(item); 
     } 
    } 

    private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     foreach (var item in e.AddedItems ?? new object[0]) 
     { 
      if (!_collection.Contains(item)) 
       _collection.Add(item); 
     } 

     foreach (var item in e.RemovedItems ?? new object[0]) 
     { 
      _collection.Remove(item); 
     } 
    } 
} 

tài sản gắn liền thực hiện

public class ListBoxExtensions 
{ 

    private static SelectedItemsBinder GetSelectedValueBinder(DependencyObject obj) 
    { 
     return (SelectedItemsBinder)obj.GetValue(SelectedValueBinderProperty); 
    } 

    private static void SetSelectedValueBinder(DependencyObject obj, SelectedItemsBinder items) 
    { 
     obj.SetValue(SelectedValueBinderProperty, items); 
    } 

    private static readonly DependencyProperty SelectedValueBinderProperty = DependencyProperty.RegisterAttached("SelectedValueBinder", typeof(SelectedItemsBinder), typeof(ListBoxExtensions)); 


    public static readonly DependencyProperty SelectedValuesProperty = DependencyProperty.RegisterAttached("SelectedValues", typeof(IList), typeof(ListBoxExtensions), 
     new FrameworkPropertyMetadata(null, OnSelectedValuesChanged)); 


    private static void OnSelectedValuesChanged(DependencyObject o, DependencyPropertyChangedEventArgs value) 
    { 
     var oldBinder = GetSelectedValueBinder(o); 
     if (oldBinder != null) 
      oldBinder.UnBind(); 

     SetSelectedValueBinder(o, new SelectedItemsBinder((ListBox)o, (IList)value.NewValue)); 
     GetSelectedValueBinder(o).Bind(); 
    } 

    public static void SetSelectedValues(Selector elementName, IEnumerable value) 
    { 
     elementName.SetValue(SelectedValuesProperty, value); 
    } 

    public static IEnumerable GetSelectedValues(Selector elementName) 
    { 
     return (IEnumerable)elementName.GetValue(SelectedValuesProperty); 
    } 
} 
+0

Cảm ơn rất nhiều, nó đã giúp tôi rất nhiều :) –

+0

Cảm ơn bạn đã viết mã. Bạn cũng nên xử lý đặt lại bộ sưu tập trong phương thức Collection_CollectionChanged. –

-2

Kể từ khi itemSource là BusinessCollection, bạn sẽ có thể:

var selectedItems = BusinessCollection.Where(x => x.IsSelected); 

Wrap nó như một tài sản trên máy ảo của bạn. Hy vọng điều đó sẽ hữu ích!

+0

Cảm ơn, nhưng Busine ssCollection không có Thuộc tính được chọn. –

+0

Xin lỗi đã không kiểm tra điều đó. Tại sao không sử dụng một bộ sưu tập khác? Với ObservableCollection, tôi biết nó hoạt động vì tôi đã thực hiện nó như thế trước đây. – WpfFanatic

+0

Cách sử dụng? –

Các vấn đề liên quan