使用动态内容创建布局时,我经常会这样做:
<Grid Visibility="{Binding IsLastSelectedItem, Converter=...}" >
<Grid Visibility="{Binding IsStatisticAvailable, Converter=...}" >
<TextBlock Visibility="{Binding HasStatistic, Converter=...}"
Text="{Binding Statistic}" />
</Grid>
</Grid>
这里有2个容器仅用于根据多个条件显示某些内容,它的3个绑定与逻辑AND
相结合。
使用MVVM可以创建单个属性并直接绑定到它:
public bool ShowStatistic => IsLastSelectedItem && IsStatisticAvailable && HasStatistic;
但它并不总是可行/容易且有缺点。我必须监视所有条件属性的更改并提高结果属性的通知。如果其中一个条件属性是静态的或特定于视图的,则添加事件处理程序,订阅/取消订阅等不可避免的麻烦,以使其在viewmodel和/或上升通知中可用。
昨天有了SO帮助我创建了nice control来添加动态内容。它有一个bool
依赖项属性来显示/隐藏其内容。现在我正在考虑如何避免为多个绑定嵌套多个此类控件,如上例所示。
问题:管理多重绑定用于创建动态内容布局的最佳(可重用,易用,简短,易于理解)的方法是什么?我可能缺乏找到类似问题的正确词语。
我能想到多重绑定和转换器。可重复使用的?一定不行。或者不是?
我可以考虑创建具有多个MyGrid
属性的自定义容器(bool
),由多个绑定和一些其他属性用来指定表达式:AND
,OR
等。
也许我错过了一些明显而简单的东西?
答案 0 :(得分:1)
在这种情况下,多值转换器是理想的选择。
如下所示:
public class MultiBoolToVisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if(values.All(v=>v is bool))
return values.All(v=>(bool)v)?
Visibility.Visible:
Visibility.Hidden;
else
throw new ArgumentException("Cannot determine boolean state of non-boolean value");
}
}
这样你就有了一个可扩展的转换器,它接受一个或多个布尔值,并且只有当'values'数组中的所有项都为真时才返回'Visible'。
在你的xaml中:
<TextBlock Text="{Binding Statistic}" >
<TextBlock.Visibility>
<MultiBinding Converter="{StaticResource MultiBoolToVisibilityConverter }">
<Binding Path="IsLastSelectedItem" />
<Binding Path="IsStatisticAvailable" />
<Binding Path="HasStatistic" />
</MultiBinding>
</TextBlock.Visibility>
</TextBlock>
在您有多个标志以确定可见性的任何区域都可以高度重复使用,而且它也可以进行单元测试。
答案 1 :(得分:0)
以下是使用附加属性的解决方案:
public static class Logic
{
public enum Equation { Empty, AandBorCandD, ... }; // more options
public static bool GetA(DependencyObject obj) => (bool)obj.GetValue(AProperty);
public static void SetA(DependencyObject obj, bool value) => obj.SetValue(AProperty, value);
public static readonly DependencyProperty AProperty =
DependencyProperty.RegisterAttached("A", typeof(bool), typeof(Logic), new PropertyMetadata(OnValueChanged));
// reduced content, normal attached properties, defined similar to AProperty above
public static bool GetB... // BProperty
public static bool GetC... // CProperty
public static bool GetD... // DProperty
public static Equation GetEquation... // EquationProperty
public static bool GetR... // RProperty = result
static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
switch (GetEquation(obj))
{
case Equation.AandBorCandD:
SetR(obj, GetA(obj) && GetB(obj) || GetC(obj) && GetD(obj));
break;
... // other options
}
}
这个想法是使用几个附加属性进行绑定,并将所需属性绑定到&#34;结果&#34;,每次更改某些内容时都会重新计算(类似于多重绑定)。
将公式指定为enum
,并计算结果switch/case
。
用法很简单:
<TextBlock local:Logic.A="{Binding ...}"
local:Logic.B="{Binding ...}"
local:Logic.C="{Binding ...}"
local:Logic.D="{Binding ...}"
local:Logic.Equation="AandBorCandD"
Visibility="{Binding (local:Logic.R), RelativeSource={RelativeSource Self}, Converter=...}" />
注意:
()
路径。