使用相同的 ViewModel 打开两个窗口时无法设置单选按钮值
Posted
技术标签:
【中文标题】使用相同的 ViewModel 打开两个窗口时无法设置单选按钮值【英文标题】:Unable to Set Radio Button value when two windows are opened using the same ViewModel 【发布时间】:2013-02-12 11:08:44 【问题描述】:我在同时打开的两个窗口中使用以下控件模板,并且都使用相同的视图模型。 这是模板;
<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>
这里是 viewmodel 属性:
private SecurityTypeEnum _securityType;
public SecurityTypeEnum SecurityType
get return _securityType;
set
_securityType = value; RaisePropertyChanged("SecurityType");
这是枚举:
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);
这个问题有点奇怪。我有两个窗口显示 SAME ViewModel 的视图略有不同。上面显示的相同模板在两个视图中重复使用。 如果 Equity 最初设置为 SecurityType,我可以通过单击相关单选按钮将其更改为 FixedIncome。然后我无法将其更改回股权。 但是,我可以将其设置为期货。但在那之后,我无法通过单击相关单选按钮将其更改为 FixedIncome 或 Equity。 在我无法设置更改的情况下发生的情况是 Setter 被调用了两次。第一次将值设置为正确的选定值,但在触发 RaisePropertyChanged 的那一刻, 再次调用 setter,这次使用原始值。 感觉就像当 RaisePropertyChanged 时,setter 被第二个窗口的绑定调用,从而覆盖了用户进行选择的第一个窗口中设置的值。 有谁知道是否是这种情况以及在这种情况下如何避免?
【问题讨论】:
你的 EnumBoolConverter 是什么样的?我曾经遇到过同样的问题,发现是我的转换器搞砸了一切,但我不记得到底是什么问题。 我已编辑帖子以包含转换器。 迈克:看看我的回答。EnumToBoolConverter
应该在 ConvertBack
中返回一个布尔值。试试看,让我知道。
【参考方案1】:
RadioButton 的默认行为是在属性更改时更新源,因此两个窗口都尝试更新源。一种解决方法是仅从用户单击的位置更新源。为此,请在绑定上使用 Binding.UpdateSourceTrigger Explicit。在 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();
您可能必须使用 UserControl 代替 ControlTemplate 或在 ControlTemplate 中使用,以便在您的视图中获取代码。
【讨论】:
谢谢。我最初尝试过这个,但我确实希望在新选择的选项时更新另一个窗口,所以这个解决方案没有为我做到这一点。 对于这种情况,EnumToBoolConverter 是答案,因为它最简单。不过,UpdateSourceTrigger 可能会帮助其他人。要点是 UpdateSourceTrigger 让您可以控制何时更新绑定源。如此处所示,当用户通过 RadioButton_Click 事件在一个窗口中选择新选择的选项时,它会特别更新其他窗口。【参考方案2】:这是我的 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;
【讨论】:
是的,这解决了问题。那么在这种情况下,Convert 和 ConvertBack 都返回一个布尔值?当你想到“转换回来”这个词时,它有点不直观......但现在我不得不考虑它,我认为它是有道理的。非常感谢! 不,我的错。实际上 ConvertBack 返回parameter
值(它实际上是一个字符串,仅在尝试将 RadioButton.IsChecked = true
转换回 Enum 时。我猜绑定框架能够自行将字符串转换为 Enum 值。跨度>
以上是关于使用相同的 ViewModel 打开两个窗口时无法设置单选按钮值的主要内容,如果未能解决你的问题,请参考以下文章
如何将相同的viewmodel设置为xamarin表单中的新mvvm中的两个视图