How can I create WPF controls in a background thread?

后端 未结 8 597
终归单人心
终归单人心 2021-01-17 15:49

I have method which create background thread to make some action. In this background thread I create object. But this object while creating in runtime give me an exception :

相关标签:
8条回答
  • 2021-01-17 16:14

    TreeView is a UI control. You can only create and manipulate UI controls on a UI thread, so what you're trying to do is not possible.

    What you want to do is do all of the time-consuming work on the background thread, and then "call back" to the UI thread to manipulate the UI. This is actually quite easy:

    void Background_Method(object sender, DoWorkEventArgs e)
    {
        // ... time consuming stuff...
    
        // call back to the window to do the UI-manipulation
        this.BeginInvoke(new MethodInvoker(delegate {
            TreeView tv = new TreeView();
            // etc, manipulate
        }));
    }
    

    I may have got the syntax wrong for BeginInvoke (it's off the top of my head), but there you go anyway...

    0 讨论(0)
  • 2021-01-17 16:15

    HTH:

        void Background_Method(object sender, DoWorkEventArgs e)
        {
            // Time Consuming operations without using UI elements
            // Result of timeconsuming operations
            var result = new object();
            App.Current.Dispatcher.Invoke(new Action<object>((res) =>
                {
                    // Working with UI
                    TreeView tv = new TreeView();
                }), result);
        }
    
    0 讨论(0)
  • 2021-01-17 16:16

    Try following Code:

    public void SomeMethod() 
    { 
    
    System.ComponentModel.BackgroundWorker myWorker = new  System.ComponentModel.BackgroundWorker();
    
    myWorker.DoWork += myWorker_DoWork;
    
    myWorker.RunWorkerAsync();
    
    }
    
    private void myWorker_DoWork(object sender,
       System.ComponentModel.DoWorkEventArgs e)
    {
       // Do time-consuming work here
    }
    
    0 讨论(0)
  • 2021-01-17 16:20

    To make your code simply work, you must join a STA COM apartment by calling Thread.SetApartmentState(ApartmentState.STA). Since BackgroundWorker is probably using some shared thread pool, joining a particular apartment may affect other users of this thread pool or may even fail if it has already been set to e.g. MTA before. Even if it all worked out, your newly created TreeView would be locked to this worker thread. You wouldn't be able to use it in your main UI thread.

    If you explained in a bit more detail about your true intentions, you would surely get better help.

    0 讨论(0)
  • 2021-01-17 16:24

    No one is discussing the case of a separate STA thread in details (even though the concept is exactly the same).

    So let's imagine a simple tab control added at a button click

        private void button_Click(object sender, RoutedEventArgs e)
        {
            TabItem newTab = new TabItem() { Header = "New Tab" };
            tabMain.Items.Add(newTab);
        }
    

    If we move it to another STA thread

        private void button_Click(object sender, RoutedEventArgs e)
        {
            Thread newThread = new Thread(new ThreadStart(ThreadStartingPoint));
            newThread.SetApartmentState(ApartmentState.STA);
            newThread.IsBackground = true;
            newThread.Start();
        }
        private void ThreadStartingPoint()
        {
            TabItem newTab = new TabItem() { Header = "New Tab" };
            tabMain.Items.Add(newTab);
        }
    

    of course we get a System.InvalidOperationException

    Now, what happens if we add the control

        private void AddToParent(string header)
        {
            TabItem newTab = new TabItem() { Header = header };
            tabMain.Items.Add(newTab);
        }
    

    using a delegate method?

        public void DelegateMethod(string header)
        {
            tabMain.Dispatcher.BeginInvoke(
                    new Action(() => {
                        this.AddToParent(header);
                    }), null);
        }
    

    it does work if you call it

        private void button_Click(object sender, RoutedEventArgs e)
        {
            Thread newThread = new Thread(new ThreadStart(ThreadStartingPoint));
            newThread.SetApartmentState(ApartmentState.STA);
            newThread.IsBackground = true;
            newThread.Start();
        }
        private void ThreadStartingPoint()
        {
            DelegateMethod("new tab");
        }
    

    because of course now we keep the visual tree in the same original thread.

    0 讨论(0)
  • 2021-01-17 16:26

    See the answer on this question: How to run something in the STA thread?

    When you define your thread, set the ApartmentState to STA:

    thread.SetApartmentState(ApartmentState.STA);
    

    This should do the trick!

    0 讨论(0)
提交回复
热议问题