我有一个带有MultiBinding的复选框,其中一个绑定是双向的(到视图模型),另一个是单向的(到它自己的IsEnabled属性)。一切看起来都很好,直到我点击了MultiBinding复选框。然后我突然松开了一个绑定。
下面的示例演示了这种效果。在实际程序中,IsEnabled属性也是一个多绑定,但这似乎没有什么区别。
<Window x:Class="TwowayMultiBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TwowayMultiBinding"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel>
<StackPanel.Resources>
<local:LogicalAndConverter x:Key="LogicalAndConverter"/>
</StackPanel.Resources>
<CheckBox Content="Enabled" Name="EnableCheck"/>
<CheckBox Content="Ticked" Name="TickCheck"/>
<CheckBox Content="Test" Name="TestCheck" IsEnabled="{Binding ElementName=EnableCheck, Path=IsChecked}">
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource LogicalAndConverter}">
<Binding ElementName="TestCheck" Path="IsEnabled" Mode="OneWay"/>
<Binding ElementName="TickCheck" Path="IsChecked" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
</StackPanel>
</Window>
我使用下面的转换器:
public class LogicalAndConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values == null || values.Length < 2)
{
return DependencyProperty.UnsetValue;
}
for (int i = 0; i < values.Length; i++)
{
bool result;
if (values[i] is bool bValue)
{
result = bValue;
}
else if (values[i] is bool?)
{
result = ((bool?)values[i]) ?? false;
}
else
{
return DependencyProperty.UnsetValue;
}
if (!result)
{
return false; // early exit.
}
}
return true;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool bValue)
{
return Enumerable.Repeat(value, targetTypes.Length).ToArray();
}
else if (value is bool?)
{
bool result = ((bool?)value) ?? false;
return Enumerable.Repeat((object)result, targetTypes.Length).ToArray();
}
return null;
}
当我运行这个例子时,TestCheck被禁用,因为Enabled复选框没有被选中(正确)。
要重现此问题:
- 单击启用=〉测试检查已启用(正确)。
- 点击勾选=〉测试检查勾选(正确)。
- 点击勾选=〉测试检查未勾选(正确)。
- 点击勾选=〉测试检查勾选(正确)。
- 点击启用=〉测试检查被禁用且未勾选(正确)。
- 单击启用=〉启用并勾选测试检查(因为勾选检查仍处于勾选状态)。(correct)
- 单击测试=〉未选中测试检查(正确)。
但是现在,启用检查不再起作用了。我松开了绑定吗?
短路线:
- 开始
- 单击启用=〉测试检查已启用(正确)。
- 单击测试=〉未选中测试检查(正确)。
再一次,启用不再起作用。
我想做的是:
- 将check值绑定到它的视图模型(双向)。
- 如果未选中"启用",则应无法以任何方式选中"测试"检查。
3条答案
按热度按时间ztyzrc3y1#
是的,你实际上失去了约束力。
如果将dependencyproperty设置为一个值,则该值将覆盖任何绑定,除非绑定是双向的。
单击时,将在“测试”上设置ischecked值。
避免这种情况的一个方法是将逻辑移到视图模型中,然后就可以在各种属性的setter和getter中精确地控制你想要发生的事情。
您可能需要考虑中间属性,这样您就有了表示视图和输入的属性、其他属性或表示内部状态的字段。
也许您正尝试将“测试”复选框用于两个不同的目的,其中两个不同的控件可能更合适。也许它应该是只读的。
11dmarpk2#
我认为您需要更换反向转换器:
xzv2uavs3#
Andy回答说除非是双向绑定,否则绑定实际上会丢失,我决定将其设置为双向绑定,并让第二个转换器在我点击Test Check时避免复选框被禁用。
LogicalAndConverter类没有改变。不确定这个解决方案在美学上是否正确,但至少它能工作。