C# 当使用相同的ViewModel打开两个窗口时,无法设置单选按钮值
我在两个同时打开的窗口中使用以下控件模板,并且两个窗口都使用相同的viewmodel。 这是模板C# 当使用相同的ViewModel打开两个窗口时,无法设置单选按钮值,c#,.net,wpf,mvvm,C#,.net,Wpf,Mvvm,我在两个同时打开的窗口中使用以下控件模板,并且两个窗口都使用相同的viewmodel。 这是模板 <ControlTemplate x:Key="SecurityTypeSelectionTemplate"> <StackPanel> <RadioButton GroupName ="SecurityType" Content="Equity" IsChecked="{Bi
<ControlTemplate x:Key="SecurityTypeSelectionTemplate">
<StackPanel>
<RadioButton GroupName ="SecurityType" Content="Equity"
IsChecked="{Binding Path=SecurityType, Mode=TwoWay, Converter={StaticResource EnumBoolConverter}, ConverterParameter=Equity}" />
<RadioButton GroupName ="SecurityType" Content="Fixed Income"
IsChecked="{Binding Path=SecurityType, Mode=TwoWay, Converter={StaticResource EnumBoolConverter}, ConverterParameter=FixedIncome}" />
<RadioButton GroupName ="SecurityType" Content="Futures"
IsChecked="{Binding Path=SecurityType, Mode=TwoWay, Converter={StaticResource EnumBoolConverter}, ConverterParameter=Futures}" />
</StackPanel>
</ControlTemplate>
以下是枚举:
public enum SecurityType { Equity, FixedIncome, Futures }
以下是转换器:
public class EnumToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object enumTarget, CultureInfo culture)
{
string enumTargetStr = enumTarget as string;
if (string.IsNullOrEmpty(enumTargetStr))
return DependencyProperty.UnsetValue;
if (Enum.IsDefined(value.GetType(), value) == false)
return DependencyProperty.UnsetValue;
object expectedEnum = Enum.Parse(value.GetType(), enumTargetStr);
return expectedEnum.Equals(value);
}
public object ConvertBack(object value, Type targetType, object enumTarget, CultureInfo culture)
{
string expectedEnumStr = enumTarget as string;
if (expectedEnumStr == null)
return DependencyProperty.UnsetValue;
return Enum.Parse(targetType, expectedEnumStr);
}
}
这个问题有点奇怪。我有两个窗口,显示同一ViewModel的略有不同的视图。上述相同的模板在两个视图中重复使用。
如果Equity最初设置为SecurityType,我可以通过单击相关单选按钮将其更改为FixedIncome。我不能把它改回衡平法。
不过,我可以把它设定为未来。但之后,我无法通过单击相关单选按钮将其更改为FixedIncome或Equity。在我无法将其设置回更改的情况下发生的情况是,设置器被调用了两次。第一次将该值设置为正确的选定值,但触发RaisePropertyChanged时, 再次调用setter,这次使用原始值。
这感觉就像当RaisePropertyChanged时,setter被第二个窗口的绑定调用,从而覆盖了在用户进行选择的第一个窗口中设置的值。
是否有人知道这种情况以及在这种情况下如何避免?以下是我的EnumToBoolConverter版本:
public class EnumToBoolConverter : BaseConverterMarkupExtension<object, bool>
{
public override bool Convert(object value, Type targetType, object parameter)
{
if (value == null)
return false;
return value.Equals(Enum.Parse(value.GetType(), (string)parameter, true));
}
public override object ConvertBack(bool value, Type targetType, object parameter)
{
return value.Equals(false) ? DependencyProperty.UnsetValue : parameter;
}
}
公共类EnumToBoolConverter:BaseConverterMarkupExtension
{
公共覆盖布尔转换(对象值、类型targetType、对象参数)
{
如果(值==null)
返回false;
返回value.Equals(Enum.Parse(value.GetType(),(string)参数,true));
}
公共重写对象转换回(布尔值、类型targetType、对象参数)
{
返回值.Equals(false)?DependencyProperty.Unset值:参数;
}
}
单选按钮的默认行为是在属性更改时更新源,以便两个窗口都尝试更新源。一种修复方法是仅从用户单击的位置更新源。要做到这一点,请在装订上明确说明。在RadioButton的代码隐藏中添加单击处理程序。在其中,明确更新源代码
<StackPanel>
<RadioButton GroupName ="SecurityType" Content="Equity"
IsChecked="{Binding Path=SecurityType, Mode=TwoWay, Converter={StaticResource EnumToBoolConverter}, UpdateSourceTrigger=Explicit, ConverterParameter=Equity}" Click="RadioButton_Click" />
<RadioButton GroupName ="SecurityType" Content="Fixed Income"
IsChecked="{Binding Path=SecurityType, Mode=TwoWay, Converter={StaticResource EnumToBoolConverter}, UpdateSourceTrigger=Explicit, ConverterParameter=FixedIncome}" Click="RadioButton_Click"/>
<RadioButton GroupName ="SecurityType" Content="Futures"
IsChecked="{Binding Path=SecurityType, Mode=TwoWay, Converter={StaticResource EnumToBoolConverter}, UpdateSourceTrigger=Explicit, ConverterParameter=Futures}" Click="RadioButton_Click"/>
</StackPanel>
private void RadioButton_Click(object sender, RoutedEventArgs e)
{
BindingExpression be = ((RadioButton)sender).GetBindingExpression(RadioButton.IsCheckedProperty);
be.UpdateSource();
}
专用void单选按钮单击(对象发送者,路由目标e)
{
BindingExpression be=((RadioButton)发送方).GetBindingExpression(RadioButton.IsCheckedProperty);
be.UpdateSource();
}
您可能必须使用UserControl而不是ControlTemplate,或者在ControlTemplate中使用UserControl才能在视图中隐藏代码。您的EnumBoolConverter是什么样子的?我曾经遇到过同样的问题,发现是我的转换器把一切都搞糟了,但我记不清到底是什么问题。我编辑了这篇文章,把转换器也包括进去。迈克:看看我的答案。
enumtoolconverter
应在ConvertBack
中返回布尔值。试试看,让我知道。是的,这解决了问题。在这种情况下,Convert和ConvertBack都返回布尔值?当你想到“转换回”这个词时,这有点不直观……但现在我不得不去想它,我想这是有道理的。多谢!不,我错了。实际上ConvertBack返回参数
值(实际上是一个字符串,仅当尝试“转换回”时)RadioButton.IsChecked=true
到Enum。我想绑定框架本身能够将字符串转换为Enum值。谢谢。我最初尝试过这个,但我确实希望在新选择选项时更新另一个窗口,因此此解决方案不适合我。对于这种情况,EnumToBoolConverter是答案b因为这是最简单的。但UpdateSourceTrigger可能会帮助其他人。主要的一点是UpdateSourceTrigger让您可以控制何时更新绑定源。如本文所示,当用户通过RadioButton\u Click事件在一个窗口中选择新选择的选项时,它会特别更新其他窗口。
<StackPanel>
<RadioButton GroupName ="SecurityType" Content="Equity"
IsChecked="{Binding Path=SecurityType, Mode=TwoWay, Converter={StaticResource EnumToBoolConverter}, UpdateSourceTrigger=Explicit, ConverterParameter=Equity}" Click="RadioButton_Click" />
<RadioButton GroupName ="SecurityType" Content="Fixed Income"
IsChecked="{Binding Path=SecurityType, Mode=TwoWay, Converter={StaticResource EnumToBoolConverter}, UpdateSourceTrigger=Explicit, ConverterParameter=FixedIncome}" Click="RadioButton_Click"/>
<RadioButton GroupName ="SecurityType" Content="Futures"
IsChecked="{Binding Path=SecurityType, Mode=TwoWay, Converter={StaticResource EnumToBoolConverter}, UpdateSourceTrigger=Explicit, ConverterParameter=Futures}" Click="RadioButton_Click"/>
</StackPanel>
private void RadioButton_Click(object sender, RoutedEventArgs e)
{
BindingExpression be = ((RadioButton)sender).GetBindingExpression(RadioButton.IsCheckedProperty);
be.UpdateSource();
}