Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/271.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在类库上使用泛型方法对WinForm进行C#线程调用_C#_.net_Multithreading_Winforms_Invoke - Fatal编程技术网

在类库上使用泛型方法对WinForm进行C#线程调用

在类库上使用泛型方法对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

您好,这是我的第一个问题,我会记住如何提出一个好问题的提示,但是如果我犯了错误(喜欢把这个问题提得太长!),请原谅

现在让我们谈谈我的奋斗历程,你可以在这篇文章的结尾找到我目前的处境和我正在努力做的事情

我正在制作自己的dll,当我第一次尝试使用线程方法时遇到了当前的问题:

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");
}