Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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
C# 在继续之前等待结果,并且不阻塞UI_C#_Multithreading - Fatal编程技术网

C# 在继续之前等待结果,并且不阻塞UI

C# 在继续之前等待结果,并且不阻塞UI,c#,multithreading,C#,Multithreading,我有一个TextBox,其中有一个TextChanged事件,如果TextBox的文本表示一个现有文件,它将调用一个自定义事件。在这种情况下,会调用对文件进行某些处理的外部dll,这可能需要一分钟以上的时间才能完成。根据这个方法返回给我的结果,我也会进行一些后处理。目前,这会阻塞我的UI,这是非常不受欢迎的 我看到基本上有两个“选项”//场景 在自定义事件中,在继续事件之前,以某种方式等待dll调用完成,同时保持UI空闲。这似乎是我未经训练的多线程处理中最简单的想法,但它在概念上也给我带来了危险

我有一个
TextBox
,其中有一个
TextChanged
事件,如果TextBox的文本表示一个现有文件,它将调用一个自定义事件。在这种情况下,会调用对文件进行某些处理的外部dll,这可能需要一分钟以上的时间才能完成。根据这个方法返回给我的结果,我也会进行一些后处理。目前,这会阻塞我的UI,这是非常不受欢迎的

我看到基本上有两个“选项”//场景

  • 在自定义事件中,在继续事件之前,以某种方式等待dll调用完成,同时保持UI空闲。这似乎是我未经训练的多线程处理中最简单的想法,但它在概念上也给我带来了危险:如果自定义事件本身(从
    TextChanged
    调用)在UI线程上,这可能吗
  • 使用
    Task.Run()
    将整个自定义事件抛出到它自己的线程中。这里的缺点是,除了dll方法调用之外,在long方法之后还有相当多的UI元素受到getter/setter的影响。我可以根据所需的
    invokererequired
    编写交替的getter/setter,但如果有更正确的方法,我宁愿采用这种方法
  • 我使用上面的选项2制作了一个更短(尽管是人为设计的)的示例项目,它基本上显示了我所追求的:

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
    
            comboBox1.Items.Add("Select One...");
            comboBox1.Items.Add("Item 1");
            comboBox1.Items.Add("Item 2");
    
            Value = 0;
        }
    
        public string SetMessage
        {
            set
            {
                if (lblInfo.InvokeRequired)
                    lblInfo.BeginInvoke((MethodInvoker)delegate () { lblInfo.Text = Important ? value + "!" : value; });
                else
                    lblInfo.Text = Important ? value + "!" : value;
            }
        }
    
        public bool Important
        {
            get
            {
                return chkImportant.Checked;
            }
            set
            {
                if (chkImportant.InvokeRequired)
                    chkImportant.BeginInvoke((MethodInvoker) delegate() { chkImportant.Checked = value; });
                else
                    chkImportant.Checked = value;
            }
        }
    
        public SomeValue Value
        {
            get
            {
                if (comboBox1.InvokeRequired)
                {
                    SomeValue v = (SomeValue)comboBox1.Invoke(new Func<SomeValue>(() => SomeValue.Bar));
                    return v;
                }
                else
                {
                    switch (comboBox1.SelectedIndex)
                    {
                        case 1:
                            return SomeValue.Foo;
                        case 2:
                            return SomeValue.Bar;
                        default:
                            return SomeValue.Nothing;
                    }
                }
            }
            set
            {
                if (comboBox1.InvokeRequired)
                {
                    comboBox1.BeginInvoke((MethodInvoker)delegate ()
                    {
                       switch (value)
                       {
                           case SomeValue.Nothing:
                               comboBox1.SelectedIndex = 0;
                               break;
                           case SomeValue.Foo:
                               comboBox1.SelectedIndex = 1;
                               break;
                           case SomeValue.Bar:
                               comboBox1.SelectedIndex = 2;
                               break;
                       }
                    });
                }
                else
                {
                    switch (value)
                    {
                        case SomeValue.Nothing:
                            comboBox1.SelectedIndex = 0;
                            break;
                        case SomeValue.Foo:
                            comboBox1.SelectedIndex = 1;
                            break;
                        case SomeValue.Bar:
                            comboBox1.SelectedIndex = 2;
                            break;
                    }
                }
            }
        }
    
        private void CustomEvent(object sender, EventArgs e)
        {
            if (!Important)
                Important = true;
    
            SetMessage = "Doing some stuff";
    
            if (Value == SomeValue.Foo)
                Debug.WriteLine("Foo selected");
    
            //I don't want to continue until a result is returned, 
            //but I don't want to block UI either.
            if (ReturnsTrueEventually())
            {
    
                Debug.WriteLine("True!");
            }
    
            Important = false;
            SetMessage = "Finished.";
        }
    
        public bool ReturnsTrueEventually()
        {
            //Simulates some long running method call in a dll.
            //In reality, I would interpret an integer and return 
            //an appropriate T/F value based on it.
            Thread.Sleep(5000);
    
            return true;
        }
    
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            //Do I *need* to multithread the whole thing?
            Task.Run(() => CustomEvent(this, new EventArgs()));
        }
    }
    
    public enum SomeValue
    {
        Nothing = 0,
        Foo = 100,
        Bar = 200
    }
    
    公共部分类表单1:表单
    {
    公共表格1()
    {
    初始化组件();
    comboBox1.Items.Add(“选择一个…”);
    comboBox1.项目。添加(“项目1”);
    组合框1.项目。添加(“项目2”);
    数值=0;
    }
    公共字符串设置消息
    {
    设置
    {
    if(lblInfo.invokererequired)
    lblInfo.BeginInvoke((MethodInvoker)委托(){lblInfo.Text=Important?value+“!”:value;});
    其他的
    lblInfo.Text=重要?值+“!”:值;
    }
    }
    公共事业很重要
    {
    得到
    {
    返回chkImportant.Checked;
    }
    设置
    {
    if(chkImportant.invokererequired)
    chkImportant.BeginInvoke((MethodInvoker)委托(){chkImportant.Checked=value;});
    其他的
    chkImportant.Checked=值;
    }
    }
    公共价值
    {
    得到
    {
    如果(comboBox1.InvokeRequired)
    {
    SomeValue v=(SomeValue)comboBox1.Invoke(newfunc(()=>SomeValue.Bar));
    返回v;
    }
    其他的
    {
    开关(comboBox1.SelectedIndex)
    {
    案例1:
    返回SomeValue.Foo;
    案例2:
    返回SomeValue.Bar;
    违约:
    返回一些值,什么也没有;
    }
    }
    }
    设置
    {
    如果(comboBox1.InvokeRequired)
    {
    comboBox1.BeginInvoke((MethodInvoker)委托()
    {
    开关(值)
    {
    case SomeValue.Nothing:
    comboBox1.SelectedIndex=0;
    打破
    case SomeValue.Foo:
    comboBox1.SelectedIndex=1;
    打破
    case SomeValue.Bar:
    comboBox1.SelectedIndex=2;
    打破
    }
    });
    }
    其他的
    {
    开关(值)
    {
    case SomeValue.Nothing:
    comboBox1.SelectedIndex=0;
    打破
    case SomeValue.Foo:
    comboBox1.SelectedIndex=1;
    打破
    case SomeValue.Bar:
    comboBox1.SelectedIndex=2;
    打破
    }
    }
    }
    }
    私有void CustomEvent(对象发送方,EventArgs e)
    {
    如果(!重要)
    重要=正确;
    SetMessage=“正在做一些事情”;
    if(Value==SomeValue.Foo)
    Debug.WriteLine(“Foo selected”);
    //在返回结果之前,我不想继续,
    //但我也不想阻止UI。
    if(ReturnsTrueEventually())
    {
    Debug.WriteLine(“True!”);
    }
    重要=错误;
    SetMessage=“已完成。”;
    }
    公共布尔返回结构最终()
    {
    //在dll中模拟一些长时间运行的方法调用。
    //实际上,我会解释一个整数并返回
    //在此基础上选择合适的T/F值。
    睡眠(5000);
    返回true;
    }
    私有void textBox1\u TextChanged(对象发送方,事件参数e)
    {
    //我需要对整个事情进行多线程处理吗?
    运行(()=>CustomEvent(这个,新的EventArgs());
    }
    }
    公共枚举值
    {
    零=0,
    Foo=100,
    巴=200
    }
    
    注意:我没有要求对我的选项2代码进行代码审查。相反,我要问的是,选项2是否需要完成,因为该选项会导致我更改相当大的代码部分,因为其中只有1个方法可以完成整个过程

    我还意识到我可以简化这些属性中的一些代码以防止复制。为了向自己演示和调试,我现在暂缓

    下面是我与选项1相关的内容(省略了重复代码和没有调用的getter/setter):

    private async void CustomEvent(对象发送方,EventArgs e)
    {
    如果(!重要)
    重要=正确;
    设置消息=”
    
    private async void CustomEvent(object sender, EventArgs e)
    {
        if (!Important)
            Important = true;
    
        SetMessage = "Doing some stuff";
    
        if (Value == SomeValue.Foo)
            Debug.WriteLine("Foo selected");
    
        //I don't want to continue until a result is returned, 
        //but I don't want to block UI either.
        if (await ReturnsTrueEventually())
        {
    
            Debug.WriteLine("True!");
        }
    
        Important = false;
        SetMessage = "Finished.";
    }
    
    public async Task<bool> ReturnsTrueEventually()
    {
        //Simulates some long running method call in a dll.
        //In reality, I would interpret an integer and 
        //return an appropriate T/F value based on it.
        Thread.Sleep(5000);
    
        return true;
    }
    
        private async void buttonProcess_Click(object sender, RoutedEventArgs e)
        {
             textBlockStatus.Text = "Processing...";
             bool processed = await Task.Run(() => SlowRunningTask());
        }
    
        private bool SlowRunningTask()
        {
            Thread.Sleep(5000);
            return true;
        }