c# - 在后台操作任务并使用另一个类的控制元素
问题描述
基本上我想实现一个相当简单的事情。我有一个C#
wpf
-Application,在一个类中(在这里main
)我有几个控制元素。(按钮,文本框,...)
现在我执行一个方法(这里是 的构造函数main
)。在这个方法中,我想从不同的类中调用另一个方法(这里是 method SomeFunction()
)。现在这个方法有两个条件:
- 它应该在后台工作,因此 GUI 仍然可用(四处移动、单击按钮等)
- 它实际上需要来自 GUI 的控制元素的输入(位于
main
)
在搜索了互联网之后,我对第一个要求的想法是使用Task
.
实际上这工作得很好,但我还必须使用Dispatcher
, 才不会遇到错误:
System.InvalidOperationException:调用线程无法访问此对象,因为不同的线程拥有它
但是,通过使用Dispatcher
,GUI 再次被阻止并且不再可用。
有什么办法可以同时满足顶层的两个要求吗?
主类看起来像这样:
public class Main
{
public Main()
{
// This class has buttons, textboxes, labels, etc.
InitializeComponent();
Task.Run(() => // Task is needed to do work in background (GUI is not blocked)
{
Dispatcher.Invoke(() => // Dispatcher is needed to avoid "System.InvalidOperationException"
{
// Initialize a new object with this class as parameter
OtherClass otherObject = new OtherClass(this);
// Now call a method from another class
otherObject = new OtherClass(this);
});
});
}
}
另一个类是这样的:
public class OtherClass
{
public SomeFunction(Main main)
{
// Pretty hard work here to do ...
string test = main.textbox.Text;
}
}
解决方案
尝试这样的事情
public void DoSomething()
{
Task.Run(() =>
{
BackgroundProcess();
});
}
private void BackgroundProcess()
{
string ControlValue;
Application.Current.Dispatcher.Invoke(() =>
{
ControlValue = textBox.Text;
});
ControlValue += ControlValue;
Application.Current.Dispatcher.Invoke(() =>
{
textBox.Text = ControlValue;
});
}
我正在做的只是在绝对必要时访问控件,并在调度程序中执行此操作。其他一切都在后台线程中完成。只要您为此只做几个条目,它就不会阻塞调度程序。
我有一个地方可以使用 TextBox.AppendText 和 TextBox.ScrollToEnd 将进程的进度记录到文本框中,这似乎不会影响 UI。所以关键是使用控件做最少的工作。如果您正在等待输入,那么您应该使用 MVVM 和 DataBinding,以便在值更改时启动流程的相关部分。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualBasic;
public class MVVMExampleViewModel : System.ComponentModel.INotifyPropertyChanged
{
private string _MajorChange;
public string MajorChange
{
get
{
return _MajorChange;
}
set
{
_MajorChange = value;
DoPropertyChanged("MajorChange");
-- Start process using value here
}
}
private void DoPropertyChanged(string propertyname)
{
PropertyChanged(me, New PropertyChangedEventArgs(propertyname));
}
public event PropertyChangedEventHandler PropertyChanged;
}
WPF 用法
<Grid DataContext="{Binding CurrentMVVMExample}"
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Label Content="{DynamicResource NewItemMessage}" Visibility="{Binding IsDetached, Converter={StaticResource BooleanToVisibilityConverter}, Mode=OneWay}" Foreground="#FFBD0000" RenderTransform="{DynamicResource NewItemMessageLocation}"/>
<Label Content="Status" Grid.Column="0" Grid.Row="1" />
<TextBox Text="{Binding MajorChange, Delay=500, UpdateSourceTrigger=PropertyChanged}"
Grid.Column="1" Grid.Row="1" Width="{DynamicResource SectionFieldWidth}" />
</Grid>
推荐阅读
- c - 如何在 _start 中使用 argv?
- c# - 来自 API 的 JsonConvert.DeserializeObject 对象,使用 Webclient 可能是 2 种对象类型之一
- python - 如何让程序在 Python 中完成后重新运行
- html - 全新的 CSS,无法弄清楚如何为我的每个 html 段落正确编码不同的类/属性值
- django-rest-framework - 类型错误:+= 不支持的操作数类型:“datetime.timedelta”和“NoneType”
- html - 如何使 html 灯箱响应?
- google-apps-script - Google脚本仅使用值和格式复制工作表
- html - 如何在引导程序 4 中创建响应式布局
- git - 推送到 GitHub 时远程挂断
- javascript - 如何在不使用 setTimeout 的情况下这样做?