我有从两个不同视图监视的Process对象。 Windows.Forms.ListView(实际上是派生类)和图形查看器(基于Microsoft Research的自动图形布局)。每个都有一个上下文菜单,可以激活类似的事件。虽然列表视图可以有多个选择,但我不允许在图表视图中使用它。
这就是我目前所拥有的:
private void ctxgrphAddBreakpoint_Click(object sender, EventArgs e)
{
Process p = GetProcess(viewer);
if (p != null)
{
p.AddBreakpoint();
BeginRefresh(false, false);
}
}
private void ctxgrphRemoveBreakpoint_Click(object sender, EventArgs e)
{
Process p = GetProcess(viewer);
if (p != null)
{
p.RemoveBreakpoint();
BeginRefresh(false, false);
}
}
private void ctxlistAddBreakpoint_Click(object sender, EventArgs e)
{
foreach (Process p in lvwProcessList.SelectedProcesses())
{
p.AddBreakpoint();
}
BeginRefresh(false, false);
}
private void ctxlistRemoveBreakpoint_Click(object sender, EventArgs e)
{
foreach (Process p in lvwProcessList.SelectedProcesses())
{
p.RemoveBreakpoint();
}
BeginRefresh(false, false);
}
我想将两个上下文菜单统一为一个,将事件处理统一为:
private void ctxlistAction_Click(object sender, EventArgs e)
{
// I can unify the Viewer and ListView and implement some common interface,
// so I'm pretty sure I can handle this part
foreach (Process p in UIView.SelectedProcesses())
{
p.Action(); // What is the best way to handle this?
}
BeginRefresh(false, false);
}
我如何到达那里?
答案 0 :(得分:3)
访客模式?
答案 1 :(得分:2)
在* .Designer.cs文件中找到事件分配(... += new System.EventHandler(ctxlistAction_Click);
),并使它们指向同一个函数。
答案 2 :(得分:0)
你不能把发送者强制转换成你的界面吗?
private void ctxlistAction_Click(object sender, EventArgs e)
{
UIView view = sender as UIView;
if (view != null)
{
// I can unify the Viewer and ListView and implement some common interface,
// so I'm pretty sure I can handle this part
foreach (Process p in view.SelectedProcesses())
{
p.Action(); // What is the best way to handle this?
}
BeginRefresh(false, false);
}
}
答案 3 :(得分:0)
首先,尝试重构常用功能并使用委托 (请原谅我选择不好的名字,比如“DoListAction”):
readonly Action<Process> removeBreakpoint = p => p.RemoveBreakpoint();
readonly Action<Process> addBreakpoint = p => p.AddBreakpoint();
void DoSingleAction(Action<Process> action)
{
var p = GetProcess(viewer);
if(p != null)
{
action(p); //invokes the action
BeginRefresh(null,null);
}
}
void DoListAction(Action<Process> action)
{
lvwProcessList.ForEach(action);
BeginRefresh(false, false);
}
private void ctxgrphAddBreakpoint_Click(object sender, EventArgs e)
{
DoSingleAction(addBreakpoint);
}
private void ctxgrphRemoveBreakpoint_Click(object sender, EventArgs e)
{
DoSingleAction(removeBreakpoint);
}
private void ctxlistAddBreakpoint_Click(object sender, EventArgs e)
{
DoListAction(addBreakpoint);
}
private void ctxlistRemoveBreakpoint_Click(object sender, EventArgs e)
{
DoListAction(removeBreakpoint);
}
然后你可以统一DoProcessAction和DoListAction:
void DoAction(object sender, Action<Process>)
{
if(sender is ListView)
{
lvwProcessList.ForEach(action);
BeginRefresh(false, false);
}
else if (sender is GraphView)
{
var p = GetProcess(viewer);
if(p != null)
{
action(p); //invokes the action
BeginRefresh(null,null);
}
}
else {throw new Exception("sender is not ListView or GraphView");}
}
//and update all the handlers to use this, and delete DoSingleAction and DoListAction:
private void ctxgrphAddBreakpoint_Click(object sender, EventArgs e)
{
DoAction(sender, addBreakpoint);
}
//etc.
无论如何,在每个事件处理程序中,我认为你必须指定要采取的行动。在这种情况下,我不确定继承或扩展方法是否真的会成为你的朋友,但是这里使用扩展方法可能看起来如何:
//these two are in a separate static class
public static InvokeAction(this ListView listView, Action<Process> action)
{ ... }
public static InvokeAction(this GraphView listView, Action<Process> action)
{ ... }
private void handler(object sender, Action<Process> action)
{
var lv = sender as ListView;
var gv = sender as GraphVeiw;
lv.InvokeAction(action); //(need to check for null first)
gv.InvokeAction(action);
if(lv == null && gv == null) {throw new Exception("sender is not ListView or GraphView");}
}
//then update all the handlers:
private void ctxgrphAddBreakpoint_Click(object sender, EventArgs e)
{
handler(sender, addBreakpoint);
}
要在C#2(VS2005)中执行此操作,使用委托的第一种方法仍然有效,你就是不能拥有lambdas。 (2.0有Action<T>
代表)。只需将lambda更改为函数即可。其他一切都能正常运作。
void removeBreakpoint(Process p) { p.RemoveBreakpoint(); }
void addBreakpoint(Process p) { p.AddBreakpoint(); }
//you could also do this, but it's overkill:
readonly Action<Process> removeBreakpoint = delegate(Process p) { p.RemoveBreakpoint(); };
readonly Action<Process> addBreakpoint = delegate(Process p) { p.AddBreakpoint(); };