WPF - загрузить файл Visio с помощью Backgroundworker - PullRequest
1 голос
/ 19 марта 2020

/ Отказ от ответственности, я впервые работаю с WPF и с многопоточностью, так что потерпите меня, если я совершаю большие ошибки /

Итак, у меня есть приложение с tabcontrol. В одной из вкладок я собираюсь загрузить файл Visio с помощью обычной windows формы host + Visio Viewer ActiveX Control et c ... И это работает отлично. Единственная проблема заключается в том, что когда я загружаю документ, пользовательский интерфейс останавливается на 20 секунд (поскольку я загружаю довольно большие файлы). Насколько я понимаю, это потому, что мое приложение работает в простом потоке. Поэтому я пытался внедрить фоновый рабочий, чтобы поддерживать реактивный интерфейс во время работы фонового потока.

Когда я создаю экземпляр своего UserControl, я добавляю его на вкладку (Initialpath - это путь к файлу 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 control' Невозможно создать экземпляр f8cf7a98-2c45-4c8d-9151-2d716989ddab ', поскольку текущий поток не находится в однопоточной квартире.'

Я прочитал, что фоновый работник не способен изменять элементы пользовательского интерфейса ( поправьте меня, если я ошибаюсь)

Я также видел эту тему: Однопоточная квартира - не удается создать экземпляр элемента управления ActiveX

Но я не уверен, как это реализовать ( это STA квартира состояние бизнеса) и когда я пытался, Visio Viewer просто рухнул при попытке открыть документ.

Мне нужны некоторые рекомендации, как подходить к этой проблеме, потому что моей целью было бы, чтобы загрузка страницы отображалась с анимацией до тех пор, пока Документ не завершит загрузку / рендеринг, чтобы я мог отобразить его.

Заранее спасибо за ответы.

ОБНОВЛЕНИЕ: Я также попробовал следующий подход :

    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;
    }

Но в этом случае я получите следующее сообщение для U C и this.Host.chilld = DiagV, когда я нахожусь в методе DisplayV: System.InvalidOperationException: «Операция между потоками недопустима: Control», доступ к которой осуществляется из потока, отличного от потока, в котором она был создан на. '

1 Ответ

0 голосов
/ 19 марта 2020

Просто невозможно загрузить элемент управления пользовательского интерфейса из другого потока. Однако вы могли бы решить проблему зависания, если бы библиотека обеспечивала многопоточный подход (например, AxViewer.LoadAsync), поэтому единственный способ сделать viewer.Load переносимым для пользователя - это отложить операцию viewer.Load до загрузки окна:

string _path;
public DiagramView(string path)
{
    InitializeComponent();

    _path = path;
   this.Resize += new EventHandler(this.UpdateSize);
   this.viewer = new AxVisioViewer.AxViewer();
   this.Controls.Add(this.viewer);
   this.viewer.CreateControl();
   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.Loaded += Viewer_Loaded;
}

private void Viewer_Loaded(object sender, RoutedEventArgs e)
{
    viewer.Load(_path);
}

И что более важно, удалите фоновый рабочий код. Здесь это не приносит пользы.

...