WPF TreeView SelectedItemChanged无法触发 [英] WPF TreeView SelectedItemChanged not firing

查看:99
本文介绍了WPF TreeView SelectedItemChanged无法触发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to create a TreeView which allows the user to rename the nodes in the TreeView. The tree represents an HL7 message and is structured from segment to subcomponent hierarchically.

例如:

PID
   PID.1
   PID.2
   etc...

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

I need to allow the user to select a node, press F2 to put the node into edit mode. Because HL7 allows repeating message structures, I also need the SelectedItem so I can know which node was changed in case duplicate names exist.

当前,每个节点都是一个具有IsReadOnly的TextBox。设置为true,样式化为类似于TextBlock。当用户按下F2时,我将TextBox样式化,使其看起来通常与输入相同。问题是,TextBox正在吃掉所有鼠标事件,从而阻止TreeView设置SelectedItem或提高SelectedItemChanged。

Currently, each node is a TextBox with IsReadOnly set to true and is stylized to look like a TextBlock. When the user presses F2, I stylize the TextBox to look like it normally does for input. The problem is, the TextBox is eating all the mouse events preventing the TreeView from setting SelectedItem or raising SelectedItemChanged.

我在MSDN上进行了一些讨论,其中有人说使用PreviewMouseLeftButtonDown事件在TextBox上。我正在使用它,而TextBox仍在使用该事件。

I found some discussion on MSDN where one person says use the PreviewMouseLeftButtonDown event on the TextBox. I'm using that and the TextBox is still consuming the event.

有人以前遇到过这个问题或有任何建议吗?

Has anyone run into this before or have any suggestions?

推荐答案

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

Another way is to have a TextBlock for display and a hidden TextBox for editing. Listen for F2 on the TreeView which will receive the keyboard events since the TextBox won't be getting any input focus while it is hidden. When F2 is pressed, hide the TextBlock and show the TextBox for editing. Handle the LostFocus event on the TextBox to hide the TextBox and show the TextBlock again.

以这种方式进行操作的优点之一是您不必 fake 一个TextBox看起来像一个TextBlock。 TextBlock始终具有类似于TextBlock的外观和行为,而TextBox始终具有类似于TextBox的外观和行为,它们每个都将能够继承在较高资源级别应用的任何样式。

One advantage of doing it this way is you don't have to fake a TextBox into looking and behaving like a TextBlock. The TextBlock will always look and behave like a TextBlock and the TextBox will always look and behave like a TextBox, and they will each be able to inherit any styling applied at a higher resource level.

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

Adding some sample code.

这里是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是您的基类数据对象,例如:

This code assumes your HL7Object is the base class for your data objects, such as the following:

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,由于您的复杂要求,我认为您拥有它。如果不是,请参见以下示例:

And also that you have implemented a DataTemplateSelector, which I assume you have because of your complex requirements. If not, here is an example:

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

这篇关于WPF TreeView SelectedItemChanged无法触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