我正在学习Windows窗体中的MDI表单,我正在使用这个简单的应用程序:
每个ToolStripMeniItem
调用特定表单的单个实例,但正如您所看到的(请参阅我的代码),我的代码对于每个ToolStripMeniItem都是重复的,我该如何缩短它?
public static Form IsFormAlreadyOpen(Type FormType)
{
foreach (Form OpenForm in Application.OpenForms)
{
if (OpenForm.GetType() == FormType)
return OpenForm;
}
return null;
}
private void form1ToolStripMenuItem_Click(object sender, EventArgs e)
{
Form1 f1 = null;
if (IsFormAlreadyOpen(typeof(Form1)) == null)
{
f1 = new Form1();
f1.MdiParent = this;
f1.Show();
}
else
{
Form selectedForm = IsFormAlreadyOpen(typeof(Form1));
foreach (Form OpenForm in this.MdiChildren)
{
if (OpenForm == selectedForm)
{
if (selectedForm.WindowState == FormWindowState.Minimized)
{
selectedForm.WindowState = FormWindowState.Normal;
}
selectedForm.Select();
}
}
}
}
private void form2ToolStripMenuItem_Click(object sender, EventArgs e)
{
Form2 f2 = null;
if (IsFormAlreadyOpen(typeof(Form2)) == null)
{
f2 = new Form2();
f2.MdiParent = this;
f2.Show();
}
else
{
Form selectedForm = IsFormAlreadyOpen(typeof(Form2));
foreach (Form OpenForm in this.MdiChildren)
{
if (OpenForm == selectedForm)
{
if (selectedForm.WindowState == FormWindowState.Minimized)
{
selectedForm.WindowState = FormWindowState.Normal;
}
selectedForm.Select();
}
}
}
// and so on... for the other ToolStripMeniItem
}
答案 0 :(得分:5)
A generic function是一个函数,它将使用一组将由调用者定义的类型
所以代替
int doubleIt(int a) { return a*2; }
你可以说
T doubleIt<T>(T a){ return a*2; }
这意味着您可以定义一个可以像这样调用的函数:
int intResult = doubleIt(...pass in a int..);
double doubleResult = doubleIt(...pass in a double..);
float floatResult = doubleIt(...pass in a float..);
因此,对于您的代码,您创建了一个方法,该方法将您创建的表单类型作为T的值。
但是编译器不知道T是一个表单并且你可以在其上调用new,所以你必须将可以作为T传递的类型与where子句相提并论T表示必须是一个表单,必须是您可以访问的构造函数
因此,您可以使用专用于您需要的f1类型的通用函数替换核心功能。
因此,您可以使用Form f1 = null;
T f1 = null;
private void ClickEvent<T>(object sender, EventArgs e) where T: Form, new() {
T f1 = null;
.
.
.
}
然后从真实的事件处理程序中调用此方法
private void form1ToolStripMenuItem_Click(object sender, EventArgs e) {
ClickEvent<Form1>(sender, e)
}
private void form2ToolStripMenuItem_Click(object sender, EventArgs e) {
ClickEvent<Form1>(sender, e)
}
所以你最终得到的结果是:
public static Form IsFormAlreadyOpen(Type FormType)
{
foreach (Form OpenForm in Application.OpenForms)
{
if (OpenForm.GetType() == FormType)
return OpenForm;
}
return null;
}
private void ClickEvent<T>(object sender, EventArgs e) where T: Form, new()
{
T f1 = null;
if (IsFormAlreadyOpen(typeof(T)) == null)
{
f1 = new T();
f1.MdiParent = this;
f1.Show();
}
else
{
Form selectedForm = IsFormAlreadyOpen(typeof(T));
foreach (Form OpenForm in this.MdiChildren)
{
if (OpenForm == selectedForm)
{
if (selectedForm.WindowState == FormWindowState.Minimized)
{
selectedForm.WindowState = FormWindowState.Normal;
}
selectedForm.Select();
}
}
}
}
private void form1ToolStripMenuItem_Click(object sender, EventArgs e) {
ClickEvent<Form1>(sender, e)
}
private void form2ToolStripMenuItem_Click(object sender, EventArgs e) {
ClickEvent<Form1>(sender, e)
}
额外:如果你可以使用Linq,那就是这样的。
using System.Linq;
public static Form IsFormAlreadyOpen(Type FormType) {
return Application.OpenForms.Where( f => f.GetType() == FormType).FirstOrDefault();
}
private void ClickEvent<T>(object sender, EventArgs e) where T: Form, new()
{
T selectedForm = IsFormAlreadyOpen(typeof(T);
if (selectedForm == null) {
(new T() { MdiParent = this; }).Show()
}
else {
this.MdiChildren.Where(o => o == selectedForm).ForEach(
openForm => {
selectedForm.WindowState = (selectedForm.WindowState == FormWindowState.Minimized) ? FormWindowState.Normal : selectedForm.WindowState;
openForm.Select();
}
);
}
}
private void form1ToolStripMenuItem_Click(object sender, EventArgs e) {
ClickEvent<Form1>(sender, e)
}
private void form2ToolStripMenuItem_Click(object sender, EventArgs e) {
ClickEvent<Form2>(sender, e)
}
您可以采取其他措施来缩短此代码,但使用泛型和linq将是最有效的。
答案 1 :(得分:2)
可能更容易使用MenuItem类的'标记'属性并使用它,并动态构建菜单项,将其添加到MenuStrip中,并使用单个Click事件处理程序< strong> 所有 菜单项,然后是找出使用了哪个标签的问题,例如你可以将标签设置为这样的表格
menuItem = new MenuItem("Form 1");
menuItem.Tag = Form1;
menuItem.Click += new EventHandler(frmMDI_FormHandler_Click);
frmMDI.MenuStrip.Add(menuItem);
答案 2 :(得分:2)
我在考虑将通用功能分解为通用方法。它确实使用了泛型和Activator.CreateInstance
,但除此之外,下面的代码几乎都是OP的代码,只是重构了。
private void form1ToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenForm<Form2>();
}
private void OpenForm<T>() where T : Form
{
T form = null;
if (IsFormAlreadyOpen(typeof(T)) == null)
{
form = Activator.CreateInstance<T>();
form.MdiParent = this;
form.Show();
}
else
{
Form selectedForm = IsFormAlreadyOpen(typeof(T));
foreach (Form OpenForm in this.MdiChildren)
{
if (OpenForm == selectedForm)
{
if (selectedForm.WindowState == FormWindowState.Minimized)
{
selectedForm.WindowState = FormWindowState.Normal;
}
selectedForm.Select();
}
}
}
}
答案 3 :(得分:0)
hackish缩短这段代码的方法(我不认为这就是你的意思:p)
另请注意:“IsXYZ(val)”意味着布尔反应......想一想。尝试“GetOpenForm(Type FormType)”
public static Form IsFormOpen(Type FormType) {
foreach (Form OpenForm in Application.OpenForms)
if (OpenForm.GetType() == FormType)
return OpenForm;
return null;
}
请注意,它有助于定义“缩短代码”...您只是意味着重复为新案例生成新代码所需的击键吗?
另外,请注意,结合Preet和Tommie的答案,您可以查看sender
并获取调用方法的类型,从而允许您在那里自定义逻辑。按类型检查每个表单的时髦逻辑是导致代码看起来过于复杂的原因。如果有另一种方法来识别打开的窗口,那可能会对你有利。