在STA线程上显示忙碌指示器 [英] Showing busy indicator on a STA thread

查看:82
本文介绍了在STA线程上显示忙碌指示器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想进行长时间的操作,希望显示扩展工具包"的繁忙状态指示器.我对此发表了一篇以前的文章,它已被固定 Wpf扩展工具包操作过程中未显示BusyIndi​​cator .但是,在该调用期间,我必须与UI元素(画布)进行交互,并且得到一个调用线程必须是STA,因为许多UI组件都需要STA".我了解(现在)有后台工作人员(请参见代码):

I have a long operation wehre I'd like to show the Extended Toolkits busy indicator. I made a previous post about this and it was fixed Wpf Extended toolkit BusyIndicator not showing during operation. However, during that call I have to interact with a UI element (canvas) and I get a "The calling thread must be STA, because many UI components require this". I understand (now) that a background worker(see code):

     private void CboItemId_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {

        BackgroundWorker _backgroundWorker = new BackgroundWorker();
        _backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
        _backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_backgroundWorker_RunWorkerCompleted);
        ItemSearchBusyIndicator.IsBusy = true;

       // Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
        if (RdoItemSearch.IsChecked == false) return;
        ///backgroundWorker_DoWork(null, null);

        if (CboItemId.SelectedValue == null) return;
        if (CboItemId.SelectedValue.ToString() != string.Empty)
        {
            selectedItem = CboItemId.SelectedValue.ToString();
            _backgroundWorker.RunWorkerAsync();
        }
       // Mouse.OverrideCursor = System.Windows.Input.Cursors.Arrow;
    }

    public void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {

            LoadItemData(selectedItem);
    }

使用MTA,并且不能设置为STA.因此,我尝试调用在其自己的线程中使用UI元素的内部函数:

uses MTA and cannot be set to STA. So i tried calling the internal function that uses the UI elelment in its own thread:

       public void LoadItemData(string itemId)
    {

        Axapta ax = new Axapta();
        files.Clear();
        try
        {
            ax.Logon(Settings.Default.Server, null, Settings.Default.Test, null);
            AxaptaContainer path = (AxaptaContainer)ax.CallStaticClassMethod(Settings.Default.ClassName, Settings.Default.ItemData, itemId);
            for (int i = 1; i <= path.Count; i++)
            {
                AxaptaContainer somestring = (AxaptaContainer)path.get_Item(i);
                for (int j = 1; j <= somestring.Count; j += 2)
                {
                    string extension = Path.GetExtension(somestring.get_Item(j + 1).ToString().ToLower());
                    if (extension == ".jpg"
                        || extension == ".jpeg"
                        || extension == ".gif"
                        || extension == ".png"
                        || extension == ".bmp"
                        || extension == ".pdf")
                        /* key=path - value=description */
                        files.Add(somestring.get_Item(j + 1).ToString(), somestring.get_Item(j).ToString());
                }
            }

           // _canvas.Children.Clear();
            Thread t = new Thread(new ThreadStart(LoadPictures));
            t.SetApartmentState(ApartmentState.STA);
            t.Start();

        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
        finally
        {
            ax.Logoff();
        }
    }

在此处与canvas元素进行交互的地方:

Heres where I interact with the canvas element:

      private void LoadPictures()
    {

        foreach (DictionaryEntry filePath in files)
        {

            try
            {

                Picture p = new Picture();
                ToolTip t = new ToolTip();
                t.Content = filePath.Value;
                p.ToolTip = t;
                TextBlock tb = new TextBlock();
                tb.Text = filePath.Value.ToString();
                Canvas.SetTop(tb, y);
                Canvas.SetLeft(tb, x);

                    p.ImagePath = filePath.Key.ToString();
                    p.OriginalImagePath = filePath.Key.ToString();
                    p.ImageName = filePath.Value.ToString();
                    _canvas.Children.Add(p); //<-------This is where i seem to error
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error:" + ex.Message,"File Load Error",MessageBoxButton.OK,MessageBoxImage.Error);
            }
        }
    }

但是我得到调用线程无法访问该对象,因为另一个线程拥有它" 我不知道在没有背景工作人员的情况下显示BusyIndi​​cator时如何调用长时间运行的(LoadItemData())函数.任何帮助表示赞赏

but I get a "The calling thread cannot access this object because a different thread owns it" I don't know how to call the long running (LoadItemData()) function while showing the BusyIndicator without a backgroundworker. Any help appreciated

推荐答案

有多种方法:

1)异步绑定,不建议使用,但它在那里.您可以在属性getter中运行长时间运行的任务,完成后框架将阻止UI阻塞-UI将得到更新.

1) Async binding, it's not recommended, but it is there. You can run long running task in property getter, framework will prevent UI from blocking, when it is finished - UI will get updated.

2)使用BackgroundWorkerTask/Thread运行代码,但将其调用到UI线程中.在您的示例中:

2) Use BackgroundWorker or Task/Thread to run code, but invoke it into UI thread. In your example:

Dispatcher.InvokeAsync(() => _canvas.Children.Add(p));

3)您可以完全阻止主窗口的UI线程,没有问题.但是要表明它正忙,您可以在另一个线程中创建一个窗口,并在其中显示忙状态(运行动画等):

3) You can block UI thread of main window completely, no problems. But to indicate about its being busy you can create window in another thread and show there busy status (run animations, etc):

        var thread = new Thread(() =>
        {
            var window = new SomeWindow();
            window.ShowDialog();
        });
        thread.SetApartmentState(ApartmentState.STA);
        thread.IsBackground = true;
        thread.Start();

这篇关于在STA线程上显示忙碌指示器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