C# - 具有动态数量可绑定属性的类

发布于 2024-11-08 16:52:21 字数 634 浏览 0 评论 0原文

我有 X 个单选按钮(Silverlight)。通常这个值在2-5之间。 称之为“开关”。每个单选按钮都绑定到该类的一个属性。

示例属性看起来像

private bool _radio1;
public bool Radio1{
 set{
  _radio1 = value;
  _radioX = !value; // make all others false
 }
 get{ return _radio1 }
}

基本思想是,如果选择一个无线电,则所有其他无线电都将关闭。

我尝试过使用其他方法,与使用模板创建列表相比,这似乎是最简单的(特别是当我在某些情况下有单选涉及的其他按钮时)

目前我有两个要求,我需要一个具有 2 个属性的类(例如,男性) /Female) 复选框和 3 个属性。

将来可能会有更多,因此我认为为 X 数量的单选按钮编写一个新类是愚蠢的。

有没有办法以某种方式使属性的数量动态化?我看到了一些字典方法。

我看到了这个方法 如何在 C# 中创建动态属性?

但我不确定如何绑定到它。

I have X number of RadioButtons (Silverlight). Normally this value is between 2-5.
Call it "Switch". Each radio button is binded to a property of that class.

Example property looks like

private bool _radio1;
public bool Radio1{
 set{
  _radio1 = value;
  _radioX = !value; // make all others false
 }
 get{ return _radio1 }
}

Basic idea is that if one radio is selected all other ones are switched off.

I have tried using other approaches, this one seems the easiest compared to creating list with templates (especially when I have other buttons involved by radio in some cases)

At the moment I have two requirements I need one class with 2 properties (eg. Male/Female) checkbox and 3 properties.

There could be more in the future hence why I thought it would be silly to write a new class for X amount of radio buttons.

Is there anyway of making number of properties dynamic in some way? I saw some dictionary approaches.

I saw this approach
How do I create dynamic properties in C#?

I'm not sure how to bind to it though.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

顾铮苏瑾 2024-11-15 16:52:21

尽管使用 C# 的动态功能很有趣,但在本例中不需要。良好的老式数据绑定功能足够强大,可以完成我们想要的事情。例如。 RadioButton 模板将 ItemsControl 绑定到集合:

<Grid>
    <StackPanel>
        <ItemsControl ItemsSource="{Binding}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <RadioButton
                        GroupName="Value"
                        Content="{Binding Description}"
                        IsChecked="{Binding IsChecked, Mode=TwoWay}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        <TextBlock Text="{Binding SelectedItem}"/>
    </StackPanel>
</Grid>

以下是在代码隐藏或视图模型中使用它的方法:

DataContext = new CheckBoxValueCollection(new[] { "Foo", "Bar", "Baz" });

下面是一些 XAML,它使用您所需要的只是使其发挥作用的集合。以下是复选框值的集合:

public class CheckBoxValueCollection : ObservableCollection<CheckBoxValue>
{
    public CheckBoxValueCollection(IEnumerable<string> values)
    {
        foreach (var value in values)
        {
            var checkBoxValue = new CheckBoxValue { Description = value };
            checkBoxValue.PropertyChanged += (s, e) => OnPropertyChanged(new PropertyChangedEventArgs("SelectedItem"));
            this.Add(checkBoxValue);
        }
        this[0].IsChecked = true;
    }

    public string SelectedItem
    {
        get { return this.First(item => item.IsChecked).Description; }
    }
}

以下是复选框值本身:

public class CheckBoxValue : INotifyPropertyChanged
{
    private string description;
    private bool isChecked;

