我有一个WPF应用程序,它应该提醒用户泵中即将发生的错误。有三种类型的错误,我将它们定义为PumpErrorModel中的枚举。这个pumpErrorModel还知道哪种类型的错误最可能发生。这是由我的PumpErrorViewModel向GUI公开的,GUI有一个标签绑定到这个最可能的错误的值,并将其转换为字符串。到目前为止,一切顺利。
// from MainWindow.xaml
<Label ... Content="{Binding LikelyError, Converter={StaticResource PumpErrorTypeToString}}" />
// from PumpErrorViewModel.cs
private PumpErrorModel.PumpErrorType likelyError;
public PumpErrorModel.PumpErrorType LikelyError {
get { return likelyError; }
private set { likelyError = value; RaisePropertyChanged("LikelyError"); } }
在我的GUI中,我也有每种类型的泵错误的描述,即每个枚举值一个。我想将这些标签的背景绑定到最可能的错误类型的值,这样当最可能的错误类型是"爆炸"时,描述爆炸的标签具有红色背景,而其他标签具有白色背景。
// from MainWindow.xaml. I would like to bind the background of these
<Label Content="Likely Error: Explosions" />
<Label Content="Likely Error: More Explosions!" />
<Label Content="Likely Error: Rabbits!!!" />
我可以在视图模型中为每种类型的错误创建一个布尔属性,以指示可能的错误是否属于特定类型。然后我可以将每个标签背景绑定到相应的属性。但这对我来说似乎有点混乱,因为我必须在原始可能错误属性的setter中对这些额外的属性调用RaisePropertyChanged。
// proposed code in PumpErrorViewModel.cs
public bool IsRabbits { get { return LikelyError == PumpErrorModel.PumpErrorType.Rabbits; } };
// amended LikelyError setter
public PumpErrorModel.PumpErrorType LikelyError {
get ...
private set { likelyError = value;
RaisePropertyChanged("LikelyError");
RaisePropertyChanged("IsRabbits"); } }
// proposed code in MainWindow.xaml
<Label Content="Likely Error: Rabbits!!!" BackGround="{Binding IsRabbits, Converter){StaticResource BoolToColor}}" />
如果我这样做,那么我在LikelyError和israbbit之间有一个耦合,每当我添加新的错误类型和布尔属性时,我可能会忘记这个耦合。有没有更好的方法来实现我的目标?
在主视图模型上使用子集合似乎是一个很好的情况。该子集合中的每个视图模型将表示单个泵错误类型。然后,您的视图将绑定到该集合,以列出所有潜在的泵错误并突出显示可能的错误。下面是我们讨论的起点:
public class MainViewModel : ViewModel
{
private readonly ICollection<PumpErrorTypeViewModel> pumpErrorTypes;
public MainViewModel()
{
this.pumpErrorTypes = Enum.GetValues(typeof(PumpErrorType))
.Cast<PumpErrorType>()
.Select(x => new PumpErrorTypeViewModel(x))
.ToList();
}
pubilc ICollection<PumpErrorTypeViewModel> PumpErrorTypes
{
get { return this.pumpErrorTypes; }
}
public class PumpErrorTypeViewModel : ViewModel
{
private readonly PumpErrorType type;
public PumpErrorTypeViewModel(PumpErrorType type)
{
this.type = type;
}
public PumpErrorType Type
{
get { return this.type; }
}
public string Display
{
// do whatever formatting you like here
get { return string.Format("Likely Error: {0}", this.type); }
}
}
<ItemsControl ItemsSource="{Binding PumpErrorTypes}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Display}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
现在,为了给标签的背景上色,我们有很多方法可以实现这一点,但最常见的两种方法是:
-
MainViewModel
可能具有LikelyError
属性。PumpErrorTypeViewModel
可以在其构造函数中接受MainViewModel
,并暴露Background
的属性。它可以监听LikelyError
中的变化,并相应地使Background
失效。这非常适合响应式实现(参见ReactiveUI)。 -
PumpErrorViewModel
可以暴露IsLikely
属性,当设置Background
属性时,该属性无效。MainViewModel
可以在LikelyError
变化时循环所有pumpErrorTypes
,并更新子IsLikely
属性。
无论哪种方式,视图都有一个简单的更改:
<Label Content="{Binding Display}" Background="{Binding Background}"/>