我是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)
答案 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属性更改事件,如果它改变了缺陷属性,它会相应地改变父母。
希望你可以使用这些代码来解决你的问题。