我有一个像下面这样的树视图。
- R1
- P1
- 孩子 1
- P2
- 孩子 1
- XX
- 孩子 3
- P1
假设我想在 a) 树节点或 b) 它的容器中显示错误消息
基于我的验证规则的值。
例如,如果我为这棵树应用验证逻辑,
验证规则 >>> 所有值以“p”开头的父母都是有效的
结果,我的“xx”节点有效。我需要突出显示这个元素并通知用户。
我在 WPF 中使用 MVVM。我该怎么做。请帮助我。
我有一个像下面这样的树视图。
假设我想在 a) 树节点或 b) 它的容器中显示错误消息
基于我的验证规则的值。
例如,如果我为这棵树应用验证逻辑,
验证规则 >>> 所有值以“p”开头的父母都是有效的
结果,我的“xx”节点有效。我需要突出显示这个元素并通知用户。
我在 WPF 中使用 MVVM。我该怎么做。请帮助我。
I've done something similar in the past, here is what you can do:
bool IsValid {get;set;}
property. (Make sure you are implementing INotifyPropertyChanged
in your ViewModel property)Create a Style for the control type you are using at your View for your nodes(e.g. Button) and create a Style trigger (lots of examples online) that sets the node background to red when the IsValid is false and apply it to your control:
<HierarchicalDataTemplate DataType="{x:Type ViewModel:NodeViewModel}" ItemsSource="{Binding Children}">
<Button Style="{StaticResource MyNodeStyle}"
Content="{Binding Path=.}"
</HierarchicalDataTemplate>
At your business logic layer, or container ViewModel create a method that validates all your nodes in the trees recursively and sets the IsValid property to all of them or define your business rule at the IsValid Get (make it read-only). When that validation happens your nodes will turn red automatically if they are not valid based on your rules.
Hope this helps, let me know if you have questions.
EDIT: Added some sample classes to illustrate the solution. My business rule was that any node that starts with 'p' is Valid (green) no matter if it is a parent or not, but you get the idea..
public class TreeNodeViewModel : ViewModelBase<TreeNodeViewModel>
{
private string _NodeText;
private ObservableCollection<TreeNodeViewModel> _Children;
public TreeNodeViewModel()
{
Children = new ObservableCollection<TreeNodeViewModel>();
}
public string NodeText
{
get { return _NodeText; }
set
{
_NodeText = value;
NotifyPropertyChanged(m => m.NodeText);
NotifyPropertyChanged(m => m.IsValid);
}
}
public bool IsValid
{
get { return !string.IsNullOrEmpty(NodeText) && NodeText.ToLower().StartsWith("p"); }
}
public ObservableCollection<TreeNodeViewModel> Children
{
get { return _Children; }
set
{
_Children = value;
NotifyPropertyChanged(m => m.Children);
}
}
}
public class TreeViewModel : ViewModelBase<TreeViewModel>
{
private ObservableCollection<TreeNodeViewModel> _RootNodeContainer;
private TreeNodeViewModel _RootNode;
public TreeViewModel()
{
InitializeTree();
}
private void InitializeTree()
{
RootNodeContainer = new ObservableCollection<TreeNodeViewModel>();
RootNode = new TreeNodeViewModel() { NodeText = "R1" };
RootNodeContainer.Add(RootNode);
TreeNodeViewModel p1 = new TreeNodeViewModel() {NodeText = "P1"};
p1.Children.Add(new TreeNodeViewModel(){NodeText = "Child1"});
RootNode.Children.Add(p1);
TreeNodeViewModel p2 = new TreeNodeViewModel() {NodeText = "P2"};
p2.Children.Add(new TreeNodeViewModel() { NodeText = "Child1" });
RootNode.Children.Add(p2);
TreeNodeViewModel xx = new TreeNodeViewModel() {NodeText = "XX"};
xx.Children.Add(new TreeNodeViewModel() { NodeText = "Child3" });
RootNode.Children.Add(xx);
}
public TreeNodeViewModel RootNode
{
get { return _RootNode; }
set
{
_RootNode = value;
NotifyPropertyChanged(m => RootNode);
}
}
public ObservableCollection<TreeNodeViewModel> RootNodeContainer
{
get { return _RootNodeContainer; }
set
{
_RootNodeContainer = value;
NotifyPropertyChanged(m => RootNodeContainer);
}
}
}
<TreeView Name="GoldTree" ItemsSource="{Binding RootNodeContainer}"
Background="#FFF0EDD1">
<TreeView.Resources>
<ResourceDictionary>
<Style TargetType="Button" x:Key="MyNodeStyle">
<Style.Triggers>
<DataTrigger
Binding="{Binding Path=IsValid,UpdateSourceTrigger=PropertyChanged}"
Value="False">
<Setter Property="Border.Background" Value="Red" />
</DataTrigger>
<DataTrigger
Binding="{Binding Path=IsValid,UpdateSourceTrigger=PropertyChanged}"
Value="True">
<Setter Property="Border.Background" Value="GreenYellow" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="TreeViewItem">
<Setter Property="Margin" Value="0,0,0,0" />
<!-- Disable blue highlighting on selection-->
<Setter Property="Focusable" Value="false" />
</Style>
<HierarchicalDataTemplate DataType="{x:Type ViewModel:TreeNodeViewModel}"
ItemsSource="{Binding Children}">
<Button Style="{StaticResource MyNodeStyle}" Content="{Binding Path=NodeText}" />
</HierarchicalDataTemplate>
</ResourceDictionary>
</TreeView.Resources>
</TreeView>
Here is what you get:
The limitation with this solution is that validation takes place when the NodeText property is set for each node so you may not know at that point whether the node has children, so I'd rather create a method in TreeViewModel to set the IsValid
flag for all nodes at some point.