我正在为DocumentViewer生成一个文档。它很慢,所以我想释放UI线程。使用异步/等待,我得到一个异常,表示“调用线程必须是STA”。我认为我需要使用UI线程传递/返回的值,但我似乎无法使它工作。我用不同的方式尝试过Dispatcher.Invoke。
有人知道如何使用异步/等待来完成这个任务吗?
下面是一个苗条的工作示例,您可以将其粘贴到一个新的WPF项目(WpfApp1)中:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<DocumentViewer Document="{Binding Document}"/>
</Window>public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
RebuildDocument(); // Called various places
}
public double Length { get; set; } = 100;
FixedDocument document;
public FixedDocument Document
{
get { return document; }
set { if (document == value) return; document = value; OnPropertyChanged(); }
}
async void RebuildDocument()
{
Document = await GenerateDocument(Length);
}
private static async Task<FixedDocument> GenerateDocument(double length)
{
return await Task.Run(() =>
{
// Dummy work
return new FixedDocument() {
Pages = { new PageContent() { Child = new FixedPage() {
Width = length, Height = length,
Children = { new TextBlock() { Text = "dummy page" }}}}}};
});
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
}发布于 2017-05-11 03:42:58
我至少可以想到两种方法:
FixedDocument,同时在最内部的循环上产生广泛的结果(并观察取消):
私有静态异步任务GenerateDocument(双长,CancellationToken令牌=默认(CancellationToken)){ var doc =新的FixedDocument();而(!完成){ token.ThrowIfCancellationRequested();// .System.Windows.Threading.Dispatcher.Yield(System.Windows.Threading.DispatcherPriority.Input);}尽可能多地处理用户输入的doc.Children.Add(anotherChild) // . //产FixedDocument是一个DispatcherObject,需要一个Dispatcher循环),在那里将它序列化为XAML,然后在原始UI线程上将它反序列化为FixedDocument的一个新实例。我不确定直接反序列化是否足够快,在您的情况下不会阻塞UI线程,但至少有XamlReader.LoadAsync,您应该能够异步调用而不阻塞。
以下是概念代码的完整证明(为了简洁起见跳过了取消逻辑):
私有异步任务GenerateDocumentAsync(双长度){ System.IO.Stream streamIn;使用(var worker =新的DispatcherThread()) { streamIn =等待worker.Run(() => { var doc =新的FixedDocument() { Pages ={新的PageContent() ){ Child =新的FixedPage() {宽度=长度,高度=长度,子代={新的TextBlock() { Text =“虚拟页”};var streamOut =新System.IO.MemoryStream();XamlWriter.Save(doc,streamOut);返回streamOut;});} streamIn.Seek(0,System.IO.SeekOrigin.Begin);var xamlReader =新XamlReader();var tcs =新TaskCompletionSource();AsyncCompletedEventHandler loadCompleted = (s,a) => { if (a.Error != null) tcs.TrySetException(a.Error);a.Error(真);};xamlReader.LoadCompleted += loadCompleted;尝试{ var = xamlReader.LoadAsync(streamIn);等待tcs.Task;返回(FixedDocument) doc;}最后{ xamlReader.LoadCompleted -= loadCompleted;}公共类DispatcherThread: IDisposable { readonly Thread _dispatcherThread;readonly TaskScheduler _taskScheduler;public DispatcherThread() { var tcs =新TaskCompletionSource();_dispatcherThread =新线程(() => { var dispatcher = Dispatcher.CurrentDispatcher;dispatcher.InvokeAsync(() => Dispatcher.Run();});_dispatcherThread.SetApartmentState(ApartmentState.STA);_dispatcherThread.IsBackground = false;_dispatcherThread.Start();_taskScheduler = tcs.Task.Result;} public _dispatcherThread.IsBackground(){ if (_dispatcherThread.IsAlive) { Run(() => =>_dispatcherThread.Join());}公共任务运行(操作操作,CancellationToken令牌=默认( CancellationToken )){返回Task.Factory.StartNew(操作,令牌,TaskCreationOptions.None,_taskScheduler);}公共任务运行(func func,CancellationToken token = default(CancellationToken)) {返回Task.Factory.StartNew(func,令牌,TaskCreationOptions.None,_taskScheduler);}公共任务运行(func func,CancellationToken token = CancellationToken ){返回Task.Factory.StartNew(func,token,TaskCreationOptions.None,_taskScheduler).Unwrap();}公共任务运行(Func func,CancellationToken token = default(CancellationToken)) {返回Task.Factory.StartNew(func,token,TaskCreationOptions.None,_taskScheduler).Unwrap();}}
https://stackoverflow.com/questions/43815772
复制相似问题