2011-07-05 11 views
2

私は、ユーザーがTreeView内のノードの名前を変更できるTreeViewを作成しようとしています。ツリーはHL7メッセージを表し、階層からサブコンポーネントに構造化されています。WPF TreeView SelectedItemChanged not firing

例えば:

PID 
    PID.1 
    PID.2 
    etc... 

私は、ユーザーが編集モードにノードを配置するノード、F2キーを押しを選択できるようにする必要があります。 HL7はメッセージ構造を繰り返すことができるので、重複した名前が存在する場合にどのノードが変更されたのか知ることができるようにSelectedItemも必要です。

現在、各ノードはIsReadOnlyがTrueに設定されたTextBoxで、TextBlockのようにスタイルが設定されています。ユーザーがF2キーを押すと、TextBoxが通常入力と同じようにスタイルが設定されます。問題は、TextBoxがTreeBoxがSelectedItemを設定したり、SelectedItemChangedを発生させないように、すべてのマウスイベントを食べていることです。

MSDNで、TextBoxでPreviewMouseLeftButtonDownイベントを使用すると言われている人がいます。私はそれを使用して、TextBoxはまだイベントを消費しています。

誰もこれまでにこれに遭遇したことがありますか、または何か提案がありますか?

+1

解決策が見つかりました。私はまだどこでもこれを見つけることができなかったことに驚いています。 バインディングを使用している場合は、GotFocusまたはPreviewMouseLeftButtonDownイベントを処理し、送信者をTextBoxとしてローカルオブジェクトにキャストします。そこから、テキストボックスオブジェクトのDataContextメンバにアクセスできます。これは、TreeViewItemにバインドされたデータオブジェクトを表します。 – Josh

答えて

0

もう1つの方法は、表示用のTextBlockと編集用の非表示のTextBoxです。 TextBoxが隠されている間に入力フォーカスを取得しないので、キーボードイベントを受け取るTreeViewでF2を聞きます。 F2キーを押すと、TextBlockを非表示にしてTextBoxを編集用に表示します。 TextBoxを非表示にしてTextBlockを再度表示するには、TextBoxのLostFocusイベントを処理します。

このようにすることの利点の1つは、 TextBoxをTextBlockのように見て動作させることです。 TextBlockは常にTextBlockのように見え、動作し、TextBoxは常にTextBoxのように見え、動作し、より高いリソースレベルで適用されたすべてのスタイルを継承することができます。

編集:サンプルコードを追加してください。

private void treeView1_KeyUp(object sender, KeyEventArgs e) 
{ 
    if (e.Key == Key.F2) 
    { 
     HL7Object selectedHL7Object = treeView1.SelectedItem as HL7Object; 
     if (selectedHL7Object != null) 
     { 
      selectedHL7Object.InEditMode = true; 
     } 
    } 
} 

private void TreeViewTextBox_LostFocus(object sender, RoutedEventArgs e) 
{ 
    HL7Object selectedHL7Object = treeView1.SelectedItem as HL7Object; 
    if (selectedHL7Object != null) 
    { 
     selectedHL7Object.InEditMode = false; 
    } 
} 

このコードは、次のような、あなたのHL7Objectは、データオブジェクトの基本クラスである前提としています:

ここ
<Window.Resources> 

    <Style x:Key="TreeViewTextBlockStyle" TargetType="TextBlock"> 
     <Setter Property="Text" Value="{Binding DisplayText}"/> 
     <Style.Triggers> 
      <DataTrigger Binding="{Binding InEditMode}" Value="true"> 
       <Setter Property="Visibility" Value="Collapsed"/> 
      </DataTrigger> 
     </Style.Triggers> 
    </Style> 

    <Style x:Key="TreeViewTextBoxStyle" TargetType="TextBox"> 
     <Setter Property="Text" Value="{Binding DisplayText, Mode=TwoWay}"/> 
     <Setter Property="MinWidth" Value="50"/> 
     <EventSetter Event="LostFocus" Handler="TreeViewTextBox_LostFocus" /> 
     <Style.Triggers> 
      <DataTrigger Binding="{Binding InEditMode}" Value="false"> 
       <Setter Property="Visibility" Value="Collapsed"/> 
      </DataTrigger> 
      <DataTrigger Binding="{Binding InEditMode}" Value="true"> 
       <Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Mode=Self}}"/> 
      </DataTrigger> 
     </Style.Triggers> 
    </Style> 

    <HierarchicalDataTemplate x:Key="HL7MessageTemplate" ItemsSource="{Binding Segments}"> 
     <StackPanel Orientation="Horizontal"> 
      <TextBlock Text="[msg]--" FontWeight="Bold"/> 
      <TextBlock Style="{StaticResource TreeViewTextBlockStyle}"/> 
      <TextBox Style="{StaticResource TreeViewTextBoxStyle}" /> 
     </StackPanel> 
    </HierarchicalDataTemplate> 

    <DataTemplate x:Key="HL7SegmentTemplate"> 
     <StackPanel Orientation="Horizontal"> 
      <TextBlock Text="[seg]--" FontWeight="Bold"/> 
      <TextBlock Style="{StaticResource TreeViewTextBlockStyle}"/> 
      <TextBox Style="{StaticResource TreeViewTextBoxStyle}" /> 
     </StackPanel> 
    </DataTemplate> 

    <HierarchicalDataTemplate x:Key="HL7SegmentWithSubcomponentsTemplate" ItemsSource="{Binding Subcomponents}"> 
     <StackPanel Orientation="Horizontal"> 
      <TextBlock Text="[seg+sub]--" FontWeight="Bold"/> 
      <TextBlock Style="{StaticResource TreeViewTextBlockStyle}"/> 
      <TextBox Style="{StaticResource TreeViewTextBoxStyle}" /> 
     </StackPanel> 
    </HierarchicalDataTemplate> 

    <DataTemplate x:Key="HL7SubcomponentTemplate"> 
     <StackPanel Orientation="Horizontal"> 
      <TextBlock Text="[sub]--" FontWeight="Bold"/> 
      <TextBlock Style="{StaticResource TreeViewTextBlockStyle}"/> 
      <TextBox Style="{StaticResource TreeViewTextBoxStyle}" /> 
     </StackPanel> 
    </DataTemplate> 

    <local:HL7DataTemplateSelector x:Key="HL7DataTemplateSelector"/> 

