Home > C# > Toolkit > DockingWindow > AvalonDock > ドキュメント

結合の問題

原文

Binding Issues(外部サイト)

訳文

結合の問題

Binding Issues

はじめに

このドキュメントでは、私は、AvalonDockでDockableContentsとDocumentContentsのためのWPFの結合をどのように管理するか説明していきます。 あなたのユーザーが、DockingManagerの上に内容を移動するか、フライアウト・ウィンドウとしてそれらを設定するとき、 AvalonDockは、ドラッグされた内容を受け入れるために、自動的に、新しいウィンドウを作成します。 これは、WinFormsコントロールをサポートするために、必要なプロジェクト要件でした。 実際に、WPFは、常に、WPFの要素の上に、常に、WinFormsコントロールを(内部の子ウィンドウに)描画します。 あなたが、想像するように、WPFの結合を壊して異なるウィンドウに、内容を移動します。 次のサンプルでは、私は、あなたに、アプリケーション・レベルのオブジェクトで結合を使用して、問題をどのように解決するかを示します。

問題

新しいアプリケーションを、AvalonDockを使用して作成しはじめましょう。(もちろん、AvalonDock.dllのアセンブリを必ず参照してください)。

これは、xamlファイルです。:


<Window x:Class="AvalonDock.BindingSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ad="clr-namespace:AvalonDock;assembly=AvalonDock"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="24"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Menu>
            <MenuItem Header="Add Item" Click="OnAddItem"/>
        </Menu>
        <ad:DockingManager Grid.Row="1">
            <ad:ResizingPanel>
                <ad:DockablePane ad:ResizingPanel.ResizeWidth="100">
                    <ad:DockableContent Title="Sample Content">
                        <ListBox x:Name="listBoxToBind"/>
                    </ad:DockableContent>
                </ad:DockablePane>
                <ad:DocumentPane/>
            </ad:ResizingPanel>
        </ad:DockingManager>
    </Grid>
</Window>

次に、MainWindowの依存関係プロパティとして、文字列のコレクションを追加してみましょう。 それは、上で示したDockableContentサンプルに含まれている、listbox「listBoxToBind」の結合参照元になります。


public static readonly DependencyProperty SampleCollectionProperty =
DependencyProperty.Register("SampleCollection", typeof(ObservableCollection<string>), typeof(MainWindow),
new FrameworkPropertyMetadata((ObservableCollection<string>)new ObservableCollection<string>()));

単純に、コレクションに項目を追加する、インターフェース内に存在するメニュー・アイテムのために、実際に、イベントハンドラを追加します。:


public partial class MainWindow : Window
 {
     public MainWindow()
     {
         InitializeComponent();

         this.DataContext = this;

     }

     private void OnAddItem(object sender, RoutedEventArgs e)
     {
         SampleCollection.Add("NewItem " + (SampleCollection.Count + 1));
     }


     #region SampleCollection

     /// <summary>
     /// SampleCollection Dependency Property
     /// </summary>
     public static readonly DependencyProperty SampleCollectionProperty =
         DependencyProperty.Register("SampleCollection", typeof(ObservableCollection<string>), typeof(MainWindow),
                new FrameworkPropertyMetadata((ObservableCollection<string>)new ObservableCollection<string>()));

     /// <summary>
     /// Gets or sets the SampleCollection property. 
    /// </summary>
    public ObservableCollection<string> SampleCollection
    {
        get { return (ObservableCollection<string>)GetValue(SampleCollectionProperty); }
        set { SetValue(SampleCollectionProperty, value); }
    }

    #endregion
}

最後に、listboxを先に述べたコレクションに結合します。 (私が、分かりやすくするために、MainWindowデータ・コンテクストをそれ自身に設定したことに注意してください)、そして、アプリケーションを実行します。:


<ad:DockableContent Title="Sample Content">
   <ListBox x:Name="listBoxToBind" ItemsSource="{Binding SampleCollection}"/>
</ad:DockableContent>

あなたが、次のスクリーンショットのような、'Add Item'メニューをクリックします。:

'Add Item'メニューをクリックします。

すべてが、正常に動作するようです。しかし、あなたが、ドッキング可能な内容を、外側にドラッグしようとする場合、 浮動ウィンドウのlistboxの項目が非表示になります。あなたが、フライアウト・ウィンドウのような内容を配置しようとするのと、同じ効果です。 ドッキング・マネージャーの内側に内容を戻すと、あなたは、その結合が再度、始まることを見つけるでしょう。 あなたが、結合が壊れることを想像するように、内容が、他のウィンドウへ移動するため、 それは、メイン・ウィンドウの異なる論理tree.datacontextは、これ以上、この状態でドラッグした内容を表示しません。

解決策

The Solution

WPFは、この小さな問題を解決するために、我々に多くの選択肢を与えます。 もちろん、そのアプリケーション要件や設計のより多くを組合せた、1つの解決策を選択します。 この場合、最も簡単なものは、結合参照元を明示的に示すことです。 それは、App.Currentオブジェクトのような、アプリケーション・レベルに表示されます。

このような何か:


<ListBox x:Name="listBoxToBind"
 ItemsSource="{Binding Path=MainWindow.SampleCollection, Source={x:Static local:App.Current}}"/>

