C# WPF TreeView复选框绑定-如何使用复选框填充ViewModel
对于如何设置带有绑定的C# WPF TreeView复选框绑定-如何使用复选框填充ViewModel,c#,wpf,xaml,checkbox,data-binding,C#,Wpf,Xaml,Checkbox,Data Binding,对于如何设置带有绑定的复选框,以确保使用所有选中字段填充ViewModel,我有点困惑。我在底部提供了一些代码和说明 我的Xaml文件称之为TreeView.Xaml: <TreeView x:Name="availableColumnsTreeView" ItemsSource="{Binding Path=TreeFieldData, Mode=OneWay, Converter={StaticResource SortingConverter}
复选框
,以确保使用所有选中字段填充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>
ViewModel(试图仅包括相关内容)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
}
问题:
我想要的行为是,当用户选中一个复选框时,它应该设置
TreeField
的IsSelected
属性(它现在就这样做了),但是我想返回到视图模型,并确保将这个特定的TreeField
添加到SelectedFields
。我真的不明白属性changedevent.Invoke的作用以及谁将接收该事件?如何确保SelectedFields
在AddFields()时填充
被调用它有所有已检查的TreeField
数据实例?您可以迭代TreeFieldData
集合中的TreeFieldData
对象,并将事件处理程序连接到其属性更改的事件,然后从所选字段
集合,例如:
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);
}
}
PropertyChanged事件的订阅者是视图,因此,如果以编程方式更改IsSelected,则视图知道它需要更新
要将选定的树字段插入列表,您需要将此代码添加到setter中
此外,您还可以定义以下函数,如果您有多个属性,该函数将使通知更容易:
private void NotifyPropertyChange([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
CallerMemberName属性指示编译器自动插入调用该方法的属性的名称。这个after PropertyChanged是比较not null的缩写
IsSelected的setter可以更改为
set
{
_isSelected = value;
if (value) { viewModel.SelectedFields.Add(this); }
else { viewModel.SelectedFields.Remove(this); }
NotifyPropertyChange();
}
当然,您需要在ViewModel实例中提供TreeFieldData,例如在构造函数中
我不知道SelectedFields是否在您的视图中有界/显示。如果是,并且希望显示对列表所做的更改,则应将列表更改为ObservableCollection。我猜MultipleColumnsSelectorVM类有一个“TreeFieldData”属性,该属性返回您在TreeView中看到的TreeFieldData对象列表?@mm8抱歉,是,我现在已经包括了它。@mm8供参考:TreeFieldData属性由一个初始化方法填充,我没有包括这个方法。谢谢,它可以工作,但只适用于“最外面”的节点。每个TreeFieldData节点都有一个子节点列表,因此我必须递归地遍历它,以确保所有字段都附加了PropertyChangedEvent。这有意义吗?我现在正在处理这个问题,在Initialize方法中执行递归。是的,您需要迭代并连接SelectedFields集合中要跟踪的所有项的事件处理程序。是的。这样做会影响性能吗?假设我们有几百块地?它只是真正附加了处理程序,但我不知道附加一个事件处理程序有多贵,而不是那么贵。
private void NotifyPropertyChange([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
set
{
_isSelected = value;
if (value) { viewModel.SelectedFields.Add(this); }
else { viewModel.SelectedFields.Remove(this); }
NotifyPropertyChange();
}