如何绑定到WPF中动态创建的单选按钮?

时间:2011-04-04 18:02:26

标签: c# wpf mvvm binding radio-button

我正在我正在使用的应用程序中使用WPF和MVVM。

我正在动态创建5个单选按钮,在创建时我使用枚举和IValueConverter设置绑定。

这没关系,因为我知道我只需要5个单选按钮,但现在我需要创建的单选按钮的数量可以改变,它们可以是5,因为它们可能是30。

那么,这是将单选按钮与代码绑定的最佳方法吗?我想我不能再使用枚举,除非我设法动态创建枚举,我不知道是否有可能我读到有关动态枚举...

感谢。

修改

这里或多或少是我用来动态创建单选按钮的代码。

public enum MappingOptions {
        Option0,
        Option1,
        Option2,
        Option3,
        Option4
    }
private MappingOptions mappingProperty; public MappingOptions MappingProperty { get { return mappingProperty; } set {
mappingProperty= value; base.RaisePropertyChanged("MappingProperty");
} }
private void CreateRadioButtons() { int limit = 5; int count = 0; string groupName = "groupName";
parent.FormWithRadioButtons.Children.Clear(); foreach (CustomValue value in AllCustomValues) { if (count < limit) { System.Windows.Controls.RadioButton tmpRadioBtn = new System.Windows.Controls.RadioButton(); tmpRadioBtn.DataContext = this; tmpRadioBtn.Content = value.Name; tmpRadioBtn.GroupName = groupName; tmpRadioBtn.Margin = new System.Windows.Thickness(10, 0, 0, 5); string parameter = string.format("Option{0}", count.ToString());
System.Windows.Data.Binding tmpBinding = new System.Windows.Data.Binding("MappingProperty"); tmpBinding.Converter = new EnumBooleanConverter(); tmpBinding.ConverterParameter = parameter; tmpBinding.Source = this; try { tmpRadioBtn.SetBinding(System.Windows.Controls.RadioButton.IsCheckedProperty, tmpBinding); } catch (Exception ex) { //handle exeption }
parent.FormWithRadioButtons.Children.Add(tmpRadioBtn); count += 1; } else break; }
MappingProperty = MappingOptions.Option0; }
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 System.Windows.DependencyProperty.UnsetValue;
if (Enum.IsDefined(value.GetType(), value) == false) return System.Windows.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 System.Windows.DependencyProperty.UnsetValue;
return Enum.Parse(targetType, parameterString); }
#endregion }

1 个答案:

答案 0 :(得分:7)

创建一个公开字符串Text和布尔IsChecked属性并实现INotifyPropertyChanged的类。叫它,哦,MutexViewModel

创建另一个类,该类实现名为Mutexes的这些对象的可观察集合,并在每个对象上处理PropertyChanged - 例如有一个像:

这样的构造函数
public MutexesViewModel(IEnumerable<MutexViewModel> mutexes)
{
   _Mutexes = new ObservableCollection<MutexViewModel>();
   foreach (MutexViewModel m in Mutexes)
   {
      _Mutexes.Add(m);
      m.PropertyChanged += MutexViewModel_PropertyChanged;
   }
}

和一个事件处理程序,确保在任何给定时间只有一个子对象IsChecked设置为true:

private void MutexViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
   MutexViewModel m = (MutexViewModel)sender;
   if (e.PropertyName != "IsChecked" || !m.IsChecked)
   {
     return;
   }
   foreach (MutexViewModel other in _Mutexes.Where(x: x != m))
   {
      other.IsChecked = false;
   }
}

您现在有一种机制可以创建任意数量的命名布尔属性,这些属性都是互斥的,即在任何给定时间只能有一个属性为真。

现在像这样创建XAML - DataContext这是一个MutexesViewModel对象,但您也可以将ItemsSource绑定到{DynamicResource myMutexesViewModel.Mutexes}之类的内容。

<ItemsControl ItemsSource="{Binding Mutexes}">
   <ItemsControl.ItemTemplate>
      <DataTemplate DataType="local:MutexViewModel">
         <RadioButton Content="{Binding Text}" IsChecked="{Binding IsChecked, Mode=TwoWay}"/>
      </DataTemplate>
   </ItemsControl.ItemTemplate>
</ItemsControl>

修改

我发布的XAML中存在语法错误,但没有什么可以让你完全停止。这些课程有效:

public class MutexViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public string Text { get; set; }

    private bool _IsChecked;

    public bool IsChecked
    {
        get { return _IsChecked; }
        set
        {
            if (value != _IsChecked)
            {
                _IsChecked = value;
                OnPropertyChanged("IsChecked");
            }
        }
    }

    private void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler h = PropertyChanged;
        if (h != null)
        {
            h(this, new PropertyChangedEventArgs(propertyName));
        }
    }

}

public class MutexesViewModel
{
    public MutexesViewModel(IEnumerable<MutexViewModel>mutexes)
    {
        Mutexes = new ObservableCollection<MutexViewModel>(mutexes);
        foreach (var m in Mutexes)
        {
            m.PropertyChanged += MutexViewModel_PropertyChanged;
        }
    }

    private void MutexViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        MutexViewModel m = (MutexViewModel) sender;
        if (e.PropertyName == "IsChecked" && m.IsChecked)
        {
            foreach(var other in Mutexes.Where(x => x != m))
            {
                other.IsChecked = false;
            }
        }
    }

    public ObservableCollection<MutexViewModel> Mutexes { get; set; }

}

创建一个项目,添加这些类,将ItemsControl XAML粘贴到主窗口的XAML中,然后将其添加到主窗口的代码隐藏中:

    public enum Test
    {
        Foo,
        Bar,
        Baz,
        Bat
    } ;

    public MainWindow()
    {
        InitializeComponent();

        var mutexes = Enumerable.Range(0, 4)
            .Select(x => new MutexViewModel 
               { Text = Enum.GetName(typeof (Test), x) });

        DataContext = new MutexesViewModel(mutexes);
    }