C# 在继续之前等待结果,并且不阻塞UI
我有一个C# 在继续之前等待结果,并且不阻塞UI,c#,multithreading,C#,Multithreading,我有一个TextBox,其中有一个TextChanged事件,如果TextBox的文本表示一个现有文件,它将调用一个自定义事件。在这种情况下,会调用对文件进行某些处理的外部dll,这可能需要一分钟以上的时间才能完成。根据这个方法返回给我的结果,我也会进行一些后处理。目前,这会阻塞我的UI,这是非常不受欢迎的 我看到基本上有两个“选项”//场景 在自定义事件中,在继续事件之前,以某种方式等待dll调用完成,同时保持UI空闲。这似乎是我未经训练的多线程处理中最简单的想法,但它在概念上也给我带来了危险
TextBox
,其中有一个TextChanged
事件,如果TextBox的文本表示一个现有文件,它将调用一个自定义事件。在这种情况下,会调用对文件进行某些处理的外部dll,这可能需要一分钟以上的时间才能完成。根据这个方法返回给我的结果,我也会进行一些后处理。目前,这会阻塞我的UI,这是非常不受欢迎的
我看到基本上有两个“选项”//场景
TextChanged
调用)在UI线程上,这可能吗Task.Run()
将整个自定义事件抛出到它自己的线程中。这里的缺点是,除了dll方法调用之外,在long方法之后还有相当多的UI元素受到getter/setter的影响。我可以根据所需的invokererequired
编写交替的getter/setter,但如果有更正确的方法,我宁愿采用这种方法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;
}