他の回避方法は、結合するためのオブジェクトを公開する、DockableContentから派生するカスタム・クラスを作成することです。 そして、ListBoxのDataContextのような、ユーザー定義したドッキング可能な内容を、それ自身に設定します。

コマンド結合

Command Bindings

あなたは、コマンド結合の問題も経験することができました。例えば、コンテキストメニューを、ただ1つのメニュー・アイテムでリストボックスに追加しようと試みます。 ユーザーが、その上でクリックすると、WPFは、私たちが、MainWindowクラスのメソッドで処理したいために、カスタム・コマンドを実行します。これは、コマンドです。:


public class CustomCommands
{
    #region MyCommand

    /// <summary>
    /// The MyCommand command .
    /// </summary>
    public static RoutedUICommand MyCommand
        = new RoutedUICommand("My Command", "MyCommand", typeof(CustomCommands));

    #endregion
}

そして、これは、MainWindowのコマンド結合で変更されるXAMLです。そして、listboxは、コンテキストメニューに添付されます。:


….
    <Window.CommandBindings>
        <CommandBinding Command="{x:Static local:CustomCommands.MyCommand}" 
CanExecute="OnCanExecuteMyCommand" 
Executed="OnExecutedMyCommand"/>
    </Window.CommandBindings>
…
<ListBox x:Name="listBoxToBind" 
ItemsSource="{Binding Path=MainWindow.SampleCollection, Source={x:Static local:App.Current}}">
      <ListBox.ContextMenu>
         <ContextMenu>
             <MenuItem Command="{x:Static local:CustomCommands.MyCommand}"/>
         </ContextMenu>
       </ListBox.ContextMenu>
</ListBox>
…

最後に、私たちは、コマンド結合のために、2つのイベントハンドラを定義する必要があります。そのメッセージボックスが、ポップアップします。:


private void OnCanExecuteMyCommand(object sender, CanExecuteRoutedEventArgs e)
 {
     e.CanExecute = true;
 }

 private void OnExecutedMyCommand(object sender, ExecutedRoutedEventArgs e)
 {
     MessageBox.Show("My Command!");
 }

次に、プロジェクトを構築して、アプリケーションを実行します。内容は、あなたが、右クリックできるlistboxの上で、DockingManagerにドッキングします。 そして、その次に、メニュー・アイテム・コマンドをアクティブにします。それは、偽物のメッセージボックスを表示します。 すべては、正常に動作します。あなたが、浮動ウィンドウのように、内容をドラッグするまで、あるいは、それをフライアウト・ウィンドウに配置します。これは、何かが発生します。:

フライアウト・ウィンドウに配置

メニューの項目はグレー表示されます。 なぜなら、WPFは、ListBoxが含まれているウィンドウの論理ツリーを上に横断するコマンドを、処理できるコマンド結合を見つけることができません。 最初の場合のように、結合は、動作を停止します。ここに、さらに簡単な、解決策があります。: 実際に、コンテキストメニューにより近い、コマンド結合を移動します。 あなたは、たとえば、DockableContent.CommandBindingsにコマンド結合を追加することができます。:


<ad:DockableContent Title="Sample Content">
    <ad:DockableContent.CommandBindings>
       <CommandBinding Command="{x:Static local:CustomCommands.MyCommand}" 
CanExecute="OnCanExecuteMyCommand" 
Executed="OnExecutedMyCommand"/>
   </ad:DockableContent.CommandBindings>
   <ListBox x:Name="listBoxToBind" 
ItemsSource="{Binding Path=MainWindow.SampleCollection, Source={x:Static local:App.Current}}">
        <ListBox.ContextMenu>
             <ContextMenu>
                   <MenuItem Command="{x:Static local:CustomCommands.MyCommand}"/>
              </ContextMenu>
        </ListBox.ContextMenu>
    </ListBox>
</ad:DockableContent>

次に、あなたが、浮動ウィンドウのような、内容をドラッグすると、コマンドは、正しく実行されます。 なぜなら、WPFは、親にドッキング可能な内容のCommandBindingsコレクションに、それが、ドラッグされるコマンド結合を見つけ出すことができます。

結論

結論として、あなたは、AvalonDockは、ユーザーが、それらをドラッグすると、 どんな結合も破壊して、内容を異なるウィンドウへ移動することに気づいています。 それは、親ウィンドウの論理ツリー構造に依存しています。 これは、もちろん、ウィンドウ・レベルのリソースで定義されるリンクのように、どんな形式の結合でも、問題を引き起すことができます。 (例えば、StaticResourceマークアップ式を使用します)。

これは、サンプル・プロジェクトです。:

AvalonDock.BindingSample.zip(外部サイト)

午後6時09分の2010年7月22日にadospaceにより、最後に編集された、version 9です。

このエントリーをはてなブックマークに追加

Home PC C# Illustration

Copyright (C) 2011 Horio Kazuhiko(kukekko) All Rights Reserved.
kukekko@gmail.com
ご連絡の際は、お問い合わせページのURLの明記をお願いします。
「掲載内容は私自身の見解であり、所属する組織を代表するものではありません。」