在类库上使用泛型方法对WinForm进行C#线程调用
您好,这是我的第一个问题,我会记住如何提出一个好问题的提示,但是如果我犯了错误(喜欢把这个问题提得太长!),请原谅 现在让我们谈谈我的奋斗历程,你可以在这篇文章的结尾找到我目前的处境和我正在努力做的事情 我正在制作自己的dll,当我第一次尝试使用线程方法时遇到了当前的问题:在类库上使用泛型方法对WinForm进行C#线程调用,c#,.net,multithreading,winforms,invoke,C#,.net,Multithreading,Winforms,Invoke,您好,这是我的第一个问题,我会记住如何提出一个好问题的提示,但是如果我犯了错误(喜欢把这个问题提得太长!),请原谅 现在让我们谈谈我的奋斗历程,你可以在这篇文章的结尾找到我目前的处境和我正在努力做的事情 我正在制作自己的dll,当我第一次尝试使用线程方法时遇到了当前的问题: public void DoThread(Action method, bool isBG = false) { Thread workerThread = new Thread(new Thread
public void DoThread(Action method, bool isBG = false)
{
Thread workerThread =
new Thread(new ThreadStart(method)) {
Name = method.Method.Name + "Thread",
IsBackground = isBG
};
workerThread.Start();
}
将更新主线程上WinForm的方法传递给它
当然,它不起作用
我问了谷歌老师,发现我必须使用调用
因此,为了了解一些信息,我使用了与以前相同的WinForm应用程序来执行以下代码:
ARThreads customThreads = new ARThreads();
public delegate void DelegateClass();
public DelegateClass delegateMethod;
private void Form1_Load(object sender, EventArgs e)
{
delegateMethod = new DelegateClass(ComboBox1);
customThreads.DoThread(ThreadFunction);
}
private void ComboBox1() => comboBox1.Items.Add("1");
private void ThreadFunction()
{
MyThreadClass myThreadClassObject = new MyThreadClass(this);
myThreadClassObject.Run();
}
public class MyThreadClass
{
Form1 myFormControl1;
public MyThreadClass(Form1 myForm) => myFormControl1 = myForm;
public void Run() => myFormControl1.Invoke(myFormControl1.delegateMethod);
}
取自stackoverflow答案(很抱歉,我无法再次找到源代码)
但是,正如我在标题中所说的,我希望我的代码使用泛型,所以这还不够好。所以我看了这些:
我学到了另一个新东西,那就是我必须运用反思:
所以我最终采用了这个方法:
public void DoInvoke<T>(T orignal, string methodName,
params object[] parameters) where T : new()
{
MethodInfo method = typeof(T).GetMethod(methodName);
if(method != null)
method.Invoke(orignal, parameters);
}
因为当我像那样使用我的DoInvoke
方法时,即使没有错误,WinForm上的组合框也不会更新
在我尝试调用时,我放弃了委托
部分,因为这两个部分都有效:
DoInvoke(this, "ComboBox1", null);
也因为这些方法不起作用,因为它们不是方法:
DoInvoke(this, "delegateMethod", null);
DoInvoke(this, "DelegateClass", null);
然后,由于DoInvoke
起作用,我开始尝试使用线程,首先是:
public void ThreadInvoke<T>(T original, string methodName, bool isBG = false,
params object[] parameters) where T : new()
{
Thread workerThread =
new Thread(() => DoInvoke(original, methodName, parameters)) {
Name = methodName + "ThreadInvoke",
IsBackground = isBG
};
workerThread.Start();
}
我也看到了:
但这并不是我真正想要的,因为它会变成这样:
1.创建一个新线程;
2.方法启动;
3.需要时,每个控件将调用一个调用
总之,我是否可以线程化并调用一个方法,以便它可以在需要时更新WinForm/MainThread的控件?或者我必须对该方法执行线程,并在该方法中调用每个特定控件的调用
附言:我真的希望答案不会像我的博文lol那样冗长让你的类库公开事件,然后让消费应用程序完成工作,如果在其中一个事件处理程序中,他们想回到UI线程上。这也有助于确保您的库是普遍适用的(从Winforms、WPF、Console、ASP.Net等,它们都有不同的规则)。此外,目前手动创建线程可能不是解决大多数情况的最佳方法。在大多数情况下,您可以使用Timer
s或来自其他系统的回调或事件,以便在有工作要做时运行代码,而不是在所有时间。请查看在创建它的线程上引发ProgressChanged事件的。或者传递一个线程可以调用以更新UI的命令。@Damien_the_Unsivers我将首先回答您关于最后一部分的问题:谢谢,从现在起我会记住这一点,但在我使用的WinForm示例中,这是关于使用sql server的默认数据设置各种控件的,之后就没有其他耗时的操作了。我只是想加快程序的安装速度,但发现了这个问题。至于第一部分,我将在尝试@Hyarus的建议的同时,看看能做些什么。@BlackRockShooter-因此,在2018年,默认设置应该是“我将使用异步库/方法进行I/O活动”。而不是“我将运行一个线程,然后将其大部分时间用于阻塞等待I/O的发生”。
public void ThreadInvoke<T>(T original, string methodName, bool isBG = false,
params object[] parameters) where T : new()
{
Thread workerThread =
new Thread(() => DoInvoke(original, methodName, parameters)) {
Name = methodName + "ThreadInvoke",
IsBackground = isBG
};
workerThread.Start();
}
public void ThreadInvoke<T>(T original, string methodName, bool isBG = false,
params object[] parameters) where T : new()
{
Type classType = original.GetType();
MethodInfo method = classType.GetMethod(methodName);
System.Threading.Thread workerThread =
new System.Threading.Thread(new System.Threading.ThreadStart (
delegate () { method.Invoke(original, parameters); })) {
Name = methodName + "ThreadInvoke",
IsBackground = isBG
};
workerThread.Start();
}
public void TaskInvoke<T>(T original, string methodName, bool isBG = false,
params object[] parameters) where T : new()
{
MethodInfo method = original.GetType().GetMethod(methodName,
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic
);
Task.Factory.StartNew(delegate () { method.Invoke(original, parameters); },
TaskCreationOptions.LongRunning);
}
SQLQueries customSQL = new SQLQueries();
ARThreads customThreads = new ARThreads();
private void Form1_Load(object sender, EventArgs e)
{
//Either this
customThreads.ThreadInvoke(this, "ComboBoxSetup", parameters: null);
//Or this
customThreads.TaskInvoke(this, "ComboBoxSetup", parameters: null);
//As long as it works
}
public void ComboBoxSetup()
{
//This is a method to make object arrays
//out of the result from a sql query
object[] first = customSQL.ObjectReader(
"select Column1, Column2 from TestTable order by Column1",
connectionString,
2
);
if(first != null)
comboBox1.Items.AddRange(first);
comboBox2.Items.Add("Test");
}