在.NET 4.5中使用c#和winforms我想鏈接菜單項的Checked
屬性和窗體的Visible
屬性。有沒有簡單的方法將兩個對象屬性鏈接在一起?
更改這兩個屬性中的任何一個都會改變另一個來保持它們的同步。
有沒有一個簡單而優雅的解決方案呢?
在.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
現在這不是一個選項。 –