Как использовать привязку данных с помощью переключателей Windows Forms?

StackOverflow https://stackoverflow.com/questions/344964

Вопрос

В моей базе данных есть двоичное поле, которое сложно описать в пользовательском интерфейсе с помощью одного флажка типа «Is XXXX?».Я бы предпочел использовать пару переключателей (например,«Сделай это по-фу» и «Сделай по-барски»), но сейчас все остальные поля в моей форме привязаны к данным бизнес-объекта.Я также хотел бы привязать данные пары переключателей к бизнес-объекту, но пока не придумал хорошего способа сделать это.Я могу привязать одну из кнопок к полю, так что поле будет установлено «истина», если кнопка выбрана, но при выборе другой кнопки выбор первой будет отменен (то есть две переключатели правильно соединены в пару ), значение поля не обновляется, чтобы отразить это.

Я хотел бы иметь возможность сказать

button1.DataBindings.Add(new Binding("checked", source, "useFoo"));
button2.DataBindings.Add(new Binding("checked", source, "!useFoo"));

но я почти уверен, что это выдастся, когда запустится.Есть ли более простой способ, или мне просто следует больше подумать о том, как написать один флажок?Я не хочу добавлять дополнительные функции для обработки чего-то такого тривиального...

Расчетное время прибытия:Комментатор предложил рассмотреть раскрывающийся список (ComboBox).Я думал об этом, но как мне привязать это к логическому полю в базе данных/свойству в бизнес-объекте?Если я привяжу SelectedItem к свойству useFoo, что будет в коллекции Items?Придется ли мне добавить только «True» и «False», или я могу каким-то образом добавить объект пары ключ/значение, который связывает отображаемый элемент («Использовать Foo» / «Не использовать Foo») с логическим значением, стоящим за ним?У меня возникли проблемы с поиском документов по этому вопросу.


Об ответе:решение, которое я использовал, включало изменение бизнес-объекта - основная идея очень похожа на ту, которую опубликовал Гург, но я придумал ее отдельно, прежде чем прочитать его ответ.Короче говоря, я добавил отдельное свойство, которое просто возвращает !useFoo.Один переключатель привязан к source.UseFoo, а другой обязан source.UseBar (название нового объекта недвижимости).Важно убедиться, что новое свойство имеет как геттеры, так и сеттеры, иначе вы столкнетесь с действительно странным поведением.

Это было полезно?

Решение

Я нашел способ сделать это, используя DataSet / DataTable.

Я делаю вычисляемый столбец в DataTable с выражением IIF(Foo=true, false, true). Давайте назовем этот столбец Bar.

RadioButton.Checked имеет тип Boolean. Теперь вы можете привязать один Foo к <=> и один к <=>.

Чтобы <=> поставить / снять флажок для распространения обратно на <=>, необходимо перейти к сгенерированному коду DataTable и добавить одну строку, последнюю в этом примере:

[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public bool Bar {
    get {
        try {
            return ((bool)(this[this.tableradio.BarColumn]));
        }
        catch (global::System.InvalidCastException e) {
            throw new global::System.Data.StrongTypingException("The value for column \'Bar\' in table \'radio\' is DBNull.", e);
        }
    }
    set {
        this[this.tableradio.BarColumn] = value;
        this[this.tableradio.FooColumn] = !value;
    }
}

Другие советы

<Ол>
  • Свяжите RadioButton, который непосредственно связан с вашим логическим значением (т. е. проверяется, когда значение равно true).
  • Добавьте обработчик событий к событию CheckedChanged этого <=>, который выглядит следующим образом:

    private void radioButton_CheckedChanged(object sender, EventArgs e)
    {
        foreach (Binding b in ((Control)sender).DataBindings)
            b.WriteValue();
    }
    
  • Если ваш бизнес-объект реализует INotifyPropertyChanged (что делает привязку более удобной), вы можете добавить следующий код в визуальный интерфейс, где BO - это ваш бизнес-объект, и он объявлен как withevents, а BO.Value - это логическое свойство, которое вы хотели бы привязать к.

    Public Property NotValue() As Boolean
        Get
            Return Not BO.Value
        End Get
        Set(ByVal value As Boolean)
            BO.Value = Not value
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("NotValue"))
        End Set
    End Property
    
    
    Private Sub BO_PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Handles BO.PropertyChanged
        If e.PropertyName = "Value" Then
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("NotValue"))
        End If
    End Sub
    

    Следующие привязки подключат переключатели.

    RBTrue.DataBindings.Add(New Binding("Checked", Me.BO, "Value", False, DataSourceUpdateMode.OnPropertyChanged))
    RBFalse.DataBindings.Add(New Binding("Checked", Me, "NotValue", False, DataSourceUpdateMode.OnPropertyChanged))
    

    Визуальный интерфейс также должен реализовывать INotifyPropertyChanged. Этот метод работает в обоих направлениях: исходное значение обновляется при изменении интерфейса и при изменении исходного значения интерфейс будет обновляться правильно.

    Я столкнулся с той же проблемой и обнаружил, что это возможно при стандартной привязке данных:

    button1.DataBindings.Add(new Binding("checked", source, "useFoo", false, DataSourceUpdateMode.OnPropertyChanged);
    // no need to databind button 2, since button1.checked 
    // is set to false when button2 is checked
    

    По умолчанию DataSourceUpdateMode установлено на OnValidation. Если для него установлено значение OnPropertyChanged, изменение немедленно распространяется на объект с привязкой к данным.

    Мой бизнес-объект реализует INotifyPropertyChanged;

    Протестировав это решение, я обнаружил, что мое button2 событие было запущено дважды, когда я нажимал <=>. Чтобы предотвратить это, просто установите

    button1.CausesValidation = false;
    button2.CausesValidation = false;
    

    как показано здесь: Отключение TextBox приводит к двойному запуску PropertyChanged

    Сделайте это вручную в коде.Когда вы загружаете форму, установите переключатели в соответствии с вашей базой данных.Когда вы нажимаете кнопку «Сохранить», сохраните состояние по своему желанию.В этом примере радиостанции сохраняются в базе данных как битовые поля.

            // Load radio state
            radioButton1.Checked = ((myModel)myBindingSource.DataSource).boolOption1;
            radioButton2.Checked = ((myModel)myBindingSource.DataSource).boolOption2;
    

    -

            // Save radio state
            ((myModel)myBindingSource.DataSource).boolOption1 = radioButton1.Checked;
            ((myModel)myBindingSource.DataSource).boolOption2 = radioButton2.Checked;
    

    Я пытался перетащить элементы из панели «Источники данных» в Visual Studio 2015, когда определил свои переключатели как логические значения в таблице, но возникли проблемы с тем, что логические значения не обновляются до значения false при выборе другого переключателя.При изменении «causesValidation» на ложные переключатели автоматически снимаются при переходе между другими полями ввода текста.

    Вам следует привязывать только один из элементов управления, если вы уверены, что они находятся в одной группе.

    Вы также можете рассмотреть DropDown.

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top