在焦点范围内使用ListBox

时间:2012-01-05 14:38:52

标签: c# wpf listbox focus user-experience

短篇小说:焦点范围内的ListBox不允许选择项目。

长篇故事:

我正在尝试为数据输入创建一个上下文相关的小部件。我有几个领域的主面板。在此之下,我有一个FocusManager.FocusScope="True"的面板。此面板将填充当前具有焦点的字段的相关窗口小部件。例如,选择日期字段会在屏幕底部显示日历。

我有几个控件要求用户从列表中选择多个值中的一个。我将一个ListBox放入焦点范围,但我无法选择任何项目。当选择某些内容(以编程方式)并单击ListBox时,它会取消选择所有内容。

我测试了一些事件,它没有拾取MouseDown事件,但它正在拾取MouseMove事件。每当我点击一个项目时它就会触发GotFocus,但它永远不会触发LostFocus。我不确定这意味着什么,但我希望这对读这篇文章的人有所帮助。

以下是我用来显示上下文相关小部件的代码。我的窗口中有以下XAML:

<Grid x:Name="EntryWidget" FocusManager.IsFocusScope="True">
    <Grid.Resources>
        <ListBox x:Key="List" ItemsSource="{Binding}" />
    </Grid.Resources>
</Grid>

我使用Window.GotFocus路由事件将窗口小部件更新为适当的控件,如下所示:

private void Window_GotFocus(object sender, RoutedEventArgs e)
{
    FrameworkElement focus = (FrameworkElement)FocusManager.GetFocusedElement(this);
    EntryWidget.Children.Clear(); // Could this be the culprit?
    object tag = focus.Tag;
    if (tag != null)
    {
        if (EntryWidget.Resources.Contains(tag))
        {
            EntryWidget.Children.Add(EntryWidget.Resources[tag] as UIElement);
        }
    }
}

所以:

  1. 有没有办法让ListBox在焦点范围内工作?

  2. 或者是否有另一个列表控件在焦点范围内更好地工作?

  3. 或者我使用焦点范围采取了错误的方法?我的要求:用户必须能够从可滚动列表中选择一个项目,该列表将把值输入当前字段。当前字段不应失去焦点。

2 个答案:

答案 0 :(得分:2)

我的回答是不使用焦点范围

你有点挫败了焦点的目的。如果有人不能使用鼠标并想要使用键盘怎么办?

为什么不在列表中选择然后将焦点设置回原始控件,而不是使用焦点范围完成所有这些额外工作?

答案 1 :(得分:1)

单击ListBox或其包含的项目时,您将应用程序的键盘焦点设置为ListBox。无论您定义的焦点范围如何,都会发生这种情况。

可以为 upper 面板(包含字段的面板)定义焦点范围,并将ListBox的SelectionChanged设置焦点设置到上面板,这将实际设置在单击任何ListBox项之前,将焦点放在该面板中聚焦的项目上。

<StackPanel>
    <StackPanel x:Name="upperPanel" FocusManager.IsFocusScope="True" GotFocus="upperPanel_GotFocus">
        <TextBox x:Name="TextBox1"></TextBox>
        <TextBox x:Name="TextBox2"></TextBox>
    </StackPanel>
    <StackPanel>
        <ListBox x:Name="ListBox1" SelectionChanged="ListBox_SelectionChanged">
            <ListBoxItem>First</ListBoxItem>
            <ListBoxItem>Second</ListBoxItem>
            <ListBoxItem>Third</ListBoxItem>
        </ListBox>

        <ListBox x:Name="ListBox2" SelectionChanged="ListBox_SelectionChanged">
            <ListBoxItem>4</ListBoxItem>
            <ListBoxItem>5</ListBoxItem>
            <ListBoxItem>6</ListBoxItem>
        </ListBox>
    </StackPanel>
</StackPanel>

private IInputElement focusedElement = null;

private void upperPanel_GotFocus(object sender, RoutedEventArgs e)
{
    focusedElement = e.Source as IInputElement;
}

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    UpdateTextBoxValue((e.AddedItems[0] as ListBoxItem).Content.ToString());
}

private void UpdateTextBoxValue(string text)
{
    TextBox focusedTextBox = focusedElement as TextBox;
    if (focusedTextBox != null)
    {
        focusedTextBox.Text = text;
    }

    upperPanel.Focus();
}

upperPanel范围内当前活动的控件由GotFocus事件处理程序保持最新,UpdateTextBoxValue方法负责设置活动文本TextBox控制并将焦点设置回来。

我假设你熟悉我使用的术语(键盘焦点/逻辑焦点);如果没有,你可以查看Focus Overview或者你可以问。