【问题标题】:Making UserControls accessible in WPF使用户控件在 WPF 中可访问
【发布时间】:2012-03-23 21:48:27
【问题描述】:

我有一个 WPF 表单,它由两列网格组成。

左列是控件标签,右列是我的控件。

这些控件都是用户控件。在最简单的情况下,其中一些控件只是简单地包装现有的 WPF 控件(例如文本框),以便它们都实现一个通用接口。

生成表单时,我有这样的代码来设置关联控件的标签,其中 newControl 是创建的 UserControl 和 ctl.Caption 只是返回所需的标签文本:

Label newLabel = new Label();
newLabel.Content = ctl.Caption + ":";
newLabel.Target = newControl;

一个问题是设置目标实际上不起作用。如果标题中有下划线,则助记键不会将焦点设置到包装控件。一种解决方法可能是手动将焦点设置到 UserControl 代码中的包装控件 - 但是...

最大的问题是可访问性。 JAWS 和 Windows 内置讲述人等屏幕阅读器在控件获得焦点时不会读取控件标题。

我看过这个:http://msdn.microsoft.com/en-us/library/windows/desktop/gg712258.aspx - 它提供了很多细节,但没有有用的示例。它有很多关于 custom 控件的内容,这对于简单的 user 控件来说肯定是多余的吗?

那么,我怎样才能将我的标签正确地“附加”到我的用户控件上?

您可以在http://quest.codeplex.com/SourceControl/changeset/view/676933506953 浏览整个项目的代码 - 特定代码在 EditorControls 项目中,而 UserControls 在 ElementEditor.xaml.cs 中实例化。

【问题讨论】:

  • 我会使用装饰器模式,因为它允许您在 XAML 中“包装”控件(即不必创建自定义控件)。我将在今天晚些时候下班后发布一个示例。

标签: wpf user-controls accessibility


【解决方案1】:

您的 newControl 属于 Control 类型,不允许您添加其他内容。 如果要向其中添加一些内容,则需要使用支持它的类,例如 ContentControl 或 Panel(用于多个子项),您可以实现自己的实现 IAddChild 接口的控件。

一个简单的解决方案可能是:

<UserControl x:Class="UIMocks.MyCustomControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <StackPanel x:Name="content"/>
</UserControl>

代码隐藏

[ContentProperty("Children")]
public partial class MyCustomControl : UserControl
{
    public MyCustomControl()
    {
        InitializeComponent();
    }

    public UIElementCollection Children { get { return content.Children; } }
}

然后你就可以使用了

MyCustomControl newControl = InitialiseEditorControl(ctl);
...
Label newLabel = new Label();
newLabel.Content = ctl.Caption + ":";
newControl.Children.Add(newLabel);

【讨论】:

  • AddChild 在 ContentControl 上受到保护,因此无法在我的 AddControlToGrid 函数中访问。并且不能将 UserControl 强制转换为 Panel。此外,从文档中可以看出 IAddChild 在 .net 4 中已被弃用。
  • 你说得对,IAddChild 现在已经过时了,它已被 e ContentProperty 属性所取代。感谢您提出来。而且我并不是说他应该将他的用户控件转换为 Panel,只是说他可以使用具有像 Panel 这样的内容的控件(这是抽象的,不能直接使用)
【解决方案2】:

嗯,我试图在一个小型测试项目中重现您的问题,但对我来说它有效......所以我想您必须提供有关如何构建 userControls 的更多详细信息。这对我有用:

我创建了一个 Empty 项目(像往常一样只是 App 和 Window 文件)并在我的窗口中设置了一个包含 2 列的网格:

<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Name="Window"
        SizeToContent="WidthAndHeight">

    <Grid Name="MyGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100" />
            <ColumnDefinition Width="100"/>
        </Grid.ColumnDefinitions>
    </Grid>

</Window>

然后创建了一个扩展 wpf TextBox 类的 userControl:

<TextBox x:Class="Test.MyTextBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">

</TextBox>

和:

使用 System.Windows; 使用 System.Windows.Controls;

