TreeView子节点 - 在wpf中输入验证

时间:2013-07-29 10:23:46

标签: wpf validation wpftoolkit wpf-4.0 hierarchicaldatatemplate

我有一个如下所示的树视图。

  • R1
    • P1
      • 儿童1
    • P2
      • 儿童1
    • XX
      • 儿童3

说我想显示错误信息 a)树节点或 b)其容器

基于我的验证规则的值。

例如,如果我应用此树的验证逻辑,

验证规则>>>所有以“p”开头的父母都有效

结果,我的“xx”节点有效。我需要突出显示该元素并通知用户。

我在WPF中使用MVVM。我该怎么做。请帮帮我。

1 个答案:

答案 0 :(得分:2)

我过去做过类似的事情,你可以做的就是:

  1. 创建一个ViewModel(例如NodeViewModel),代表您的每个树节点,以防您还没有
  2. 您可以在NodeViewModel中创建和实现一个接口,如IValidate,它会公开bool IsValid {get;set;}属性。 (确保在ViewModel属性中实现INotifyPropertyChanged
  3. 为您在节点的View(例如Button)中使用的控件类型创建样式,并创建样式触发器(在线大量示例),当IsValid为false时,将节点背景设置为红色将它应用于您的控制:

                    <HierarchicalDataTemplate DataType="{x:Type ViewModel:NodeViewModel}" ItemsSource="{Binding Children}">
                        <Button Style="{StaticResource MyNodeStyle}" 
                                Content="{Binding Path=.}"
                    </HierarchicalDataTemplate>
    
  4. 在您的业务逻辑层或容器ViewModel中创建一个方法,以递归方式验证树中的所有节点,并将IsValid属性设置为所有节点,或者在IsValid Get中定义业务规则(使其读取 - 只要)。当验证发生时,如果节点根据您的规则无效,则会自动变为红色。

  5. 希望这有帮助,如果您有疑问,请与我联系。

    编辑:添加了一些示例类来说明解决方案。我的业务规则是任何以'p'开头的节点都是有效的(绿色),无论它是否是父节点,但你明白了......

    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>
    

    这是你得到的:
    Output

    此解决方案的限制是在为每个节点设置NodeText属性时进行验证,因此您可能不知道该节点是否有子节点,因此我宁愿在TreeViewModel中创建一个方法来设置{ {1}}某个点上所有节点的标志。