原文
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'メニューをクリックします。:
すべてが、正常に動作するようです。しかし、あなたが、ドッキング可能な内容を、外側にドラッグしようとする場合、 浮動ウィンドウの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です。