【问题标题】:Silverlight MVVM:Updating parent view model based on status of child View modelSilverlight MVVM:根据子视图模型的状态更新父视图模型
【发布时间】:2014-01-24 10:42:29
【问题描述】:

我是 Silverlight MVVM 的新手。 我有一个要求在父子层次结构中显示复选框。 加载页面时,如果选中子项,则还应选中父复选框。

我创建了一个如下的 ViewModel

   public class TestViewModel : INotifyPropertyChanged
    {
  private string name;
        private string percent;
        private bool isChecked;
        internal event EventHandler CheckboxStateChanged = delegate { };

        private List<TestViewModel> testViewModel;

        public List<TestViewModel> TestViewModel1
        {
            get { return testViewModel; }
            set
            {
                testViewModel = value;
                NotifyPropertyChanged("TestViewModel1");

            }
        }

        public TestViewModel()
        {
            //IsChecked = true;
            //Name = "Hello";
            //Percent = "10";
        }

        public bool IsChecked
        {
            get { return isChecked; }
            set
            {
                isChecked = value;
                NotifyPropertyChanged("IsChecked");
                               CheckboxStateChanged(this, new EventArgs());

            }
        }


     public event PropertyChangedEventHandler PropertyChanged;
            protected void NotifyPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }

}

在我的 main.xaml.cs 中,我创建了递归方法,该方法将创建复选框的父子层次结构。 单击子复选框时,父复选框将被选中,因为我已在我的 VM 中添加了事件处理程序(CheckboxStateChanged)。但是在页面加载时,如果选中子复选框,则父复选框也会被选中,我无法做到这一点..请帮助.

请注意,在我获得孩子身份之前,我无法让父母检查,一旦我获得孩子身份,我不知道如何回到父母身边。

父虚拟机包含与子虚拟机相同的列表(即公共列表 TestViewModel1)

【问题讨论】:

    标签: wpf silverlight mvvm


    【解决方案1】:

    如果我理解您的问题是正确的,您正在寻找一种方法将复选框值从子复选框合并到其父复选框。

    我为树视图做了类似的解决方案。此代码有效,但如果集合发生更改,则需要分离一些事件。

    以下是用于运行此解决方案的 ViewModel 部分的一组类。

    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    
    public class StructureViewModel : ViewModelBase
    {        
        private bool? _isChecked = false;
    
        public bool? IsChecked
        {
            get { return _isChecked; }
            set
            {
                if (_isChecked != value)
                {
                    _isChecked = value;
                    RaisePropertyChanged("IsChecked");                    
                }
            }
        }
    
        public string Name { get; set; }        
    }
    
    public class ChildViewModel : StructureViewModel
    {
    
    }
    
    public class ParentViewModel : StructureViewModel
    {
        public ParentViewModel()
        {
            Children = new List<ChildViewModel>();                    
        }
    
        public ICollection<ChildViewModel> Children { get; set; }
    }
    
    public class MainViewModel : ViewModelBase
    {
        public MainViewModel()
        {
            Parents = new List<ParentViewModel>();
    
            var parent = new ParentViewModel { Name = "Parent" };
    
            parent.Children.Add(new ChildViewModel
            {
                Name = "Child1"                
            });
    
            parent.Children.Add(new ChildViewModel
            {
                Name = "Child2"
            });
    
            Parents.Add(parent);
        }
    
        public ICollection<ParentViewModel> Parents { get; set; }
    }
    

    为了显示这一点,我使用以下标记:

         <TreeView ItemsSource="{Binding Parents}">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Children}" >
                    <CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" Content="{Binding Name}">
                        <i:Interaction.Behaviors>
                            <local:CheckParentBehavior Children="{Binding Children}" />
                        </i:Interaction.Behaviors>
                    </CheckBox>
    
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    

    修复复选框的神奇之处在于 CheckParentBehavior:

    public class CheckParentBehavior : Behavior<CheckBox>
    {
        public IEnumerable<StructureViewModel> Children
        {
            get { return (IEnumerable<StructureViewModel>)GetValue(ChildrenProperty); }
            set { SetValue(ChildrenProperty, value); }
        }
    
        public static readonly DependencyProperty ChildrenProperty =
            DependencyProperty.Register("Children", typeof(IEnumerable<StructureViewModel>), typeof(CheckParentBehavior), new PropertyMetadata(OnChildrenChanged));
    
        protected override void OnAttached()
        {
            if (Children != null)
                AssociatedObject.IsChecked = GetCheck(Children);
        }
    
        private static void OnChildrenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null)
            {
                foreach (var child in e.NewValue as IEnumerable<StructureViewModel>)
                    child.PropertyChanged += (_, args) => OnChildPropertyChanged(d as CheckParentBehavior, args);
            }
        }
    
        private static void OnChildPropertyChanged(CheckParentBehavior behavior, PropertyChangedEventArgs args)
        {
            if (args.PropertyName == "IsChecked")
                behavior.AssociatedObject.IsChecked = GetCheck(behavior.Children);
        }
    
        public static bool? GetCheck(IEnumerable<StructureViewModel> children)
        {
            if (children.All(c => c.IsChecked.GetValueOrDefault()))
                return true;
            else if (children.Any(c => c.IsChecked.GetValueOrDefault()))
                return null;
            else
                return false;
        }
    
    
    }
    

    它会监听每个 childs propertychanged 事件,如果它改变 ischecked 属性,它会相应地改变父母。

    希望您可以使用其中的一些代码来解决您的问题。

    【讨论】:

    • 您也可以在 ViewModel 逻辑中执行此操作,但如果“IsChecked”属性名称可配置,则可以重用上述 Beahvior。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-26
    • 1970-01-01
    • 2017-05-04
    • 2016-11-25
    • 1970-01-01
    • 2018-06-30
    • 2012-11-14
    相关资源
    最近更新 更多