【发布时间】:2020-03-19 15:28:34
【问题描述】:
/免责声明,这是我第一次使用 WPF 和多线程,如果我犯了一些大错误,请多多包涵/
所以我有一个带有选项卡控件的应用程序。在其中一个选项卡中,我打算通过通常的 Windows 窗体主机 + Visio 查看器 activeX 控件等加载 visio 文件......它工作得很好。唯一的问题是,当我在文档中加载时,UI 会冻结 20 秒(因为我正在加载相当大的文件)。当我读到这是因为我的应用程序在一个简单的线程上运行。所以我试图实现一个后台工作者,以在后台线程运行时保持 UI 反应。
当我实例化我的 UserControl 然后我添加到选项卡(初始路径是 visio 文件的文件路径):
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += Worker_DoWork;
worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
worker.RunWorkerAsync(initialpath);
private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
DiagramView UCworker;
UCworker = new DiagramView((string)e.Argument);
e.Result = UCworker;
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
UC = (DiagramView)e.Result;
this.Host.Child = UC;
}
当它创建新的 DiagramView 时:
public DiagramView(string path)
{
InitializeComponent();
this.Resize += new EventHandler(this.UpdateSize);
this.viewer = new AxVisioViewer.AxViewer();
this.Controls.Add(this.viewer);
this.viewer.CreateControl();
this.viewer.Load(path);
this.viewer.HighQualityRender = false;
this.viewer.BackColor = Color.White;
this.viewer.PageTabsVisible = true;
this.viewer.ContextMenuEnabled = false;
this.viewer.PropertyDialogEnabled = false;
this.viewer.ToolbarVisible = true;
this.viewer.OnSelectionChanged += Viewer_OnSelectionChanged;
}
对于这一行:
this.viewer = new AxVisioViewer.AxViewer();
我得到:'ActiveX 控件'f8cf7a98-2c45-4c8d-9151-2d716989ddab' 无法实例化,因为当前线程不在单线程单元中。'
我读到后台工作人员无法修改 UI 元素(如果我错了,请纠正我)
我也看到了这个帖子:Single-threaded apartment - cannot instantiate ActiveX control
但我不确定如何实现它(这个 STA 公寓状态业务),当我尝试时,visio 查看器在尝试打开文档时简单崩溃。
我需要一些指南来解决这个问题,因为我的目标是让加载页面显示动画,直到文档完成加载/渲染,以便我可以显示它。
提前感谢您的回答。
更新: 我也尝试了以下方法:
public partial class TabDiagramView : UserControl, INotifyPropertyChanged
{
public delegate void DisplayVisio(DiagramView view);
public DisplayVisio DelegateM;
DiagramView UC;
public TabDiagramView()
{
InitializeComponent();
DelegateM = new DisplayVisio(DisplayV);
Thread t = new Thread(RT);
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
}
#region Thread
private void RT()
{
DiagramView UCworker;
UCworker = new DiagramView(initialpath);
Dispatcher.Invoke(DelegateM, UCworker);
}
private void DisplayV (DiagramView DiagV)
{
UC = DiagV;
this.Host.Child = DiagV;
}
但在这种情况下,当我在 DisplayV 方法中时,我在 UC 和 this.Host.chilld=DiagV 上收到以下消息: System.InvalidOperationException: 'Cross-thread operation not valid: Control '' 从线程访问除了创建它的线程。'
【问题讨论】:
-
如果您告诉我们您使用的是什么库会有所帮助?什么是 AxVisioViewer.AxViewer?
-
根本不可能从另一个线程加载 UI 控件。如果该库包含异步加载器,则可以使用该方法加载而不会阻塞 UI 线程,否则您将不走运
-
嗨! AxVisioViewer.AxViewer 只是对 Visio 查看器 API (docs.microsoft.com/en-us/office/vba/api/…) 的引用,创建的对象是 Visio 查看器对象 (docs.microsoft.com/en-us/office/vba/api/visio.viewer)。我还尝试手动创建线程(请参阅更新)
-
正如我所说,您不能在另一个线程中创建控件。该库应提供线程安全的方法,否则无法完成。最接近实现它的方法是仅将 Load() 放在另一个线程中,但我认为这行不通
标签: c# wpf multithreading visio