我在使用c#在MVVM WPF三层主 - 详细信息关系中实现级联复选框状态时有一个关于递归的问题。
假设关系是< DIVISION> - < TEAM> - < PLAYER>。如果我检查< DIVISION>,则所有< TEAM>对象和所有< PLAYER> < DIVISION>中的对象应该检查。如果我检查< TEAM>对象,所有< PLAYER> < TEAM>的对象应该检查< DIVISION>复选框状态应该是部分检查或检查,具体取决于< TEAM>的状态。兄弟姐妹。
为此,我在父级持有的子对象的ObservableCollection中的每个项目上分配一个PropertyChanged事件。然后,每个对象将响应相关子集合中对象的更改。每个复选框都绑定到每个模型上的IsChecked属性。 IsChecked属性由私有_isChecked变量支持。 ViewModel保存对顶级< DIVISION>的可观察集合的引用。对象。
情景:
有两个< DIVISION>具有三个< TEAM>的对象对象。每个团队有三个< PLAYER>对象。没有检查任何对象。
用户更改< TEAM>使用关联的复选框将IsChecked状态从False状态转换为True。
< TEAM>调用setter逻辑。
< TEAM>等级IsChecked setter循环通过< PLAYER>列表设置< PLAYER>等级IsChecked值为提供给setter的值。
第一个< PLAYER> IsChecked值切换为true。 < PLAYER> IsChecked状态已更改并正在广播。
< PLAYER>状态变化由< TEAM>检测到。级别改变听众。 < TEAM> IsChecked状态现在已经过部分检查。 < TEAM> IsChecked状态已更改并正在广播。
< TEAM>通过< DIVISION>检测状态变化。级别改变听众。 < DIVISION>州是部分检查。 < DIVISION> IsChecked状态已更改并正在广播。
第二个< PLAYER> IsChecked值切换为true。 < PLAYER> IsChecked状态已更改并正在广播。
< PLAYER>状态变化由< TEAM>检测到。级别改变听众。 < TEAM> IsChecked状态是部分检查。 < TEAM> IsChecked状态没有改变,也没有广播。
第三个也是最后一个< PLAYER> IsChecked值切换为true。 < PLAYER>国家改变是广播。
< TEAM>检测到状态变化。级别改变听众。 < TEAM>检查IsChecked状态。 < TEAM> IsChecked状态已更改并正在广播。
< TEAM>通过< DIVISION>检测状态变化。级别改变听众。 < DIVISION>州是部分检查。 IsChecked状态没有改变,也没有广播。
< TEAM> setter逻辑完成。 < TEAM>对象广播状态变化。
团队设定者逻辑的完成由< DIVISION>检测到。级别改变听众。 < DIVISION>州是部分检查。 < DIVISION> IsChecked状态没有改变,也没有广播。
这是通常的做法吗?这似乎效率很低,感觉有点笨重。有没有更好的方法来实现这一目标?
示例类如下:
public class DivisionObject : ObservableObject
{
bool? _isSelected = false;
public bool? IsSelected
{
get
{
return _isSelected;
}
set
{
if (value != _isSelected)
{
foreach (TeamObject p in TeamCollection)
{
p.IsSelected = value;
}
_isSelected = value;
RaisePropertyChanged("IsSelected");
}
}
}
public string Name { get; set; }
public int Tier { get; set; }
public decimal PrizeMoney { get; set; }
public ObservableCollection<TeamObject> TeamCollection{ get; set; }
public DivisionObject()
{
TeamCollection = new ObservableCollection<TeamObject>();
TeamCollection.CollectionChanged += TeamCollectionChanged;
}
void TeamCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
foreach (TeamObject t in e.NewItems)
{
t.PropertyChanged += t_PropertyChanged;
}
break;
case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
foreach (TeamObject t in e.NewItems)
{
t.PropertyChanged -= t_PropertyChanged;
}
break;
}
}
void t_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
bool? isSelected = _isSelected;
if (e.PropertyName == "IsSelected")
{
int selectedCount = TeamCollection.ToList().Count(p => p.IsSelected == true);
int unselectedCount = TeamCollection.ToList().Count(p => p.IsSelected == false && p.IsSelected != null);
if (selectedCount == TeamCollection.Count())
{
isSelected = true;
}
else
{
if (unselectedCount == TeamCollection.Count())
{
isSelected = false;
}
else
{
isSelected = null;
}
}
if (isSelected != _isSelected)
{
_isSelected = isSelected;
RaisePropertyChanged("IsSelected");
}
}
}
}
public class TeamObject : ObservableObject
{
bool? _isSelected = false;
public bool? IsSelected
{
get { return _isSelected; }
set
{
if (value != _isSelected)
{
foreach (PlayerObject a in PlayerCollection)
{
a.IsSelected = value;
}
_isSelected = value;
RaisePropertyChanged("IsSelected");
}
}
}
public string Name { get; set; }
public string Ground { get; set; }
public decimal AverageAttendance { get; set; }
public int YearFormed { get; set; }
public ObservableCollection<PlayerObject> PlayerCollection { get; set; }
public TeamObject()
{
PlayerCollection = new ObservableCollection<PlayerObject>();
PlayerCollection.CollectionChanged += PlayerCollection_CollectionChanged;
}
void PlayerCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
foreach (PlayerObject p in e.NewItems)
{
p.PropertyChanged += p_PropertyChanged;
}
break;
case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
foreach (PlayerObject p in e.NewItems)
{
p.PropertyChanged -= p_PropertyChanged;
}
break;
}
}
void p_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
bool? isSelected = _isSelected;
if (e.PropertyName == "IsSelected")
{
int selectedCount = PlayerCollection.ToList().Count(p => p.IsSelected == true);
int unselectedCount = PlayerCollection.ToList().Count(p => p.IsSelected == false && p.IsSelected != null);
if (selectedCount == PlayerCollection.Count())
{
isSelected = true;
}
else
{
if (unselectedCount == PlayerCollection.Count())
{
isSelected = false;
}
else
{
isSelected = null;
}
}
if (isSelected != _isSelected)
{
_isSelected = isSelected;
RaisePropertyChanged("IsSelected");
}
}
}
}
public class PlayerObject : ObservableObject
{
bool? _isSelected = false;
public bool? IsSelected
{
get { return _isSelected; }
set
{
if (value != _isSelected)
{
_isSelected = value;
RaisePropertyChanged("IsSelected");
}
}
}
public string FirstName { get; set; }
public string LastName { get; set; }
public string Position { get; set; }
public PlayerObject()
{
_isSelected = false;
}
}