c# - 具有动态孩子的 MVVM 可能吗?
问题描述
我有一个简单的表单,它作为一组动态的父标签(可能是 1 -10 个标签)在计时器上更新,如果一切正常,这些标签保持绿色,如:
但是,如果其中一位父母的状态发生了变化,我会尝试显示有问题的孩子或孩子,并导致以下结果:
然后一旦状态恢复正常恢复到原始布局(如上)
所以目前我有这样的看法:
<Grid>
<ItemsControl ItemsSource = "{Binding Path = CIs}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Label Content = "{Binding Path = NodeName, Mode = OneWay}"
Background = "{Binding Path = NodeStatus, Mode = OneWay}"
Tag="{Binding Path = Nodeid, Mode = OneWay}"
Foreground="White"
FontFamily="Arial Black"
HorizontalContentAlignment="Center"
BorderBrush="Black"
BorderThickness="1,1,1,1"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
使用简单的添加填充视图的视图模型:
if (Node.level == 3)
{
CIs.Add(new CI { NodeName = Node.name, NodeStatus = Node.status, Nodeid = Node.id });
}
和基本模型:
public class CIModel {}
public class CI : INotifyPropertyChanged {
private string nodeName;
private string nodeStatus;
private string nodeid;
public string NodeName {
get {
return nodeName;
}
set {
if (nodeName != value) {
nodeName = value;
RaisePropertyChanged("NodeName");
}
}
}
public string Nodeid
{
get
{
return nodeid;
}
set
{
if (nodeid != value)
{
nodeid = value;
RaisePropertyChanged("Nodeid");
}
}
}
public string NodeStatus
{
get
{
return nodeStatus;
}
set
{
if (nodeStatus != value)
{
nodeStatus = value;
RaisePropertyChanged("NodeStatus");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property) {
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
以某种方式在父状态更改上创建子视图是一种可能的方式吗?或者我可以创建所有的父母和孩子并在状态发生变化时切换那里的可见性?
谢谢
解决方案
你的意思是这样的吗?
// Put this in MainWindow()
public MainWindow()
{
InitializeComponent();
new Demo(this);
}
// Demo code
public class Demo
{
public Demo(FrameworkElement view)
{
View = view;
View.DataContext = this;
StartDemo();
}
private FrameworkElement View { get; }
public ObservableCollection<Parent> Parents { get; } = new ObservableCollection<Parent>();
public async void StartDemo()
{
var delay = 500;
foreach (var index in Enumerable.Range(0, 5))
{
var item = new Parent { Name = $"Parent {index + 1}" };
Parents.Add(item);
await Task.Delay(delay);
}
// Add errors
for (var i = 0; i < 3; i++)
{
Parents[1].Errors.Add(new Child { Name = $"Child {i + 1}" });
await Task.Delay(delay);
}
// Remove errors
while (Parents[1].Errors.Any())
{
Parents[1].Errors.RemoveAt(Parents[1].Errors.Count - 1);
await Task.Delay(delay);
}
// Remove parents
while (Parents.Any())
{
Parents.RemoveAt(Parents.Count-1);
await Task.Delay(delay);
}
}
}
/// <summary>
/// Child (error item)
/// </summary>
public class Child
{
public string Name { get; set; }
}
/// <summary>
/// Parent
/// </summary>
public class Parent : INotifyPropertyChanged
{
public Parent()
{
System.Collections.Specialized.CollectionChangedEventManager.AddHandler(Errors,
delegate
{
OnPropertyChanged(nameof(Status));
});
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; OnPropertyChanged(); }
}
public string Status { get { return Errors.Any() ? "ERROR" : "OK"; } }
/// <summary>
/// Children/errors
/// </summary>
public ObservableCollection<Child> Errors { get; } = new ObservableCollection<Child>();
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
<!-- Xaml -->
<ItemsControl ItemsSource="{Binding Path=Parents}"
Grid.IsSharedSizeScope="True">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:Parent}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="ParentColumn" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!-- Parent label -->
<Label Content="{Binding Path=Name}"
x:Name="Label"/>
<!-- Errors -->
<ItemsControl ItemsSource="{Binding Path=Errors}"
Grid.Column="1">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:Child}">
<Label Content="{Binding Path=Name}"
Background="Red" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
<DataTemplate.Triggers>
<!-- Parent is ok -->
<DataTrigger Binding="{Binding Path=Status}"
Value="OK">
<Setter TargetName="Label" Property="Background" Value="Green" />
</DataTrigger>
<!-- Parent is not ok -->
<DataTrigger Binding="{Binding Path=Status}"
Value="ERROR">
<Setter TargetName="Label" Property="Background" Value="Red" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
推荐阅读
- php - 无法捕获 SwiftMailer 异常?
- scp - scp -r 拉取的文件顺序
- php - Strpos 没有返回预期的结果(而不是 FALSE)
- angular - 未定义标识符
- gmail-api - 现有的基于 gmail API 提供本地镜像、IMAP 和 SMTP 守护程序的工具?
- spring-boot - 加载本机库 db2jcct2 失败
- typescript - 为什么在对象文字中分配时,TypeScript 将字符串文字联合类型转换为字符串?
- python - 无法从字典中分离姓名和日期以便将它们写入 excel 文件
- r - 如何修复使用“嵌套”导致列表列的列表?
- amazon-web-services - 如何使用密码而不是密钥对ubuntu?