有没有简单的方法将两个对象属性链接在一起?
在.NET 4.5中使用c#和winforms我想链接菜单项的Checked
属性和窗体的Visible
属性。有没有简单的方法将两个对象属性链接在一起?
更改这两个属性中的任何一个都会改变另一个来保持它们的同步。
有没有一个简单而优雅的解决方案呢?
像这样例如用一个复选框和一个按钮:
线到的CheckedChanged事件
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
var checkBox = sender as CheckBox;
button1.Visible = !checkBox.Checked;
}
编辑:
好,我误解。
虽然'farid'的解决方案是一个清晰的解决方案,使用视图模型和模型分离问题,但它也增加了应用程序的复杂性。
如果您不想使用此mvvm模式并将逻辑放在后面的代码中,可以将INotifyPropertyChanged接口实现为具有可见属性的窗体(或添加自定义事件),请添加新的Visible属性它设置base.visible属性(由Control类继承)并引发PropertyChanged事件。在包含菜单项的表单中,可以连接到事件并执行必要的逻辑来设置选中状态或执行其他操作。
下面是一个例子:
Form1的代码背后:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += new System.EventHandler(this.Form1_Load);
}
private Form2 _frm2;
private void Form1_Load(object sender, EventArgs e)
{
_frm2 = new Form2();
_frm2.MdiParent = this;
_frm2.PropertyChanged += _frm2_PropertyChanged;
_frm2.Show();
}
void _frm2_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Visible")
{
showToolStripMenuItem.Checked = _frm2.Visible;
}
}
private void showToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
{
var menuItem = sender as ToolStripMenuItem;
if (_frm2 != null)
_frm2.Visible = menuItem.Checked;
}
}
Form2的代码背后:
public partial class Form2 : Form, INotifyPropertyChanged
{
public Form2()
{
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
public new bool Visible
{
get
{
return base.Visible;
}
set
{
base.Visible = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Visible"));
}
}
private void hideButton_Click(object sender, EventArgs e)
{
Visible = false;
}
}
这是不够的,因为如果Visible属性发生更改,它将不会更新菜单项的Checked属性。 –
您可以使用Windows Forms Data Bindings。
每个窗体窗体控件都有一个DataBindings
属性,可用于将给定数据源中的属性绑定到某个控件属性。
你可以组织你的代码像下面的例子:
这个例子显示了从ViewModel
对象控件属性绑定。在您的具体情况下,您可以将ViewModel
属性绑定到两个控件属性。
public partial class StackOverflowForm : Form
{
public ViewModel Model { get; set; }
public Dictionary<string, Control> BindableControls { get; set; }
public StackOverflowForm()
{
Model = new ViewModel();
Model.PropertyChanged += Model_PropertyChanged;
BindableControls = new Dictionary<string, Control>();
Model.Visible = false;
InitializeComponent();
RegisterBinding(boundButton, "Visible", Model, "Visible");
}
void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
foreach (var item in BindableControls)
{
NotifyChange(item.Value, e.PropertyName);
}
}
private void NotifyChange(Control control, string propertyName)
{
button1.DataBindings[propertyName].ReadValue();
}
private void RegisterBinding(Control control, string controlPropertyName, ViewModel _model, string modelPropertyName)
{
control.DataBindings.Add(controlPropertyName, _model, modelPropertyName, true, DataSourceUpdateMode.OnPropertyChanged);
BindableControls[control.Name] = control;
}
private void SetPropertyButton_Click(object sender, EventArgs e)
{
Model.Visible = true;
}
}
public class ViewModel : INotifyPropertyChanged
{
private bool _IsVisible;
public bool Visible
{
get
{
return _IsVisible;
}
set
{
_IsVisible = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Visible"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
我已经定义在形式的视图模型对象,用作对照的结合数据源。 (即具有可见性属性)
private void RegisterBinding(Control control, string controlPropertyName, ViewModel _model, string modelPropertyName)
{
control.DataBindings.Add(controlPropertyName, _model, modelPropertyName, true, DataSourceUpdateMode.OnPropertyChanged);
BindableControls[control.Name] = control;
}
使用RegisterBinding
方法注册简单结合(参数足够简单)。
'ViewModel'类在System.ComponentModel
中执行INotifyPropertyChanged
接口。当ViewModel中的任何属性发生变化时,此接口将添加一个PropertyChanged
事件以供调用。
在窗体的构造函数中,我添加了事件侦听器到PropertyChanged
事件ViewModel
在侦听器中,我强制绑定为每个绑定注册的控件读取新值。这部分代码刷新是绑定控件,并更改按钮的可见状态。
NOTE:为了回答简单问题,我假设ViewModel
中绑定到控件属性的属性在窗体控件中具有与目标属性相同的名称。 (Mode.Visible和boundButton.Visible)。如果你想实现源和目标属性的属性名称映射,你可以使用Dictionary
或其他来实现这个功能。
这是一个看似复杂的解决方案,并不是很高雅。但它会工作:-) –
考虑使用WPF。 – SLaks
现在这不是一个选项。 –