Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
cuiliang opened this issue Jan 22, 2021 · 7 comments
Labels
🤔 pending discussion It may take time to discuss.

Comments

@cuiliang
Copy link
Contributor

cuiliang commented Jan 22, 2021

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

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

@lwqwag
Copy link
Contributor

lwqwag commented Jan 22, 2021

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

@GF-Huang
Copy link
Member

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

class A {
    public void Method() { }
}

image

@NaBian NaBian added the 🐛 bug Something isn't working label Jan 26, 2021
@NaBian
Copy link
Member

NaBian commented Jan 26, 2021

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

@NaBian NaBian added 🤔 pending discussion It may take time to discuss. and removed 🐛 bug Something isn't working labels Jan 26, 2021
@cuiliang
Copy link
Contributor Author

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

@NaBian
Copy link
Member

NaBian commented Jan 31, 2021

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

@NaBian NaBian closed this as completed in e44e117 Jun 20, 2021
@NaBian
Copy link
Member

NaBian commented Jun 20, 2021

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

<Window.Resources>
    <hc:StandaloneTheme/>
</Window.Resources>

@cuiliang
Copy link
Contributor Author

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

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🤔 pending discussion It may take time to discuss.
Projects
None yet
Development

No branches or pull requests

4 participants