Skip to content

多线程问题:调用线程无法访问此对象,因为另一个线程拥有该对象 #632

Closed

Description

@cuiliang

有的情况下,为了避免模态窗口弹出时无法操作别的窗口,会对个别窗口使用新的线程运行。
示例代码:

public static class DispatcherBuilder
    {
        public static Dispatcher Build()
        {
            Dispatcher dispatcher = null;
            var manualResetEvent = new ManualResetEvent(false);
            var thread = new Thread(() =>
            {
                dispatcher = Dispatcher.CurrentDispatcher;
                var synchronizationContext = new DispatcherSynchronizationContext(dispatcher);
                SynchronizationContext.SetSynchronizationContext(synchronizationContext);

                manualResetEvent.Set();

                try
                {
                    Dispatcher.Run();
                }
                catch
                {
                    // ignore
                }
            }, maxStackSize: 1);
            thread.Priority = ThreadPriority.Normal;
            thread.SetApartmentState(ApartmentState.STA);
            thread.IsBackground = true;
            thread.Start();
            manualResetEvent.WaitOne();
            manualResetEvent.Dispose();
            return dispatcher;
        }
    }
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            var dispatcher = DispatcherBuilder.Build();

            dispatcher.InvokeAsync(() =>
            {
                try
                {
                    MainWindow mainWindow = new MainWindow();
                    mainWindow.Show();

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


            });
        }

使用HC库以后,这种情况会报线程错误:
image

WPF原生风格没有这个问题。
示例代码(threadtest分支):https://github.com/cuiliang/HandyControl/tree/threadtest

Activity

  1. lwqwag commented on Jan 22, 2021

    @lwqwag
    Contributor

    使用hc后我也遇到同样的问题

  2. GF-Huang commented on Jan 22, 2021

    @GF-Huang
    Member

    建议代码用这种形式包起来,没有着色很难看。

    class A {
        public void Method() { }
    }

    image

  3. NaBian commented on Jan 26, 2021

    @NaBian
    Member

    先尝试一下这里的解决方案 access-to-styles-from-several-ui-threads

  4. added and removed
    🐛 bugSomething isn't working
    on Jan 26, 2021
  5. cuiliang commented on Jan 29, 2021

    @cuiliang
    ContributorAuthor

    @NaBian
    这里的方案(使用一个线程,模拟ShowDialog)我也在使用,有个问题:子窗体关闭的时候,父窗体有些时候会被最小化。
    多线程的场景主要是有一些用户自定义的c#脚本,把它们当作一个独立的程序运行,这种情况下放在新的线程里比较合适一点。

  6. NaBian commented on Jan 31, 2021

    @NaBian
    Member

    原因其实知道,是因为window在初始化的时候会去app.xaml中寻找默认样式,这将导致跨线程,所以报错了,但是还没有时间尝试该如何解决

  7. NaBian commented on Jun 20, 2021

    @NaBian
    Member

    需要使用子线程打开的窗口需要独立的样式资源,使用以下代码可解决多线程报错问题:

    <Window.Resources>
        <hc:StandaloneTheme/>
    </Window.Resources>
    
  8. cuiliang commented on Jun 20, 2021

    @cuiliang
    ContributorAuthor

    @NaBian 感谢~ 今天找到了一个使用await的方式避免多线程。

    https://stackoverflow.com/a/25601933/3335415

    private Task ShowPopup<TPopup> (TPopup popup)
        where TPopup : Window
    {
        var task = new TaskCompletionSource<object>();
        popup.Owner = Application.Current.MainWindow;
        popup.Closed += (s, a) => task.SetResult(null);
        popup.Show();
        popup.Focus();
        return task.Task;
    }
    

    再加上一些禁用父窗口的处理,大概可以模拟模态的效果。 就是不知道会不会有别的问题,等发布版本以后看看有没有反馈😂

  9. added a commit that references this issue on Mar 28, 2024
    e44e117
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      ⌂ 换网址