WPF TreeView SelectedItemChanged没有触发

时间:2011-07-05 17:25:28

标签: .net wpf c#-4.0

我正在尝试创建一个TreeView,它允许用户重命名TreeView中的节点。树表示HL7消息,并且从分段到子组件分层结构。

例如:

PID
   PID.1
   PID.2
   etc...

我需要允许用户选择节点,按F2键将节点置于编辑模式。因为HL7允许重复消息结构,所以我还需要SelectedItem,这样我就知道在存在重复名称的情况下哪个节点被更改了。

目前,每个节点都是一个TextBox,其IsReadOnly设置为true,并被设计为看起来像TextBlock。当用户按下F2时,我将TextBox设置为看起来像通常用于输入的样式。问题是,TextBox正在吃掉所有鼠标事件,阻止TreeView设置SelectedItem或者提升SelectedItemChanged。

我在MSDN上找到了一些讨论,其中一个人说在TextBox上使用PreviewMouseLeftButtonDown事件。我正在使用它,TextBox仍在使用该事件。

有没有人遇到此问题或有任何建议?

1 个答案:

答案 0 :(得分:0)

另一种方法是使用TextBlock进行显示,使用隐藏的TextBox进行编辑。在TreeView上收听F2,它将接收键盘事件,因为TextBox在隐藏时不会获得任何输入焦点。按下F2时,隐藏TextBlock并显示TextBox以进行编辑。处理TextBox上的LostFocus事件以隐藏TextBox并再次显示TextBlock。

这样做的一个好处是你不必将伪造一个TextBox变成一个看起来像TextBlock一样的行为。 TextBlock的外观和行为总是像TextBlock一样,TextBox的外观和行为总是像TextBox一样,它们每个都能够继承在更高资源级别应用的任何样式。

编辑:添加一些示例代码。

这是XAML:

<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>

这是背后的代码:

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是数据对象的基类,如下所示:

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;
    }
}