2011-07-05 3 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를 발생시키는 것을 방지하는 모든 마우스 이벤트를 먹고 있다는 것입니다.

한 사람이 TextBox에서 PreviewMouseLeftButtonDown 이벤트를 사용한다고하는 MSDN에 대한 토론이있었습니다. 나는 그것을 사용하고 있으며 TextBox는 여전히 이벤트를 소비하고 있습니다.

이전에이 문제를 겪거나 제안 사항이있는 사람이 있습니까?

+1

해결책을 찾았습니다. 나는 이것이 아직 어느 곳에서도 찾을 수 없었던 것에 놀랐다. 어쨌든 바인딩을 사용하는 경우 GotFocus 또는 PreviewMouseLeftButtonDown 이벤트를 처리하고 보낸 사람을 TextBox로 캐스팅하여 로컬 개체로 만듭니다. 그로부터 텍스트 상자 개체의 DataContext 멤버에 액세스 할 수 있습니다. 이것은 TreeViewItem에 바인드 된 데이터 객체를 나타냅니다. – Josh

답변

0

또 다른 방법은 표시 할 TextBlock과 편집을위한 숨겨진 TextBox를 만드는 것입니다. TextBox가 숨겨져있는 동안 입력 포커스를 얻지 못할 것이므로 키보드 이벤트를받을 TreeView에서 F2를 들어보십시오. F2 키를 누르면 TextBlock을 숨기고 편집을 위해 TextBox를 표시합니다. TextBox를 숨기고 TextBlock을 다시 표시하려면 TextBox에서 LostFocus 이벤트를 처리하십시오.

이런 식으로하는 것의 한 가지 이점은 가짜 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에 없었기 때문에 textblock이나 textbox를 찾을 수 없었다. treeview itemtemplate에서 하나의 계층 적 데이터 템플릿을 사용하고 있어도 IsReadOnly에 대한 스타일이 TextBlock 인 텍스트 상자를 사용하고 있기 때문에 두 번째 필드를 유지 관리하는 오버 헤드가 없기 때문에 내가 찾은 솔루션을 선호합니다. 다른 사람들에게도 도움이 될 것이므로 대답으로 받아 들일 것입니다. – Josh

+0

실제로 treeView.ItemContainerGenerator.ContainerFromItem (treeView.SelectedItem)을 사용하여 textblock/textbox를 찾고 VisualTreeHelper를 사용하여 시각적 트리를 보면서 WPF Styling 및 Templating을 효과적으로 사용하면 _find_ 할 필요가 없습니다. 위의 대답에 몇 가지 샘플 코드를 추가합니다). 또한 두 번째 필드를 유지할 필요가 없으며 두 컨트롤을 동일한 속성에 데이터 바인딩하기 만하면됩니다. –