</Window.Resources>  
<Grid> 
    <TreeView Name="treeView1" ItemsSource="{Binding}" ItemTemplateSelector="{StaticResource HL7DataTemplateSelector}" KeyUp="treeView1_KeyUp"/> 
</Grid> 

が背後にあるコードである:ここでは

はXAMLです
public class HL7Object : INotifyPropertyChanged 
{ 
    private string DisplayTextField; 
    public string DisplayText 
    { 
     get { return this.DisplayTextField; } 
     set 
     { 
      if (this.DisplayTextField != value) 
      { 
       this.DisplayTextField = value; 
       this.OnPropertyChanged("DisplayText"); 
      } 
     } 
    } 

    private bool InEditModeField = false; 
    public bool InEditMode 
    { 
     get { return this.InEditModeField; } 
     set 
     { 
      if (this.InEditModeField != value) 
      { 
       this.InEditModeField = value; 
       this.OnPropertyChanged("InEditMode"); 
      } 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

また、DataTemplateSelectorを実装していると思いますあなたの複雑な要件のそうでない場合は、ここに例があります:

public class HL7DataTemplateSelector : DataTemplateSelector 
{ 
    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     FrameworkElement element = container as FrameworkElement; 

     if (element != null && item != null && 
      (item is HL7Message || item is HL7Segment || item is HL7Subcomponent) 
      ) 
     { 
      HL7Message message = item as HL7Message; 
      if (message != null) 
      { 
       return element.FindResource("HL7MessageTemplate") as DataTemplate; 
      } 

      HL7Segment segment = item as HL7Segment; 
      if (segment != null) 
      { 
       if (segment.Subcomponents != null && segment.Subcomponents.Count > 0) 
       { 
        return element.FindResource("HL7SegmentWithSubcomponentsTemplate") as DataTemplate; 
       } 
       else 
       { 
        return element.FindResource("HL7SegmentTemplate") as DataTemplate; 
       } 
      } 

      HL7Subcomponent subcomponent = item as HL7Subcomponent; 
      if (subcomponent != null) 
      { 
       return element.FindResource("HL7SubcomponentTemplate") as DataTemplate; 
      } 
     } 

     return null; 
    } 
} 
+0

残念ながら、このソリューションは私の場合は動作しませんでした。ツリー内でのネストの複雑さのため、複数の階層データテンプレートをツリービューリソースに配置する必要がありました。彼らはtreeview itemtemplateになかったので、私はテキストブロックまたはテキストボックスを見つけることができませんでした。 ツリービューのitemtemplateで1つの階層データテンプレートを使用していたとしても、IsReadOnly用にスタイルされたテキストボックスをTextBlockのようなスタイルにして、2番目のフィールドを維持するオーバーヘッドがないため、それは他人のために働くので、私はそれを答えとして受け入れます。 – Josh

+0

実際には、treeView.ItemContainerGenerator.ContainerFromItem(treeView.SelectedItem)を使用してtextblock/textboxを検索し、VisualTreeHelperを使用してビジュアルツリーを歩くことは可能ですが、WPF StylingとTemplatingを有効に使用すると、それらを見つける必要はありません(I上記の答えにサンプルコードを追加します)。また、2つ目のフィールドを維持する必要はなく、両方のコントロールを同じプロパティにデータバインドするだけです。 –