namespace Test
{
    public partial class MyTextBox : TextBox
    {
        public static readonly DependencyProperty CaptionProperty =
             DependencyProperty.Register("Caption", typeof(string), typeof(MyTextBox), new UIPropertyMetadata(""));
        public string Caption
        {
            get { return (string)GetValue(CaptionProperty); }
            set { SetValue(CaptionProperty, value); }
        }

        public MyTextBox()
        {
            InitializeComponent();
        }
    }
}

它基本上是一个带有“标题”dp 的文本框。

现在在我窗口的代码后面:

public MainWindow()
{
    InitializeComponent();

    MyTextBox tb = new MyTextBox { Caption = "_Foo", Width = 100 };
    Label lb = new Label { Content = tb.Caption + ":", Target = tb };

    MyGrid.Children.Add(lb);
    MyGrid.Children.Add(tb);

    Grid.SetColumn(lb, 0);
    Grid.SetColumn(tb, 1);
}

有了这个,当我按下 ALT + F 时,我确实将注意力集中在 TB 上(当我按下 ALT 时,我什至可以看到标签中“Foo”的 F 下的 _)

所以我猜你的问题与你的 UserControls 本身以及它们是如何构建的(例如什么模板)有关

编辑:

如果您的控件不是扩展现有控件而是包含 WPF 控件,则问题可能出在 Focus 方法上。您应该添加一个 Focus() 方法,当控件本身获得焦点时,该方法将焦点设置在控件的右侧。

代码(例如,对于包含要获得焦点的文本框的 UserControl):

<TextBox x:Class="Test.MyTextBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <Button Content="foo" Grid.Column="0" />
        <TextBox Name="TextBoxPart" Grid.Column="1" />
    </Grid> 

</TextBox>

后面的代码

public partial class MyTextBox : TextBox
{
    public static readonly DependencyProperty CaptionProperty =
         DependencyProperty.Register("Caption", typeof(string), typeof(MyTextBox), new UIPropertyMetadata(""));
    public string Caption
    {
        get { return (string)GetValue(CaptionProperty); }
        set { SetValue(CaptionProperty, value); }
    }

    public MyTextBox()
    {
        InitializeComponent();
    }

    protected override void OnGotFocus(RoutedEventArgs e)
    {
        TextBoxPart.Focus();
    }
}

编辑 2: 我曾经遇到过一个问题,要将焦点转移到 dataGridCell 中的子控件,这是我在模板中所做的:

 <ControlTemplate.Triggers>
     <Trigger Property="IsFocused" Value="True">
          <Setter TargetName="TextBoxPart" Property="FocusManager.FocusedElement" Value="{Binding ElementName=TextBoxPart}" />
     </Trigger>
 </ControlTemplate.Triggers>

您可以尝试将其添加到您的模板中。这应该可以转移您的注意力。

至于可访问性,我认为这无济于事,但我看不出有任何方法可以实现您想要的:-/

【讨论】:

  • 就我而言,我没有扩展任何现有控件,只是将它们包装起来。所以也许我有一些 MyCustomTextBoxControl,它可能包含一个文本框,但不是从它派生的(可能是因为它旁边还有一个按钮或其他东西)
  • 谢谢大卫,我刚刚试了一下,但似乎没有任何效果。即便如此,可访问性仍然被破坏 - 使用讲述人或 JAWS 时,专注于文本框仍然不会读出标签标题。
  • 该死...明天我会进一步考虑您的问题
  • 谢谢大卫。如果有帮助(可能有点矫枉过正),您可以从 quest.codeplex.com 下载整个源代码 - 问题代码在 EditorControls 项目中,并且 UserControls 在 ElementEditor.xaml.cs 中实例化。
  • 我终于找到了我正在寻找的代码,请参阅我的第二次编辑。希望这将解决至少一半的问题。至于其他的……
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-04
  • 2017-07-21
  • 1970-01-01
  • 2017-08-05
  • 1970-01-01
  • 2011-03-24
相关资源
最近更新 更多