【问题标题】:How to update radio button in view from viewmodel?如何从视图模型更新视图中的单选按钮?
【发布时间】:2016-03-31 05:47:07
【问题描述】:

假设我在 view.xaml 中有几个单选按钮:

<RadioButton GroupName="Group" Content="Item1" Command="{Binding ChangeRadioSelectionCommand}" CommandParameter="Item1" />
<RadioButton GroupName="Group" Content="Item2" Command="{Binding ChangeRadioSelectionCommand}" CommandParameter="Item2" />
<RadioButton GroupName="Group" Content="Item3" Command="{Binding ChangeRadioSelectionCommand}" CommandParameter="Item3" />

然后在我的viewmodel.cs 我有类似的东西:

public class ViewModel : BindableBase
{
  private string radioSelection = "Item1";
  public string RadioSelection
  {
    get { return this.radioSelection; }
    set { SetProperty(ref this.radioSelection, value); }
  }

  public ViewModel() 
  {
    this.ChangeRadioSelectionCommand = new DelegateCommand<string>(this.OnChangeRadioSelection, this.CanChangeRadioSelection);
  }

  public ICommand ChangeRadioSelectionCommand { get; private set; }
  private void OnChangeRadioSelection(string radioSelection)
  {
    RadioSelection = radioSelection;
  }
  private bool CanChangeRadioSelection(string radioSelection) { return true; }
}

这对于将视图中的值获取到视图模型中效果很好,但是如果视图模型中的某些内容发生变化,我将如何从视图模型转到视图。为简单起见,假设我向 xaml 添加了一个按钮:

<Button Command="{Binding ResetRadioSelectionCommand}" />

它所做的只是将收音机选择重置为第一项,因此viewmodel.cs 看起来像:

public class ViewModel : BindableBase
{
  private string radioSelection = "Item1";
  public string RadioSelection
  {
    get { return this.radioSelection; }
    set { SetProperty(ref this.radioSelection, value); }
  }

  public ViewModel() 
  {
    this.ChangeRadioSelectionCommand = new DelegateCommand<string>(this.OnChangeRadioSelection, this.CanChangeRadioSelection);
    this.ResetRadioSelectionCommand = new DelegateCommand(this.OnResetRadioSelection, this.CanResetRadioSelection);
  }

  public ICommand ChangeRadioSelectionCommand { get; private set; }
  private void OnChangeRadioSelection(string radioSelection)
  {
    RadioSelection = radioSelection;
  }
  private bool CanChangeRadioSelection(string radioSelection) { return true; }

  public ICommand ResetRadioSelectionCommand { get; private set; }
  private void OnResetRadioSelection()
  {
    RadioSelection = "Item1";
  }
  private bool CanResetRadioSelection() { return true; }
}

这会改变 radioSelection,但不会反映在 gui 中。有没有办法做到这一点?或者也许只是处理单选按钮的更好方法?

【问题讨论】:

    标签: c# wpf mvvm data-binding prism


    【解决方案1】:

    这是完全错误的方式。您的 ViewModel 应该包含一个具有合理名称的合理属性。例如,CurrentMode。

    第一个解决方案

    视图模型

    public enum DisplayMode { Vertical, Horizontal, Diagonal }
    
    private DisplayMode currentMode;
    public DisplayMode CurrentMode
    {
        get { return currentMode; }
        set { SetProperty(ref currentMode, value); }
    }
    

    现在您可以通过IValueConverter将此属性绑定到RadioButton.IsChecked

    <RadioButton GroupName="Group" Content="Vertical" IsChecked="{Binding CurrentMode, Converter={StaticResource enumToBoolConverter}, ConverterParameter=Vertical}" />
    <RadioButton GroupName="Group" Content="Horizontal" IsChecked="{Binding CurrentMode, Converter={StaticResource enumToBoolConverter}, ConverterParameter=Horizontal}" />
    <RadioButton GroupName="Group" Content="Diagonal" IsChecked="{Binding CurrentMode, Converter={StaticResource enumToBoolConverter}, ConverterParameter=Diagonal}" />
    

    转换器对所有枚举都是通用的。您需要将其添加到您的项目中并在视图的资源块中声明。

    public class EnumBooleanConverter : IValueConverter
    {
        #region IValueConverter Members
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string parameterString = parameter as string;
            if (parameterString == null)
                return DependencyProperty.UnsetValue;
    
            if (Enum.IsDefined(value.GetType(), value) == false)
                return DependencyProperty.UnsetValue;
    
            object parameterValue = Enum.Parse(value.GetType(), parameterString);
    
            return parameterValue.Equals(value);
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string parameterString = parameter as string;
            if (parameterString == null)
                return DependencyProperty.UnsetValue;
    
            return Enum.Parse(targetType, parameterString);
        }
        #endregion
    }
    

    这是众多解决方案之一。您可能不希望我们为您的属性枚举,因为主题区域未映射到参数枚举。然后你可以绑定到文本值:

    第二个解决方案

    视图模型

    private string currentMode;
    public string CurrentMode
    {
        get { return currentMode; }
        set { SetProperty(ref currentMode, value); }
    }
    

    查看

    <RadioButton Name="RadioButton1"
                         GroupName="Group"
                         Content="Vertical"
                         IsChecked="{Binding Path=CurrentMode, Converter={StaticResource boolToStringValueConverter}, ConverterParameter=Vertical}" />
            <RadioButton Name="RadioButton2"
                         GroupName="Group"
                         Content="Horizontal"
                         IsChecked="{Binding Path=CurrentMode, Converter={StaticResource boolToStringValueConverter}, ConverterParameter=Horizontal}" />
            <RadioButton Name="RadioButton3"
                         GroupName="Group"
                         Content="Diagonal"
                         IsChecked="{Binding Path=CurrentMode, Converter={StaticResource boolToStringValueConverter}, ConverterParameter=Diagonal}" />
    

    转换器

    public class BooleanToStringValueConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (System.Convert.ToString(value).Equals(System.Convert.ToString(parameter)))
            {
                return true;
            }
            return false;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (System.Convert.ToBoolean(value))
            {
                return parameter;
            }
            return null;
        }
    }
    

    一般原则是将有意义的主题区域投影存储在 ViewModel 中。如果您将视图属性的存储副本保留在您的 ViewModel 中,那没有多大意义。 RadioSelection 是一个毫无意义的名称,如果没有额外的注释,它就无法与模型相关联。

    【讨论】:

    • “您的 ViewModel 应包含具有合理名称的合理属性”是什么意思?如今,对于 prism mvvm 实践和模式,转换器方法是否仍然必要?
    • 1.我的意思是,属性名称应该根据主题区域而不是您的视图(如按钮、收音机组等)来明确。或其他人。
    • 是的,我只是给出了通用名称,因为它只是一个示例。我偶然发现a page that suggests using radios as a checkbox, overriding onchecked and ontoggled, or using radios as a list 是一种解决单选按钮绑定问题的方法。您对这些方法有什么意见吗?
    • 我不确定我是否记得这个问题。 .net 4.0 存在 5 年,WinXP 支持 .net 4.0,然后我可能从未将 wpf 与 .net 3.5 一起使用,因为直到 2011 年才使用 winforms。但是文章包含的解决方案很少,它们不适合吗?带有自定义模板的复选框将来可能会成为问题,但是具有继承样式的继承单选按钮不是问题,不是吗?
    猜你喜欢
    • 1970-01-01
    • 2022-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-26
    • 2019-12-13
    • 2011-08-09
    相关资源
    最近更新 更多