none
WPFToolkitのAutoCompleteBoxを別タスクのWindowで表示 RRS feed

  • 質問

  • 複数のWPFウィンドウを別スレッドで起動させるため、下記のように各ウィンドウを開いています。
    Window win = null;
    DispatcherFrame dispacherFrame = null;
    
    var thread = new Thread(
        () =>
        {
            dispacherFrame = new DispatcherFrame(true);
            win = new Window1();
            win.Show();
            win.Closed += (o, args) =>
            {
                dispacherFrame.Continue = false;
            };
            Dispatcher.PushFrame(dispacherFrame);
        });
    thread.SetApartmentState(ApartmentState.STA);
    
    thread.Start();
    

    この時、Window1にAutoCompleteBoxが配置されていると、win.Show()の段階でSystem.InvalidOperationExceptionが発生します。

     型 'System.InvalidOperationException' のハンドルされていない例外が WindowsBase.dll で発生しました

     追加情報:このオブジェクトは別のスレッドに所有されているため、呼び出しスレッドはこのオブジェクトにアクセスできません。

       場所 System.Windows.Threading.Dispatcher.VerifyAccess()
       場所 System.Windows.Application.get_Windows()
       場所 System.Windows.Controls.PopupHelper.Arrange()
       場所 System.Windows.Controls.AutoCompleteBox.ArrangeOverride(Size finalSize)
       場所 System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
       場所 System.Windows.UIElement.Arrange(Rect finalRect)
       場所 System.Windows.Controls.StackPanel.StackArrangeHelper(IStackMeasure arrangeElement, IStackMeasureScrollData scrollData, Size arrangeSize)
       場所 System.Windows.Controls.StackPanel.ArrangeOverride(Size arrangeSize)
       場所 System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
       場所 System.Windows.UIElement.Arrange(Rect finalRect)
       場所 System.Windows.Controls.Grid.ArrangeOverride(Size arrangeSize)
       場所 System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
       場所 System.Windows.UIElement.Arrange(Rect finalRect)
       場所 System.Windows.Controls.DockPanel.ArrangeOverride(Size arrangeSize)
       場所 System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
       場所 System.Windows.UIElement.Arrange(Rect finalRect)
       場所 MS.Internal.Helper.ArrangeElementWithSingleChild(UIElement element, Size arrangeSize)
       場所 System.Windows.Controls.ContentPresenter.ArrangeOverride(Size arrangeSize)
       場所 System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
       場所 System.Windows.UIElement.Arrange(Rect finalRect)
       場所 System.Windows.Controls.Decorator.ArrangeOverride(Size arrangeSize)
       場所 System.Windows.Documents.AdornerDecorator.ArrangeOverride(Size finalSize)
       場所 System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
       場所 System.Windows.UIElement.Arrange(Rect finalRect)
       場所 System.Windows.Controls.Border.ArrangeOverride(Size finalSize)
       場所 System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
       場所 System.Windows.UIElement.Arrange(Rect finalRect)
       場所 System.Windows.Window.ArrangeOverride(Size arrangeBounds)
       場所 System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
       場所 System.Windows.UIElement.Arrange(Rect finalRect)
       場所 System.Windows.Interop.HwndSource.SetLayoutSize()
       場所 System.Windows.Interop.HwndSource.set_RootVisualInternal(Visual value)
       場所 System.Windows.Window.SetRootVisual()
       場所 System.Windows.Window.SetRootVisualAndUpdateSTC()
       場所 System.Windows.Window.SetupInitialState(Double requestedTop, Double requestedLeft, Double requestedWidth, Double requestedHeight)
       場所 System.Windows.Window.CreateSourceWindow(Boolean duringShow)
       場所 System.Windows.Window.ShowHelper(Object booleanBox)

    WPFToolkit.3.5.50211.1をローカルコピー:Trueで参照しております。

    解決方法はありますでしょうか。

    2017年3月20日 5:09

回答

  • AutoCompleteBoxが呼び出している関数内でメインスレッドにあるウィンドウにアクセスしようとしてるので、それを回避する必要があります。

    解決方法はCodeplexからソースコードをダウンロードしてきて該当箇所を修正したバイナリをビルドです。
    \Source\Input\AutoCompleteBox\System\Windows\Controls\PopupHelper.cs

    public void Arrange()
    {
        if (Popup == null
            || PopupChild == null
    #if SILVERLIGHT
    || OutsidePopupCanvas == null
    #endif
    || Application.Current == null
    #if SILVERLIGHT
    || Application.Current.Host == null
            || Application.Current.Host.Content == null
    #endif
    || false)
        {
            return;
        }
    
    #if SILVERLIGHT
        Content hostContent = Application.Current.Host.Content;
        double rootWidth = hostContent.ActualWidth;
        double rootHeight = hostContent.ActualHeight;
    #else
        UIElement u = Parent;
        /* ここから */
        //if (Application.Current.Windows.Count > 0)
        //{
        //    // TODO: USE THE CURRENT WINDOW INSTEAD! WALK THE TREE!
        //    u = Application.Current.Windows[0];
        //}
        /* ここまでを消す */
        while ((u as Window) == null && u != null)
        {
            u = VisualTreeHelper.GetParent(u) as UIElement;
        }
        Window w = u as Window;
        if (w == null)
        {
            return;
        }
    //以下略

    ダウンロードした各ファイルは読み取り専用になっているので解除する。
    ビルドはControls.Input.Toolkitプロジェクトだけを取り出して、既存のWPFToolkit.dllに参照変更するだけでいい。


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2017年3月20日 8:09

すべての返信

  • AutoCompleteBoxが呼び出している関数内でメインスレッドにあるウィンドウにアクセスしようとしてるので、それを回避する必要があります。

    解決方法はCodeplexからソースコードをダウンロードしてきて該当箇所を修正したバイナリをビルドです。
    \Source\Input\AutoCompleteBox\System\Windows\Controls\PopupHelper.cs

    public void Arrange()
    {
        if (Popup == null
            || PopupChild == null
    #if SILVERLIGHT
    || OutsidePopupCanvas == null
    #endif
    || Application.Current == null
    #if SILVERLIGHT
    || Application.Current.Host == null
            || Application.Current.Host.Content == null
    #endif
    || false)
        {
            return;
        }
    
    #if SILVERLIGHT
        Content hostContent = Application.Current.Host.Content;
        double rootWidth = hostContent.ActualWidth;
        double rootHeight = hostContent.ActualHeight;
    #else
        UIElement u = Parent;
        /* ここから */
        //if (Application.Current.Windows.Count > 0)
        //{
        //    // TODO: USE THE CURRENT WINDOW INSTEAD! WALK THE TREE!
        //    u = Application.Current.Windows[0];
        //}
        /* ここまでを消す */
        while ((u as Window) == null && u != null)
        {
            u = VisualTreeHelper.GetParent(u) as UIElement;
        }
        Window w = u as Window;
        if (w == null)
        {
            return;
        }
    //以下略

    ダウンロードした各ファイルは読み取り専用になっているので解除する。
    ビルドはControls.Input.Toolkitプロジェクトだけを取り出して、既存のWPFToolkit.dllに参照変更するだけでいい。


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2017年3月20日 8:09
  • 解消されました。ありがとうございます。

    2017年3月21日 5:00