    public string Description
    {
        get { return description; }
        set { description = value; OnPropertyChanged("Description"); }
    }
    public bool IsChecked
    {
        get { return isChecked; }
        set { isChecked = value; OnPropertyChanged("IsChecked"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

现在您拥有完全动态的数据驱动和数据绑定友好的单选按钮设计。

示例程序如下所示:

在此处输入图像描述

单选按钮下方的文本显示当前选定的项目。尽管在此示例中我使用了字符串,但您可以轻松更改设计以使用enum 值或单选按钮描述的其他来源。

Although using dynamic features of C# is fun, it is not needed in this case. Good old fashioned databinding is powerful enough to do what we want. For example. Here is some XAML that binds an ItemsControl to a collection with a RadioButton template:

<Grid>
    <StackPanel>
        <ItemsControl ItemsSource="{Binding}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <RadioButton
                        GroupName="Value"
                        Content="{Binding Description}"
                        IsChecked="{Binding IsChecked, Mode=TwoWay}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        <TextBlock Text="{Binding SelectedItem}"/>
    </StackPanel>
</Grid>

And here is how you use it in the code-behind or from a view-model:

DataContext = new CheckBoxValueCollection(new[] { "Foo", "Bar", "Baz" });

Now all you need is the collection to make it work. Here is the collection of check box values:

public class CheckBoxValueCollection : ObservableCollection<CheckBoxValue>
{
    public CheckBoxValueCollection(IEnumerable<string> values)
    {
        foreach (var value in values)
        {
            var checkBoxValue = new CheckBoxValue { Description = value };
            checkBoxValue.PropertyChanged += (s, e) => OnPropertyChanged(new PropertyChangedEventArgs("SelectedItem"));
            this.Add(checkBoxValue);
        }
        this[0].IsChecked = true;
    }

    public string SelectedItem
    {
        get { return this.First(item => item.IsChecked).Description; }
    }
}

And here are the check box values themselves:

public class CheckBoxValue : INotifyPropertyChanged
{
    private string description;
    private bool isChecked;

    public string Description
    {
        get { return description; }
        set { description = value; OnPropertyChanged("Description"); }
    }
    public bool IsChecked
    {
        get { return isChecked; }
        set { isChecked = value; OnPropertyChanged("IsChecked"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

Now you have a completely dynamic data-driven and databinding-friendly radio button design.

Here is what the sample program looks like:

enter image description here

The text below the radios shows the currently selected item. Although in this example I've used strings, you can easily change the design to use enum values or other sources for the radio button description.

伪心 2024-11-15 16:52:21

也许您应该尝试使用绑定到字典? (或者带有 this[string x] 索引器的对象?)

像这样:

public class AnyGroup : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    IDictionary<string, bool> _options;
    public AnyGroup(IDictionary<string, bool> options)
    {
        this._options = options;
    }

    public bool this[string a]
    {
        get
        {
            return _options[a];
        }
        set
        {
            if (value)
            {
                var other = _options.Where(p => p.Key != a).Select(p => p.Key).ToArray();
                foreach (string key in other)
                    _options[key] = false;
                _options[a] = true;

                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Item[]"));
            }
            else
                _options[a] = false;                
        }
    }        
}

数据绑定将如下所示:

cbGroup.DataContext = new AnyGroup(new Dictionary<string, bool>() { {"male", true}, {"female", false} } );

...

<StackPanel Name="cbGroup">
    <CheckBox IsChecked="{Binding [male], Mode=TwoWay}" />
    <CheckBox IsChecked="{Binding [female], Mode=TwoWay}" />
</StackPanel>

Maybe you should try using binding to a dictionary? (Or to an object with a this[string x] indexer?)

Something like this:

public class AnyGroup : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    IDictionary<string, bool> _options;
    public AnyGroup(IDictionary<string, bool> options)
    {
        this._options = options;
    }

    public bool this[string a]
    {
        get
        {
            return _options[a];
        }
        set
        {
            if (value)
            {
                var other = _options.Where(p => p.Key != a).Select(p => p.Key).ToArray();
                foreach (string key in other)
                    _options[key] = false;
                _options[a] = true;

                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Item[]"));
            }
            else
                _options[a] = false;                
        }
    }        
}

And the databinding would be like this:

cbGroup.DataContext = new AnyGroup(new Dictionary<string, bool>() { {"male", true}, {"female", false} } );

...

<StackPanel Name="cbGroup">
    <CheckBox IsChecked="{Binding [male], Mode=TwoWay}" />
    <CheckBox IsChecked="{Binding [female], Mode=TwoWay}" />
</StackPanel>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文