2016-10-03 4 views
0

今朝私はhereという質問をしました。単純な作業サンプルを実行すると、予想外の動作が起こりました。なぜDataBindingがUserControlに伝播しないのですか

GitHubで全作業サンプル。下の主な部分コード。

この場合、UserControlがWindowの子として直接使用されている場合でも、このコマンドはどのUserControlにも伝播されません。 UserControlがListBox ItemTemplateのDataTemplateとして使用されている場合、これも機能しません。

また、CommandがUserControlsに到達する問題を解決するためのハックボタンが含まれています。ハックはStackOverflowです。

しかし、なぜUserControlが(それなしで)コマンドを受け取っていないし、このハックを使用して良いコーディングの最初のルールを破る: "こんにちは凝集力と低結合"ハックを説明しません。ハックは、UserControlでコマンドを管理するために、ウィンドウコードで使用する必要があります、私の考えは、デフォルトで起こるはずです。

コマンドがデフォルトでUserControlに伝播していないのはなぜですか。コマンドを明確にUserControlに伝播するにはどうすればよいですか?

注:UserControlでCommandBindingを1つだけ使用すると、いずれかを削除しても問題は解決されません。

部分コード:

<Window x:Class="CommandRoutingIntoItemTemplate.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:CommandRoutingIntoItemTemplate" 
     xmlns:system="clr-namespace:System;assembly=mscorlib" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition></RowDefinition> 
      <RowDefinition></RowDefinition> 
      <RowDefinition Height="Auto"></RowDefinition> 
     </Grid.RowDefinitions> 

     <local:UserControlTest></local:UserControlTest> 

     <ListBox Grid.Row="1"> 
      <ListBox.ItemTemplate> 
       <DataTemplate> 
        <Border BorderBrush="Aqua" BorderThickness="2"> 
         <local:UserControlTest></local:UserControlTest> 
        </Border> 
       </DataTemplate> 
      </ListBox.ItemTemplate> 

      <ListBox.Items> 
       <system:String>1</system:String> 
       <system:String>2</system:String> 
      </ListBox.Items> 
     </ListBox> 

     <StackPanel Grid.Row="2" Orientation="Horizontal"> 
      <Button Command="local:Commands.CommandTest">Put focus on TestBlock and click here to see if command occurs</Button> 
      <Button Click="AddHack">Hack</Button> 
     </StackPanel> 
    </Grid> 
</Window> 

ユーザーコントロール:あなたのユーザーコントロール上で呼び出されたコマンドを取得されていません

<UserControl x:Class="CommandRoutingIntoItemTemplate.UserControlTest" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:CommandRoutingIntoItemTemplate" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <UserControl.CommandBindings> 
     <CommandBinding Command="local:Commands.CommandTest" CanExecute="CommandTestCanExecuteUserControl" Executed="CommandTestExecuteUserControl"></CommandBinding> 
    </UserControl.CommandBindings> 
    <Grid> 
     <TextBox Text="UserControlTest"> 
      <TextBox.CommandBindings> 
       <CommandBinding Command="local:Commands.CommandTest" CanExecute="CommandTestCanExecuteTextBox" Executed="CommandTestExecuteTextBox"></CommandBinding> 
      </TextBox.CommandBindings> 
     </TextBox> 
    </Grid> 
</UserControl> 

答えて

1

理由は、あなたのボタンが独立したフォーカス範囲に含まれていないということです。 WPFがコマンドターゲットのフォーカスされた要素を正しくピックアップするには、コマンド呼び出しコントロールとは別のフォーカススコープにある必要があります。

フレームワークはボタンからビジュアルツリーをたどって、フォーカス範囲内のコマンドバインディングを探します(あなたの場合は見つからない)。フレームワークが現在のフォーカススコープ内でコマンドバインディングを見つけられなかった場合にのみ、フォーカスされた要素の親フォーカススコープが表示されます(ボタンはWindowフォーカススコープにあり、親スコープは存在しません)。

StackPanelFocusManager.IsFocusScope="True"と設定するだけで問題が解決されます。

ボタンにCommandTargetプロパティを指定して、ユーザーコントロールをポイントし、フォーカスに頼ることもできます。

+0

すばらしい説明!どうもありがとうございます!完璧に動作します。 UserControl側で何かを行うことができるかどうかを知っていますか?今は問題なく動作しますが、私はUserControlを別の場所で使用したいと思っています。すべての状況で適切な使用を保証するために、1つの共通の場所(UserControl)にコードを書くより良い解決策と聞こえますか? –

+0

私もmenuItemでテストしましたが、これはおそらくMenu要素が私に提案した修正を持っているためうまくいきます:FocusManager.IsFocusScopeがtrueに設定されていますか?それは私が知って覚えなければならないものです;-)? –

+0

@EricOuelletそれはまさに正しいことです。 MenuItemsは、独自のフォーカススコープを持つポップアップで表示されます。 – ghord

関連する問題