C # - класс с динамическим числом свойств, которые могут быть привязаны - PullRequest
2 голосов
/ 19 мая 2011

У меня есть X количество радиокнопок (Silverlight).Обычно это значение находится между 2-5.Назовите это «Переключатель».Каждая радио-кнопка привязана к свойству этого класса.

Пример свойства выглядит как

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

Основная идея состоит в том, что если выбрана одна радиостанция, все остальные отключаются.

Я пробовал использовать другие подходы, этот, кажется, самый простой по сравнению с созданием списка с шаблонами (особенно, когда в некоторых случаях радио использует другие кнопки)

На данный момент у меня есть дватребования Мне нужен один класс с 2-мя свойствами (например, мужской / женский) и 3-мя свойствами.

В будущем может быть больше, поэтому я подумал, что было бы глупо писать новый класс для количества Xпереключатели.

Можно ли каким-то образом сделать динамический ряд свойств?Я видел некоторые словарные подходы.

Я видел этот подход Как создать динамические свойства в C #?

Хотя я не уверен, как с ним связываться.

Ответы [ 2 ]

5 голосов
/ 20 мая 2011

Хотя использование динамических функций C # увлекательно, в этом случае оно не требуется. Хорошее старомодное связывание данных достаточно мощно, чтобы делать то, что мы хотим. Например. Вот некоторый XAML, который связывает ItemsControl с коллекцией с шаблоном RadioButton:

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

Теперь все, что вам нужно, это коллекция, чтобы она заработала. Вот коллекция значений флажков:

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

Теперь у вас есть полностью динамический дизайн переключателей, управляемый данными и ориентированный на данные.

Вот как выглядит пример программы:

enter image description here

Текст под радио показывает выбранный в данный момент элемент. Хотя в этом примере я использовал строки, вы можете легко изменить дизайн, чтобы использовать значения enum или другие источники для описания переключателя.

1 голос
/ 19 мая 2011

Может быть, вы должны попробовать использовать привязку к словарю? (Или объекту с индексатором 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>
...