gpt4 book ai didi

c# - DoEvents 与其他任何东西 --> 对于长时间的 COM 操作

转载 作者:行者123 更新时间:2023-11-30 19:40:58 25 4
gpt4 key购买 nike

我有一个 WPF 程序,我的模型需要加载一个“进程外”(.exe) COM 组件,以便在用户在 UI 上执行操作时实现一些验证.我想通知用户将执行一个长操作,让他知道应用程序正忙,而不仅仅是卡住。但是 UI 上的任何操作都发生在 COM 操作完成之后。

我认为任何 COM 通信都应该在主 UI 线程上完成。它消除了将在除主 (UI) 线程之外的另一个线程上运行的任何解决方案。

我尝试了很多选项都没有成功:

我看不出如何从需要刷新 UI 的模型中实现同步操作。我的操作有一个属性“IsLoading”,我从我的 View 中订阅了它,我尝试根据它的状态更新 UI,但在 WPF 中似乎不可能 ???

还有其他建议吗?

我能否使用 async/await 并从运行另一个调度程序的另一个线程执行我的 COM 操作(有点复杂)并且会失去所需的同步性(用户需要 COM 操作的结果才能继续其工作)?

主要针对盲人...一些更清晰的解释(有关所需同步性的更多详细信息):

当用户单击 TreeView 项目时,我加载了一个网格,然后需要验证在网格中输入的数据是否仍然有效。为了进行验证,我需要通过 COM 加载应用程序并自动加载文档,然后解析它并验证网格中的数据(在 View 中的网格模型中)。这需要 10 秒。如果我在另一个线程上这样做,那么用户可以执行一个操作来选择在网格中添加一个新行,该行仍然依赖于加载了先前文档的同一 COM 应用程序。我仍然需要等待应用程序加载。这是一个同步 Action 。我的应用程序依赖于该 COM 应用程序及其加载的文档处于有效状态,以便用户执行更多操作。但我需要就我正在做的事情向用户提供一些反馈(启动 COM 应用程序并加载文档)。在另一个线程上执行 COM 操作只会稍后报告问题,但不能解决用户需要等待操作完成的事实。我想我需要(强制)更新我的 WPF 应用程序,但找不到任何(扭曲的)方法来做到这一点。

最佳答案

[UPDATE] 由于 OP 更新了问题并指定他正在使用 out-of-proc COM 对象,因此下面描述的自定义 STA 线程管道不会感觉。现在,一个简单的 await Task.Run(() => {/* call the out-of-proc COM */}) 就足以保持 UI 响应。感谢@acelent澄清这一点。


最近回答了一个相关问题:StaTaskScheduler and STA thread message pumping .

solution是在专用后台 STA 线程上创建和使用 STA COM 对象,该线程为这些 COM 对象提供消息泵送和线程关联。

我想展示如何 ThreadWithAffinityContext可以在您的情况下使用 async/await:

dynamic _comObject = null;

ThreadWithAffinityContext _staThread = null;

// Start the long-running task
Task NewCommandHandlerAsync()
{
// create the ThreadWithAffinityContext if haven't done this yet
if (_staThread == null)
_staThread = new ThreadWithAffinityContext(
staThread: true,
pumpMessages: true);

// create the COM Object if haven't done this yet
if (_comObject == null)
{
await _staThread.Run(() =>
{
// _comObject will live on a dedicated STA thread,
// run by ThreadWithAffinityContext
_comObject = new ComObject();
}, CancellationToken.None);
}

// use the COM object
await _staThread.Run(() =>
{
// run a lengthy process
_comObject.DoWork();
}, CancellationToken.None);
}

// keep track of pending NewCommandHandlerAsync
Task _newCommandHandler = null;

// handle a WPF command
private async void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
try
{
// avoid re-entrancy (i.e., running two NewCommandHandlerAsync in parallel)
if (_newCommandHandler != null)
throw new InvalidOperationException("One NewCommandHandlerAsync at a time!");
try
{
await _newCommandHandler = NewCommandHandlerAsync();
}
finally
{
_newCommandHandler = null;
}
}
catch (Exception ex)
{
// handle all exceptions possibly thrown inside "async void" method
MessageBox.Show(ex.Message);
}
}

我们将冗长的过程 _comObject.DoWork() 卸载到单独的线程这一事实并不能自动解决其他常见的 UI 相关问题:

当冗长的后台操作挂起时如何处理 UI?

有多种选择。例如,您可以禁用触发 NewCommand_Executed 事件的 UI 元素,以避免重新进入,并启用另一个 UI 元素以允许用户取消挂起的工作(Stop按钮)。如果您的 COM 对象支持,您还应该提供一些进度反馈。

或者,您可以在启动长时间运行的任务之前显示模式对话框,并在任务完成后隐藏它。就 UI 可用性而言,模态不太理想,但它很容易实现 (example)。

关于c# - DoEvents 与其他任何东西 --> 对于长时间的 COM 操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21531445/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com