这是我在控件上调用的扩展方法:
public static void Invoke<T>(this T c, Action<System.Windows.Forms.Control> DoWhat)
where T:System.Windows.Forms.Control
{
if (c.InvokeRequired)
c.Invoke(o=> DoWhat(c) );
else
DoWhat(c);
}
ds
是强类型数据集。
这有效:
Action<DataGridView> a = row => row.DataSource = ds.bLog;
this.dataGridView1.Invoke(a);
这不编译:
this.dataGridView1.Invoke<DataGridView>(o => o.DataSource = ds.bLog);
并说System.Windows.Forms.Control不包含'DataSource'的定义......
我真的要把它分成两行吗? 为了清楚/安全,我应该调用通用扩展方法InvokeSafe吗?
编辑:修改了扩展方法(有效,但我想删除指定的委托要求):
private delegate void myDel();
public static void InvokeSafe<T>(this T c, Action<T> DoWhat) where T : Control
{
myDel d = delegate() { DoWhat(c); };
if (c.InvokeRequired)
c.Invoke(d);
else
DoWhat(c);
}
我似乎无法弄清楚如何将myDel
分解成块中的匿名委托?
答案 0 :(得分:4)
问题是您的行为仅在Control
中声明(在方法中)。将其更改为:
public static void Invoke<T>(this T c, Action<T> DoWhat)
where T:System.Windows.Forms.Control
{
if (c.InvokeRequired)
c.Invoke((EventHandler) delegate { DoWhat(c) } );
else
DoWhat(c);
}
这样编译器就会推断你想要一个Action<DataGridView>
,这样调用者中的lambda表达式就可以使用DataSource
。
答案 1 :(得分:2)
尝试将方法签名更改为:
public static void Invoke<T>(this T c, Action<T> DoWhat)
这会让您的Action
使用您指定的所需类型。
答案 2 :(得分:0)
为了进一步说明Jon Said,数据源不在System.Windows.Forms.Control上。数据源位于datagrid上。因此,如果您查看错误消息,您将看到它正在尝试在没有数据源的类型上设置数据源。做Jon建议应该解决问题。
答案 3 :(得分:0)
作品!
public static void InvokeSafe<T>(this T c, Action<T> DoWhat)
where T : System.Windows.Forms.Control
{
Action d = delegate() { DoWhat(c); };
if (c.InvokeRequired)
c.Invoke(d);
else
DoWhat(c);
}
此代码确实导致InvalidOperationException-跨线程操作无效:
List<customer> c=new List<customer>{new customer{ Name="test"},new customer{Name= "John doe"}};
Thread t = new Thread(o => this.dataGridView1.DataSource = c);
t.Start();
新的扩展方法没有!
List<customer> c=new List<customer>{new customer{ Name="test"},new customer{Name= "John doe"}};
Thread t = new Thread(o => this.dataGridView1.InvokeSafe(p => p.DataSource = c));
t.Start();