我正在尝试将两个布尔属性绑定到两个单选按钮。当表单加载时,两个单选按钮均处于未选中状态。当我单击第一个单选按钮时,它被选中。但是,当我尝试单击第二个单选按钮时,第一个单选按钮保持选中状态,第二个单选按钮仍未选中。如果我再次单击第二个单选按钮,两个单选按钮都将被取消选中。如果我再次单击第二个单选按钮,它将被选中。基本上,需要点击 3 次才能选中第二个单选按钮。如果我首先检查了第二个单选按钮,则同样适用于第一个单选按钮。
我有一个视图模型类:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace WinFormsApp1
{
internal class ViewModel : INotifyPropertyChanged
{
private bool _isCashPayment;
private bool _isChequePayment;
public bool IsCashPayment
{
get => _isCashPayment;
set
{
if (_isCashPayment == value)
{
return;
}
_isCashPayment = value;
// Notify the UI that the property has changed.
OnPropertyChanged();
}
}
public bool IsChequePayment
{
get => _isChequePayment;
set
{
if (_isChequePayment == value)
{
return;
}
_isChequePayment = value;
// Notify the UI that the property has changed.
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler? PropertyChanged;
// Notify the UI that one of the properties has changed.
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
表格代码:
namespace WinFormsApp1
{
public partial class Form7 : Form
{
private ViewModel _viewModel;
public Form7()
{
InitializeComponent();
_viewModel = new ViewModel();
}
private void Form7_Load(object sender, EventArgs e)
{
rdbCash.DataBindings.Add(nameof(rdbCash.Checked), _viewModel, nameof(_viewModel.IsCashPayment), false, DataSourceUpdateMode.OnPropertyChanged);
rdbCheque.DataBindings.Add(nameof(rdbCheque.Checked), _viewModel, nameof(_viewModel.IsChequePayment), false, DataSourceUpdateMode.OnPropertyChanged);
}
}
}
表单设计器生成的代码:
namespace WinFormsApp1
{
partial class Form7
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
rdbCash = new RadioButton();
rdbCheque = new RadioButton();
button1 = new Button();
SuspendLayout();
//
// rdbCash
//
rdbCash.AutoSize = true;
rdbCash.Location = new Point(20, 66);
rdbCash.Name = "rdbCash";
rdbCash.Size = new Size(51, 19);
rdbCash.TabIndex = 0;
rdbCash.Text = "Cash";
rdbCash.UseVisualStyleBackColor = true;
//
// rdbCheque
//
rdbCheque.AutoSize = true;
rdbCheque.Location = new Point(136, 66);
rdbCheque.Name = "rdbCheque";
rdbCheque.Size = new Size(66, 19);
rdbCheque.TabIndex = 1;
rdbCheque.Text = "Cheque";
rdbCheque.UseVisualStyleBackColor = true;
//
// button1
//
button1.Location = new Point(15, 28);
button1.Name = "button1";
button1.Size = new Size(75, 23);
button1.TabIndex = 2;
button1.Text = "button1";
button1.UseVisualStyleBackColor = true;
//
// Form7
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(button1);
Controls.Add(rdbCheque);
Controls.Add(rdbCash);
Name = "Form7";
Text = "Form7";
Load += Form7_Load;
ResumeLayout(false);
PerformLayout();
}
#endregion
private RadioButton rdbCash;
private RadioButton rdbCheque;
private Button button1;
}
}
我正在尝试使用数据绑定而不是传统的单选按钮检查事件处理程序。我期望单选按钮在单击时会更改其状态,并更改绑定属性的值。我尝试将两个单选按钮放在一个组框中,结果是相同的。 我观察到的是,当选择第一个单选按钮并单击第二个单选按钮时,首先调用绑定到第一个单选按钮的属性设置器并传递 false 值,然后调用绑定到第二个单选按钮的属性设置器。但是,设置器获取的是假值,而不是传递真值,因此,单击单选按钮时不会选中该单选按钮。
在 Jimi 和这篇文章的帮助下:MVVM radiobuttons,我终于在 Windows 窗体中使用了单选按钮双向数据绑定。
在 form.cs 文件中,我们创建一个 BindingSource 并使用它来绑定单选按钮。
private void Form7_Load(object sender, EventArgs e)
{
BindingSource rdBindingSource = new BindingSource(_viewModel, null);
rdbCash.DataBindings.Add(nameof(rdbCash.Checked), rdBindingSource, nameof(_viewModel.IsCashPayment), false, DataSourceUpdateMode.OnPropertyChanged);
rdbCheque.DataBindings.Add(nameof(rdbCheque.Checked), rdBindingSource, nameof(_viewModel.IsChequePayment), false, DataSourceUpdateMode.OnPropertyChanged);
}
在 ViewModel 中,我们定义一个枚举对象来保存单选按钮值。单选按钮绑定属性的设置器不会直接触发 PropertyChanged() 事件。相反,他们更改支付源属性,并且支付源属性仅在更改时才会触发 PropertyChanged() 事件。这里的关键点是,当单击单选按钮时,会发生两个事件:首先,先前选择的单选按钮会将状态更改为 false(未选中),其次当前选择的单选按钮会将状态更改为 true(选中)。 PropertyChanged() 事件应仅在第二个事件中触发。如果它在第一个事件中被触发,它会弄乱单选按钮的状态。第二个事件实际上会将单选按钮状态传递为 false(未选中)。
internal enum PaymentSource
{
None,
Cash,
Cheque
}
internal partial class ViewModel : INotifyPropertyChanged
{
private PaymentSource _paymentSource;
public bool IsCashPayment
{
get { return Source == PaymentSource.Cash; }
set
{
if (value && Source != PaymentSource.Cash)
{
Source = PaymentSource.Cash;
}
}
}
public bool IsChequePayment
{
get { return Source == PaymentSource.Cheque; }
set
{
if (value && Source != PaymentSource.Cheque)
{
Source = PaymentSource.Cheque;
}
}
}
public PaymentSource Source
{
get { return this._paymentSource; }
set
{
if (this._paymentSource == value)
return;
this._paymentSource = value;
OnPropertyChanged(nameof(IsCashPayment));
OnPropertyChanged(nameof(IsChequePayment));
}
}
public event PropertyChangedEventHandler? PropertyChanged;
// Notify the UI that one of the properties has changed.
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}