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

C# 如何绑定到WPF中动态创建的单选按钮?,c#,wpf,mvvm,binding,radio-button,C#,Wpf,Mvvm,Binding,Radio Button,我正在开发的应用程序中使用WPF和MVVM 我动态创建了5个单选按钮,在创建时,我使用枚举和IValueConverter设置绑定 这没关系,因为我知道我只需要5个单选按钮,但是现在我需要创建的单选按钮的数量可以改变,可以是5个,也可以是30个 那么,用代码绑定单选按钮的最佳方法是什么?我想我不能再使用枚举了,除非我设法动态创建枚举,我不知道我读到的关于动态枚举的内容是否可能 谢谢 编辑 这里或多或少是我用来动态创建单选按钮的代码 公共枚举映射选项{ 选项0, 选择1, 选择2, 选择3, 选择

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

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

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

那么,用代码绑定单选按钮的最佳方法是什么?我想我不能再使用枚举了,除非我设法动态创建枚举,我不知道我读到的关于动态枚举的内容是否可能

谢谢

编辑

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

公共枚举映射选项{
选项0,
选择1,
选择2,
选择3,
选择4
}
私有映射选项映射属性; 公共映射选项映射属性 { 获取{return mappingProperty;} 设置 {
mappingProperty=值; base.RaisePropertyChanged(“MappingProperty”);
} }
私有void CreateRadioButtons() { 整数极限=5; 整数计数=0; 字符串groupName=“groupName”;
parent.FormWithRadioButtons.Children.Clear(); foreach(所有CustomValue中的CustomValue值) { 如果(计数<限制) { System.Windows.Controls.RadioButton tmpRadioBtn=新的System.Windows.Controls.RadioButton(); tmpRadioBtn.DataContext=this; tmpRadioBtn.Content=value.Name; tmpRadioBtn.GroupName=GroupName; tmpRadioBtn.Margin=新系统窗口厚度(10,0,0,5); 字符串参数=string.format(“选项{0}”,count.ToString());
System.Windows.Data.Binding tmpBinding=新的System.Windows.Data.Binding(“MappingProperty”); tmpBinding.Converter=新的EnumBooleanConverter(); tmpBinding.ConverterParameter=参数; tmpBinding.Source=这个; 尝试 { tmpRadioBtn.SetBinding(System.Windows.Controls.RadioButton.IsCheckedProperty,tmpBinding); } 捕获(例外情况除外) { //句柄解释 }
parent.FormWithRadioButtons.Children.Add(tmpRadioBtn); 计数+=1; } 其他的 打破 }
MappingProperty=MappingOptions.Option0; }
公共类EnumBooleanConverter:IValueConverter { #地区/地区转换器成员
公共对象转换(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性) { string parameterString=作为字符串的参数; if(parameterString==null) 返回System.Windows.DependencyProperty.UnsetValue;
if(Enum.IsDefined(value.GetType(),value)==false) 返回System.Windows.DependencyProperty.UnsetValue;
object parameterValue=Enum.Parse(value.GetType(),parameterString);
返回参数value.Equals(值); } 公共对象转换回(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性) { string parameterString=参数为字符串;
if(parameterString==null) 返回System.Windows.DependencyProperty.UnsetValue;
返回Enum.Parse(targetType,parameterString); }
#端区 }

创建一个类,该类公开string
Text
和boolean
IsChecked
属性,并实现
INotifyPropertyChanged
。称之为MutexViewModel

创建另一个类,该类实现这些对象的可观察集合,称为
互斥体
,并在每个对象上处理
属性更改
,例如,具有如下构造函数:

public MutexesViewModel(IEnumerable<MutexViewModel> mutexes)
{
   _Mutexes = new ObservableCollection<MutexViewModel>();
   foreach (MutexViewModel m in Mutexes)
   {
      _Mutexes.Add(m);
      m.PropertyChanged += MutexViewModel_PropertyChanged;
   }
}
现在,您有了一种机制,可以创建任意数量的命名布尔属性,这些属性都是互斥的,即在任何给定时间,它们中只能有一个是真的

现在像这样创建XAML—这是一个
MutexesViewModel
对象的
DataContext
,但是您也可以将
ItemsSource
绑定到类似
{DynamicResource mymutexviewmodel.mutex}
的对象

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

请发布一些代码,以便我们了解您绑定到的内容。您好,谢谢您的回答,但我不认为我可以用它来解决我的问题,因为我需要从代码而不是从XAML创建单选按钮,我尝试使用您建议的类,并将其与我上面发布的代码相结合,但没有效果……完全没有必要从代码中创建这些单选按钮。请看我的编辑。非常感谢,我不知道为什么我第一次尝试时它不起作用,但今天当我再次尝试时,它起了很大的作用!
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;
   }
}
<ItemsControl ItemsSource="{Binding Mutexes}">
   <ItemsControl.ItemTemplate>
      <DataTemplate DataType="local:MutexViewModel">
         <RadioButton Content="{Binding Text}" IsChecked="{Binding IsChecked, Mode=TwoWay}"/>
      </DataTemplate>
   </ItemsControl.ItemTemplate>
</ItemsControl>
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; }

}
    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);
    }