WPF - 使用 MVVM 根据模型的不同状态禁用和启用不同控件的优雅方法
我正在为以下问题寻找一个优雅的解决方案。
假设我们有一个具有以下布尔属性的(视图)模型:
- Alpha
- Beta
- Gamma
- Delta
接下来,我在表面上有 5 个控件,它们仅在满足基于这些属性的条件时才可见。当然,一旦这些属性之一被更新,更改就应该立即传播:
- ControlA -> ControlA -> ControlA -> ControlA -> ControlA -> ControlA -> ControlA -> ControlA -> ControlA -> ControlA阿尔法&& ( Beta || Gamma )
- ControlB ->台达
- 控制C ->达美航空|| Beta
- ControlD ->伽玛&&阿尔法&&台达
- 控制E ->阿尔法 || Gamma
到目前为止我想到的唯一解决方案是使用 MultiValueConverters。
ControlA 示例:
<ControlA>
<ControlA.Visibility>
<MultiBinding Converter={StaticResource ControlAVisibilityConverter}>
<Binding Path="Alpha"/>
<Binding Path="Beta"/>
<Binding Path="Gamma"/>
</MultiBinding>
</ControlA.Visibility>
</ControlA>
此 ControlAVsibilityConverter 检查条件“Alpha && ( Beta || Gamma )”并返回适当的值。
它确实有效..好吧..但也许你可以想出一个更优雅的解决方案?
谢谢你, 双生习惯
I am looking for an elegant solution for the following problem.
Let's assume we have a (View)Model with the following boolean properties:
- Alpha
- Beta
- Gamma
- Delta
Next I have 5 controls on the surface that shall only be visible when a condition based on those properties are met. Of course, as soon as one of those properties is updated the change should be propagated immediatelly:
- ControlA -> Alpha && ( Beta || Gamma )
- ControlB -> Delta
- ControlC -> Delta || Beta
- ControlD -> Gamma && Alpha && Delta
- ControlE -> Alpha || Gamma
The only solution I came up with so far is using MultiValueConverters.
Example for ControlA:
<ControlA>
<ControlA.Visibility>
<MultiBinding Converter={StaticResource ControlAVisibilityConverter}>
<Binding Path="Alpha"/>
<Binding Path="Beta"/>
<Binding Path="Gamma"/>
</MultiBinding>
</ControlA.Visibility>
</ControlA>
This ControlAVisibilityConverter checks for condition "Alpha && ( Beta || Gamma )" and returns the appropriate value.
It does work.. well.. but maybe you can come up with a more elegant solution?
Thank you,
TwinHabit
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在这种情况下,为每个规则编写转换器会将您的业务逻辑置于两个位置(在转换器和视图模型中)。
我建议使用 INotifyPropertyChanged 事件为 ViewModel 中的每个控件创建一个属性/标志,以决定该控件是否可见(或其他行为)。
请注意,当您查看我的视图模型(如下)时,您将看到我公开了 bool 和 Visibilty 类型的属性。
如果您需要使用该属性作为一般规则,请使用 bool 和 DataTrigger。
如果您只需要控制可见性,可以直接绑定到 Visibility:
UPDATE:
由于@Wallstreet Programmer 的评论,我添加了另一个使用 BooleanVisibilityConverter 的选项。我更新了下面的第五个控件以反映如何使用转换器。我在底部添加了转换器的代码。
这是 XAML 中的测试窗口:
这是 ViewModel:
这是转换器:
Writing a converter for each rule puts your business logic two places in this case (in the converter and the view model).
I suggest creating a property/flag for each control in your ViewModel with INotifyPropertyChanged events to decide whether the control is visible (or other behaviour).
Note, that when you look at my viewmodel (below) you will see that I expose properties of type bool and Visibilty.
If you need to use the property as a general rule use bool and a DataTrigger.
If you only need to control visibility you can bind to Visibility directly:
UPDATE:
Because of the comment by @Wallstreet Programmer, I added another option to use a BooleanVisibilityConverter. I updated the fifth control below to reflect how to use a converter. I added the code for the converter at the bottom.
Here is a test Window in XAML:
Here is the ViewModel:
Here is the converter:
假设是否应显示控件存在业务逻辑原因,我肯定会将逻辑存储为 ViewModel 中的布尔值(尽管我会根据业务逻辑命名它,例如:CriteriaA 而不是 ControlAVsible)。这样可以轻松进行单元测试,以确保在 alpha、beta、gamma 和 delta 变化时正确设置标准。除此之外,我同意华尔街程序员的回答(尽管我没有代表评论或投票他的回答)。
Assuming that there's a business logic reason for whether or not the controls should be displayed I'd definitely have the logic stored as a bool in the ViewModel (though I'd name it according to the business logic e.g.: CriteriaA not ControlAVisible). This allows easy unit testing to ensure that the Criteria are set correctly as alpha, beta, gamma and delta change. Other than that I'd agree with Wallstreet Programmers answer (though I don't have the rep to comment or vote his response).
如果控件支持命令(例如,如果它们是按钮),请使用命令模式。使用 RelayCommand(查找),您可以使用 lambda 表达式指定启用控件的条件(这正是您所需要的)。但它需要一些隐藏代码。
If the controls support commands (for example if they are buttons), use command pattern. With
RelayCommand
(look it up), you can specify the condition under which the control is enable with an lambda expression (which is exactly what you need). It needs some code-behind though.