Silverlight MVVM:根据子视图模型的状态更新父视图模型

时间:2014-01-24 10:42:30

标签: wpf silverlight mvvm

我是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中添加了eventhandler(CheckboxStateChanged),但是在页面加载时如果检查了child,那么父也会被检查,我无法执行此操作。请帮助

注意我不能让父母检查,直到我得到孩子的状态,一旦我得到孩子的状态,我不知道如何回到父母。

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

1 个答案:

答案 0 :(得分: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属性更改事件,如果它改变了缺陷属性,它会相应地改变父母。

希望你可以使用这些代码来解决你的问题。