2017-03-08 77 views
1

我對如何使用綁定設置CheckBox有點困惑,該綁定確保我的ViewModel中填充了所有選中的字段。我在底部提供了一些代碼和說明。WPF TreeView複選框綁定 - 如何使用複選框填充ViewModel

我的XAML文件讓我們把它TreeView.xaml

<TreeView x:Name="availableColumnsTreeView"   
      ItemsSource="{Binding Path=TreeFieldData, Mode=OneWay, Converter={StaticResource SortingConverter}, ConverterParameter='DisplayName.Text'}"> 

    <TreeView.ItemTemplate> 
     <HierarchicalDataTemplate x:Uid="HierarchicalDataTemplate_1" ItemsSource="{Binding Path=Children, Mode=OneWay, Converter={StaticResource SortingConverter}, ConverterParameter='DisplayName.Text'}"> 
      <CheckBox VerticalAlignment="Center" IsChecked="{Binding IsSelected, Mode=TwoWay}"> 
       <TextBlock x:Uid="TextBlock_1" Text="{Binding DisplayName.Text, Mode=OneWay}" /> 
      </CheckBox>    
     </HierarchicalDataTemplate> 
    </TreeView.ItemTemplate> 
</TreeView> 

的 「代碼隱藏」 TreeView.xaml.cs

public partial class MultipleColumnsSelectorView : UserControl 
{ 
    public MultipleColumnsSelectorView() 
    { 
     InitializeComponent(); 
    } 

    private MultipleColumnsSelectorVM Model 
    { 
     get { return DataContext as MultipleColumnsSelectorVM; } 
    } 
} 

視圖模型(試圖只包括相關的東西)MultipleColumnsSelectorVM

public partial class MultipleColumnsSelectorVM : ViewModel, IMultipleColumnsSelectorVM 
{ 
    public ReadOnlyCollection<TreeFieldData> TreeFieldData 
    { 
     get { return GetValue(Properties.TreeFieldData); } 
     set { SetValue(Properties.TreeFieldData, value); } 
    } 

    public List<TreeFieldData> SelectedFields 
    { 
     get { return GetValue(Properties.SelectedFields); } 
     set { SetValue(Properties.SelectedFields, value); } 
    } 

    private void AddFields() 
    { 
     //Logic which loops over SelectedFields and when done calls a delegate which passes 
     //the result to another class. This works, implementation hidden 
    } 

該模型TreeFieldData

public class TreeFieldData : INotifyPropertyChanged 
{  
    public event PropertyChangedEventHandler PropertyChanged; 
    public IEnumerable<TreeFieldData> Children { get; private set; } 
    private bool _isSelected; 
    public bool IsSelected 
    { 
     get { return _isSelected; } 
     set 
     { 
      _isSelected = value; 
      if (PropertyChanged != null) 
       PropertyChanged.Invoke(this, new PropertyChangedEventArgs("IsSelected")); 
     } 
    } 
} 

問題:

,我想是當用戶檢查一個複選框,它應該設置的TreeFieldIsSelected財產行爲(它是現在),但後來我想返回ViewModel並確保將此特定TreeField添加到SelectedFields。我真的不明白PropertyChangedEvent.Invoke會做什麼以及誰會收到該事件?我怎樣才能確保SelectedFields得到填充,所以當AddFields()被調用時,它有所有TreeField數據實例被檢查?

+0

我猜MultipleColumnsSelectorVM類有一個「TreeFieldData」屬性,它返回TreeView中看到的TreeFieldData對象的列表? – mm8

+0

@ mm8對不起,現在我已經包括了。 – DSF

+0

@ mm8 FYI:TreeFieldData屬性由我沒有包含的Initialize方法填充。 – DSF

回答

2

你可以通過TreeFieldData對象TreeFieldData集合中迭代,掛鉤事件處理程序,以他們的PropertyChanged事件,然後添加/從SelectedFields集合中刪除選定/未選定項目,如:

public MultipleColumnsSelectorVM() 
{ 
    Initialize(); 

    //do this after you have populated the TreeFieldData collection 
    foreach (TreeFieldData data in TreeFieldData) 
    { 
     data.PropertyChanged += OnPropertyChanged; 
    } 
} 

private void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
{ 
    if (e.PropertyName == "IsSelected") 
    { 
     TreeFieldData data = sender as TreeFieldData; 
     if (data.IsSelected && !SelectedFields.Contains(data)) 
      SelectedFields.Add(data); 
     else if (!data.IsSelected && SelectedFields.Contains(data)) 
      SelectedFields.Remove(data); 
    } 
} 
+0

它的工作表示感謝,但僅限於「最外層」節點。每個TreeFieldData節點都有一個Children列表,所以我必須遞歸循環以確保所有字段都附有PropertyChangedEvent。如果這有道理?我現在正在處理這個問題,在Initialize方法中進行遞歸。 – DSF

+0

是的,您需要遍歷並連接所有您想要在SelectedFields集合中跟蹤的項目的事件處理程序。 – mm8

+0

是的。這樣做對性能不利?假設我們有幾百個領域?這只是真的附加處理程序,但我不知道這是多麼昂貴 – DSF

0

的PropertyChanged事件的訂閱者是視圖,因此如果以編程方式更改IsSelected,則視圖知道它需要更新。

要將選定的TreeField插入到列表中,您需要將此代碼添加到您的setter中。

此外,你可以定義下面的函數,這使得該通知,如果你有很多屬性更容易:

private void NotifyPropertyChange([CallerMemberName] string propertyName = null) 
{ 
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
} 

的CallerMemberName屬性指示編譯器自動插入屬性調用該方法的名稱。這個?在PropertyChanged之後,你的比較是非空的。

IsSelected的制定者然後可以改爲

set 
{ 
    _isSelected = value; 
    if (value) { viewModel.SelectedFields.Add(this); } 
    else { viewModel.SelectedFields.Remove(this); } 
    NotifyPropertyChange(); 
} 

當然,你將需要提供TreeFieldData與視圖模型的實例,例如在構造函數中。

我不知道在您的視圖中SelectedFields是否有界/顯示。如果是,並且希望顯示對列表所做的更改,則應將List更改爲ObservableCollection。