开发者

C# - Class with dynamic number of properties that are bind-able

开发者 https://www.devze.com 2023-03-07 15:38 出处:网络
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.

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.


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:

C# - Class with dynamic number of properties that are bind-able

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.


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>
0

精彩评论

暂无评论...
验证码 换一张
取 消