通用的可编辑标签

本文关键字:编辑 标签 | 更新日期: 2023-09-27 18:10:55

我正在实现一种在treeview中重命名元素的方法。我的想法不是建立一个特殊的TreeView,而是一个特殊的Label,也可以在ListBox和其他控件中使用。它通过点击将焦点设置为自身,所以我将Focusable更改为true。如果有焦点,它可以被[F2]编辑,当它被点击时已经有焦点。可编辑意味着,一个文本框显示(所有类似于Windows资源管理器)。不幸的是,当我单击label时,TreeViewItem没有被选中。当点击左边的图标时,TreeViewItem被选中。

我不处理任何事件设置Handled=true,但我认为Label本身处理点击,所以treeviewItem没有机会对它作出反应。如果我在这里,是否有一种方法来修改标签(自己的类?)的方式,它不处理事件?

通用的可编辑标签

我重新考虑了我的尝试。解决的办法是根本不要集中注意力。相反,我将一个处理程序绑定到当前具有焦点的观察元素的KeyUp事件(参见EditableLabel.cs中的注释)。

EditableLabel.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:myown.Wpf"
                    xmlns:localCtrls="clr-namespace:myown.Wpf.Controls">
    <Style TargetType="{x:Type localCtrls:EditableLabel}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type localCtrls:EditableLabel}">
                    <StackPanel>
                        <Label x:Name="label" 
                                            Content="{TemplateBinding Text}" 
                                            Visibility="Visible"
                                            Height="{TemplateBinding Height}"
                                            Width="{TemplateBinding Width}"
                                            Padding="{TemplateBinding Padding}"
                                            Foreground="{TemplateBinding Foreground}"/>
                        <!-- TemplateBinding is always OneWay! -->
                        <TextBox x:Name="textbox" 
                                 Text="{Binding Path=Text, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"  
                                 Visibility="Collapsed"
                                 Height="{TemplateBinding Height}"
                                 Width="{TemplateBinding Width}"
                                 Padding="{TemplateBinding Padding}"/>
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

EditableLabel.cs:

public partial class EditableLabel : Label
{
    #region DependencyProperties
    public static readonly DependencyProperty IsEditingProperty =
        DependencyProperty.Register("IsEditing", typeof(bool), typeof(EditableLabel),
        new UIPropertyMetadata(false, IsEditingUpdate));
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string), typeof(EditableLabel),
         new FrameworkPropertyMetadata("",
             FrameworkPropertyMetadataOptions.AffectsRender |
             FrameworkPropertyMetadataOptions.AffectsParentMeasure |
             FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    public bool IsEditing
    {
        get { return (bool)GetValue(IsEditingProperty); }
        set { SetValue(IsEditingProperty, value); }
    }
    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }
    private string m_lastValue = "";
    private IInputElement m_lastFocus = null;
    private Label m_label = null;
    private TextBox m_textBox = null;
    #endregion
    static EditableLabel()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(EditableLabel),
            new FrameworkPropertyMetadata(typeof(EditableLabel)));
    }
    public EditableLabel()
    {
        LostFocus += (s, e) => { };
        LostKeyboardFocus += EditableLabel_LostKeyboardFocus;
    }
    private void EditableLabel_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
    {
        if (e.NewFocus != null)
            Debug.WriteLine(e.NewFocus.GetType().Name);
    }
    public override void OnApplyTemplate()
    {
        m_label = GetTemplateChild("label") as Label;
        m_textBox = GetTemplateChild("textbox") as TextBox;
        m_label.MouseUp += Label_MouseUp;
        m_textBox.LostFocus += (s, e) => IsEditing = false;
        m_textBox.KeyUp += (s, e) => { TextBox_KeyUp(s, e); e.Handled = true; };
        m_textBox.GotKeyboardFocus += (s, e) => m_textBox.SelectAll();
        base.OnApplyTemplate();
    }
    private void Label_MouseUp(object sender, MouseButtonEventArgs e)
    {
        DependencyObject scope = FocusManager.GetFocusScope(this);
        IInputElement currFocus = FocusManager.GetFocusedElement(scope);
        if ((currFocus != null))
        {
            if (currFocus == m_lastFocus)
            {
                IsEditing = true;
            }
            else
            {
                m_lastFocus = currFocus;
                DependencyObject observedObject = currFocus as DependencyObject;
                if (observedObject != null)
                {
                    m_lastFocus.LostKeyboardFocus += ObservedElementLostFocus;
                    m_lastFocus.KeyUp += ObservedElement_KeyUp; // THIS IS THE TRICK
                }
            }
        }
    }
    private void ObservedElement_KeyUp(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.F2)
        {
            IsEditing = true;
            e.Handled = true;
        }
    }
    private void ObservedElementLostFocus(object sender, RoutedEventArgs e)
    {
        KeyboardFocusChangedEventArgs kfc = e as KeyboardFocusChangedEventArgs;
        if (kfc.NewFocus != null)
        {
            if ((kfc.NewFocus != m_textBox) && (kfc.NewFocus != m_lastFocus))
            {
                m_lastFocus.LostKeyboardFocus -= ObservedElementLostFocus;
                m_lastFocus.KeyUp -= ObservedElement_KeyUp;
                m_lastFocus = null;
            }
        }
    }
    private void TextBox_KeyUp(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Escape)
        {
            IsEditing = false;
            Text = m_lastValue;
        }
        else if (e.Key == Key.Enter)
        {
            IsEditing = false;
        }
    }
    private static void IsEditingUpdate(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        EditableLabel self = obj as EditableLabel;
        if ((bool)e.NewValue)
        {
            self.m_lastValue = self.Text;
            self.m_textBox.Visibility = Visibility.Visible;
            self.m_textBox.Focus();
            self.m_label.Visibility = Visibility.Collapsed;
        }
        else
        {
            self.m_textBox.Visibility = Visibility.Collapsed;
            self.m_label.Visibility = Visibility.Visible;
            if (self.m_lastFocus != null)
                self.m_lastFocus.Focus();
        }
    }
}