代码之家  ›  专栏  ›  技术社区  ›  15ee8f99-57ff-4f92-890c-b56153

当父级可见时,如何将键盘焦点设置为子级?

  •  0
  • 15ee8f99-57ff-4f92-890c-b56153  · 技术社区  · 6 年前

    我有一个 ListBox 具有可编辑项。第一次编辑项目时,编辑控件(A TextBox 在这个最小的例子中)最初有键盘焦点。第二次编辑项目时, 文本框 没有键盘焦点。如果测试代码,则通过选择项目并按F2或RETURN将其置于编辑模式。

    有没有什么合理直接的方法 文本框 当键盘变为可见时总是获得焦点?如果不能做到这一点,是否存在一种不合理或间接的可靠工作方式?

    一直使用编辑模板是不可行的,因为真正的编辑模板包括很多东西,例如300像素高 列表框 有一千种选择,以及 文本框 用于筛选 列表框 . 我试着用 CellTemplate A的 DevExpress网格控件 但那是一罐蠕虫,原因多种多样。

    我交替显示/隐藏两个内容控件的原因是,当我将不同的模板交换到 ListBox.ItemTemplate ,焦点被传递到窗口。

    XAML:

    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>
    <Grid>
        <ListBox
            ItemsSource="{Binding Items}"
            >
            <ListBox.Resources>
                <DataTemplate x:Key="DisplayTemplate">
                    <Label Content="{Binding Value}" />
                </DataTemplate>
                <DataTemplate x:Key="EditTemplate">
                    <WrapPanel FocusManager.FocusedElement="{Binding ElementName=TextBox}" Focusable="False">
                        <Label>Editing:</Label>
                        <TextBox Margin="4,2,2,2" Text="{Binding Value}" x:Name="TextBox" />
                    </WrapPanel>
                </DataTemplate>
            </ListBox.Resources>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <ContentControl x:Name="Display" Content="{Binding}" ContentTemplate="{StaticResource DisplayTemplate}" />
                        <ContentControl x:Name="Edit" Content="{Binding}" ContentTemplate="{StaticResource EditTemplate}" Visibility="Collapsed" />
                    </Grid>
                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding IsEditing}" Value="True">
                            <Setter TargetName="Edit" Property="Visibility" Value="Visible" />
                            <Setter TargetName="Display" Property="Visibility" Value="Collapsed" />
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>
            </ListBox.ItemTemplate>
            <ListBox.ItemContainerStyle>
                <Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">
                    <EventSetter Event="KeyDown" Handler="ListBoxItem_KeyDown" />
                </Style>
            </ListBox.ItemContainerStyle>
        </ListBox>
    </Grid>
    

    VIEW模型

    public class ViewModel : ViewModelBase
    {
        public ViewModel()
        {
            Items = new ObservableCollection<ItemViewModel>(
                new[] { "ytesadamy", "ugexudunamo", "wovaxatytol", "imuq" }.Select(s => new ItemViewModel() { Value = s }));
        }
    
        public ObservableCollection<ItemViewModel> Items { get; private set; }
    }
    
    public class ItemViewModel : ViewModelBase
    {
        #region Value Property
        private String _value = default(String);
        public String Value
        {
            get { return _value; }
            set
            {
                if (value != _value)
                {
                    _value = value;
                    OnPropertyChanged();
                }
            }
        }
        #endregion Value Property
    
        #region IsEditing Property
        private bool _isEditing = default(bool);
        public bool IsEditing
        {
            get { return _isEditing; }
            set
            {
                if (value != _isEditing)
                {
                    _isEditing = value;
                    OnPropertyChanged();
                }
            }
        }
        #endregion IsEditing Property
    }
    
    #region ViewModelBase Class
    public class ViewModelBase : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propName = null) =>
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        #endregion INotifyPropertyChanged
    }
    #endregion ViewModelBase Class
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   15ee8f99-57ff-4f92-890c-b56153    6 年前

    我通常会这样做:

    public static class FocusOnVisibleBehavior
    {
        public static readonly DependencyProperty FocusProperty = DependencyProperty.RegisterAttached(
            "Focus",
            typeof(bool),
            typeof(FocusOnVisibleBehavior),
            new PropertyMetadata(false, OnFocusChange));
    
        public static void SetFocus(DependencyObject source, bool value)
        {
            source.SetValue(FocusProperty, value);
        }
    
        public static bool GetFocus(DependencyObject source)
        {
            return (bool)source.GetValue(FocusProperty);
        }
    
        private static void OnFocusChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var element = d as FrameworkElement;
            DependencyPropertyChangedEventHandler handler = (sender, args) =>
            {
                if ((bool)args.NewValue)
                {
                    // see http://stackoverflow.com/questions/13955340/keyboard-focus-does-not-work-on-text-box-in-wpf
                    element.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(delegate()
                    {
                        element.Focus();         // Set Logical Focus
                        Keyboard.Focus(element); // Set Keyboard Focus
                        //element.SelectAll();
                    }));
    
                }
            };
    
            if (e.NewValue != null)
            {
                if ((bool)e.NewValue)
                {
                    element.IsVisibleChanged += handler;
                    element.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(delegate ()
                    {
                        element.Focus();         // Set Logical Focus
                        Keyboard.Focus(element); // Set Keyboard Focus
                                                 //element.SelectAll();
                    }));
                }
                else
                {
                    element.IsVisibleChanged -= handler;
                }
            }
    
            //  e.OldValue is never null because it's initialized to false via the PropertyMetadata()
            //  Hence, the effect here is that regardless of the value that's set, we first add the 
            //  handler and then immediately remove it. 
            //if (e.NewValue != null)
            //{
            //    element.IsVisibleChanged += handler;
            //    element.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(delegate ()
            //    {
            //        element.Focus();         // Set Logical Focus
            //        Keyboard.Focus(element); // Set Keyboard Focus
            //                                 //element.SelectAll();
            //    }));
            //}
            //if (e.OldValue != null)
            //    element.IsVisibleChanged -= handler;
        }
    

    不记得我是自己写的还是从其他地方得到的,不管你是这样使用的:

    <TextBox behaviors:FocusOnVisibleBehavior.Focus="True" ... etc ... />
    
    推荐文章