如何设置在另一个线程

如何设置在另一个线程

本文介绍了在WPF中,如何设置在另一个线程(另一个分派器)上构建的窗口的窗口所有者的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到以下异常:
InvalidOperationException:调用线程无法访问该对象,因为其他线程拥有它。

I got the following exception:InvalidOperationException : The calling thread cannot access this object because a different thread owns it.

当我尝试设置在所有者以外的其他线程上构建的窗口的所有者。

when I try to set the Owner of a window that is build on another thread than the Owner.

我知道我只能从适当的线程更新UI对象,但是为什么我不能只设置所有者(如果它来自另一个线程)呢?我可以用其他方式吗?我想使进度窗口成为唯一一个可以输入条目的窗口。

I know that I can only update UI object from the proper thread, but why I can't just set the owner if it come from another thread? Can I do it on another way ? I want to make the progress window the only one which can have input entries.

这是发生错误的代码部分:

This is the portion of code where bug occurs:

    public partial class DlgProgress : Window
{
    // ******************************************************************
    private readonly DlgProgressModel _dlgProgressModel;

    // ******************************************************************
    public static DlgProgress CreateProgressBar(Window owner, DlgProgressModel dlgProgressModel)
    {
        DlgProgress dlgProgressWithProgressStatus = null;
        var listDlgProgressWithProgressStatus = new List<DlgProgress>();
        var manualResetEvent = new ManualResetEvent(false);
        var workerThread = new ThreadEx(() => StartDlgProgress(owner, dlgProgressModel, manualResetEvent, listDlgProgressWithProgressStatus));
        workerThread.Thread.SetApartmentState(ApartmentState.STA);
        workerThread.Start();
        manualResetEvent.WaitOne(10000);
        if (listDlgProgressWithProgressStatus.Count > 0)
        {
            dlgProgressWithProgressStatus = listDlgProgressWithProgressStatus[0];
        }

        return dlgProgressWithProgressStatus;
    }

    // ******************************************************************
    private static void StartDlgProgress(Window owner, DlgProgressModel progressModel, ManualResetEvent manualResetEvent, List<DlgProgress> listDlgProgressWithProgressStatus)
    {
        DlgProgress dlgProgress = new DlgProgress(owner, progressModel);
        listDlgProgressWithProgressStatus.Add(dlgProgress);
        dlgProgress.ShowDialog();
        manualResetEvent.Set();
    }

    // ******************************************************************
    private DlgProgress(Window owner, DlgProgressModel dlgProgressModel)
    {
        if (owner == null)
        {
            throw new ArgumentNullException("Owner cannot be null");
        }

        InitializeComponent();
        this.Owner = owner; // Can't another threads owns it exception


推荐答案

答案以上是正确的。但我将尝试总结一下:

Answer above was correct. But I will try to summarize:

     [DllImport("user32.dll")]
     static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);

  public static void SetOwnerWindowMultithread(IntPtr windowHandleOwned, IntPtr intPtrOwner)
  {
            if (windowHandleOwned != IntPtr.Zero && intPtrOwner != IntPtr.Zero)
            {
                SetWindowLong(windowHandleOwned, GWL_HWNDPARENT, intPtrOwner.ToInt32());
            }
 }

获取WPF处理程序的代码:

Code to get WPF handler:

 public static IntPtr GetHandler(Window window)
        {
            var interop = new WindowInteropHelper(window);
            return interop.Handle;
        }

请注意,应在设置所有者调用之前初始化窗口! (可以在窗口中设置。已加载或窗口中。 SourceInitialized 事件)

Note that window should be initialized before set owner call! (can be set in window.Loaded or window.SourceInitialized event)

 var handler = User32.GetHandler(ownerForm);

        var thread = new Thread(() =>
        {
                var window = new DialogHost();
                popupKeyboardForm.Show();
                SetOwnerWindowMultithread(GetHandler(popupKeyboardForm), handler);
                Dispatcher.Run();
        });

        thread.IsBackground = true;
        thread.Start();

也可以使用SetParent。比不需要转换处理程序:

Also SetParent can be used. Than you dont need to convert handlers:

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

请注意,父母和所有者的含义不同。

Note that parent and owner have different meanings.Win32 window Owner vs window Parent?

这篇关于在WPF中,如何设置在另一个线程(另一个分派器)上构建的窗口的窗口所有者的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-15 08:35