C# 将集合绑定到列表框中的SelectedItems而不违反MVVM
我有一个名为SelectedVNodes”的ObservableCollection,它包含来自ObservableCollectionVNodes的项目 SelectedVNodes应仅包含属性为C# 将集合绑定到列表框中的SelectedItems而不违反MVVM,c#,wpf,C#,Wpf,我有一个名为SelectedVNodes”的ObservableCollection,它包含来自ObservableCollectionVNodes的项目 SelectedVNodes应仅包含属性为IsSelected=True的节点,否则如果为“false”,则不应在列表中 ObservableCollection<VNode> SelectedVNodes {...} ObservableCollection<VNode> VNodes {...} NOTIFYPR
IsSelected=True
的节点,否则如果为“false”,则不应在列表中
ObservableCollection<VNode> SelectedVNodes {...}
ObservableCollection<VNode> VNodes {...}
NOTIFYPROPERTYCHANGED派生自INotifyPropertyChanged。不使用INotifyPropertyChanged的一种方法是在
设置程序中添加if
构造:
private bool isSelected;
public bool IsSelected
{
get { return isSelected; }
set
{
Set(ref isSelected, value);
if(isSelected)
{
if(!SelectedVNodes.Any(v => v.Name == this.Name))
SelectedVNodes.Add(this);
}
else{
if(SelectedVNodes.Any(v => v.Name == this.Name))
SelectedVNodes.Remove(this);
}
Console.WriteLine("selected/deselected");
}
}
如果我没记错的话,在上一集结束时,我们使用了一些异想天开的WPF控件,它不允许您正确绑定SelectedItems
,所以就这样结束了。但如果你能做到,这是迄今为止最好的方法:
<NonWhimsicalListBox
ItemsSource="{Binding VNodes}"
SelectedItems="{Binding SelectedVNodes}"
/>
假设AttachedProperties
在XAML中的“local:
”命名空间中定义
<ListBox
ItemsSource="{Binding VNodes}"
SelectionMode="Extended"
local:AttachedProperties.SelectedItems="{Binding SelectedVNodes}"
/>
执行该事件,而不是添加/删除,只需重新创建SelectedVNodes
:
var newvnode = new VNode();
newvnode.PropertyChanged += (s,e) => {
if (e.PropertyName == "IsSelected") {
// Make sure OnPropertyChanged("SelectedVNodes") is happening!
SelectedVNodes = new ObservableCollection<VNode>(
VNodes.Where(vn => vn.IsSelected)
);
}
};
给VNode
一个父属性。当父视图模型创建一个VNode
时,它会为每个VNode
提供一个父引用,指向selectedvnode
的所有者(可能是它自己)。在VNode.IsSelected.set
中,VNode对父级.SelectedVNodes
执行添加或删除操作
// In class VNode
private bool _isSelected = false;
public bool IsSelected {
get { return _isSelected; }
set {
_isSelected = value;
OnPropertyChanged("IsSelected");
// Elided: much boilerplate checking for redundancy, null parent, etc.
if (IsSelected)
Parent.SelectedVNodes.Add(this);
else
Parent.SelectedVNodes.Remove(this);
}
}
以上这些都不是艺术品。版本1可能最不坏
如果您有大量项目,请不要使用IEnumerable
one。另一方面,它免除了您进行双向操作的责任,也就是说,如果某些消费者直接干扰了SelectedVNodes
,您应该真正处理其CollectionChanged
事件并更新相关VNodes
。当然,然后您必须确保不会意外地递归:不要向已经存在的集合中添加一个,如果vn.IsSelected
已经为true,则不要设置vn.IsSelected
。如果你的眼睛现在像我的眼睛一样呆滞,你开始感觉到墙壁在靠近,请允许我推荐选项3
也许SelectedVNodes
应该公开ReadOnlyObservableCollection
,让您摆脱困境。在这种情况下,1号是您的最佳选择,因为vnode
将无法访问VM的私有可变observateCollection
但是你自己选吧 您好,您应该在您的复选框声明中添加一个命令和一个commandParameter。在ur viewmodel中添加命令,命令参数应该是选中的元素(VNode类型),更新属性ISSELECT=false,并且应该正常更新。请注意,由于命令嵌套在listview@Guillaume你能告诉我怎么做吗?它是相同的实现,而不是按钮复选框,在removeCommand中,您将更新ur Vnodes.IsSelected=true,并且您应该更改AncestorType={x:Type DataGrid}}}}“DataGrid”“到Gridview或listView。很抱歉,我在午餐时间得到了快速回复:)您使用什么控件来显示/选择VNode
s?如果控件支持multi-select,那么它应该已经有了一个集合,比如SelectedItems
或类似的集合。在我的例子中,控件没有selected Items属性,因为我使用的是画布。是否有方法向画布添加扩展以收集所选项目?因此,画布是ItemsControl(或其他)使用的ItemsPanel?像这样:还是什么?这会让事情变得更简单吗?@JokerMartini好的,我写了一个附件属性,它将列表框的SelectedItems状态反映到集合中(任何实现viewmodel提供的IList
的东西。ItemsPanel是什么都没有区别。@JokerMartini好的,这样做了。它可以反映通过UI输入的选择中的更改。没有测试相反方向的更改。
<ListBox
ItemsSource="{Binding VNodes}"
SelectionMode="Extended"
local:AttachedProperties.SelectedItems="{Binding SelectedVNodes}"
/>
private ObservableCollection<Node> _selectedVNodes
= new ObservableCollection<Node>();
public ObservableCollection<Node> SelectedVNodes
{
get
{
return _selectedVNodes;
}
}
var newvnode = new VNode();
newvnode.PropertyChanged += (s,e) => {
if (e.PropertyName == "IsSelected") {
if ((bool)e.NewValue) {
// If not in SelectedVNodes, add it.
} else {
// If in SelectedVNodes, remove it.
}
}
};
// blah blah blah
var newvnode = new VNode();
newvnode.PropertyChanged += (s,e) => {
if (e.PropertyName == "IsSelected") {
// Make sure OnPropertyChanged("SelectedVNodes") is happening!
SelectedVNodes = new ObservableCollection<VNode>(
VNodes.Where(vn => vn.IsSelected)
);
}
};
var newvnode = new VNode();
newvnode.PropertyChanged += (s,e) => {
if (e.PropertyName == "IsSelected") {
OnPropertyChanged("SelectedVNodes");
}
};
// blah blah blah much else blah blah
public IEnumerable<VNode> SelectedVNodes {
get { return VNodes.Where(vn => vn.IsSelected); }
}
// In class VNode
private bool _isSelected = false;
public bool IsSelected {
get { return _isSelected; }
set {
_isSelected = value;
OnPropertyChanged("IsSelected");
// Elided: much boilerplate checking for redundancy, null parent, etc.
if (IsSelected)
Parent.SelectedVNodes.Add(this);
else
Parent.SelectedVNodes.Remove(this);
}
}