Creating UserControls in WPF

I have a WPF form that consists of a 2 column grid.

The left column contains the control labels and the right column contains my controls.

Controls are all UserControls. In the simplest case, some of these controls simply carry over existing WPF controls, such as a text box, so that they all implement a common interface.

When the form is generated, I have code like this to set the label for the associated control, where newControl is the created UserControl and ctl.Caption just returns the required label text:

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

      

One problem is that setting Target doesn't actually work. If I have an underscore in the title, the mnemonic key does not set focus to the wrapped control. A workaround for this could be to manually set focus to the wrapped control in the UserControl code, but ...

The biggest issue is accessibility. Screensavers such as JAWS and the Windows built-in storyteller do not read the title of the control when the control receives focus.

I looked at this: http://msdn.microsoft.com/en-us/library/windows/desktop/gg712258.aspx - which has a lot of details but no useful examples. Does it have a lot of information about custom controls that is probably overkill for simple user controls?

So how can I bind my labels correctly to my UserControls?

You can view the code for the whole project at http://quest.codeplex.com/SourceControl/changeset/view/676933506953 - the specific code is in the EditorControls project and the UserControls is instantiated in ElementEditor.xaml.cs.

+3


source to share


2 answers


Your newControl is of type Control, which does not allow additional content to be added. If you want to add some content to it, you need to use a class that supports it, like ContentControl or Panel (for multiple children), you can implement your own control that implements the IAddChild interface.

A simple solution for you might be:

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

      

Code



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

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

      

and then you can use

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

      

+1


source


hmmm I tried to reproduce your problem on a small test project, but it works for me ... so I think you will need to give more details on how your userControls are created. Here's what works for me:

I created an empty project (as usual, application and windows files as usual) and set a two-column grid in my window:

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

      

then created a userControl which extends the wpf textbox class:

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

      

and

using System.Windows; using 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();
        }
    }
}

      

it is basically a text field with a "Caption" dp.

and now in my window the code is behind:

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

      

and with this I am focusing on TB when I press ALT + F (I even see _ under the F from "Foo" in the shortcut when I just press ALT)



So I guess your problem is with your UserControls and how they are created (for example for a template)

Edit:

If your control does not extend an existing control, but contains a WPF control, the problem is likely with the Focus method. You must add a Focus () method that focuses attention on the right side of your control when the control itself receives focus.

(for a UserControl containing a textarea you want focus for, for example):

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

      

code for

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

      

Edit 2: I once had a problem to move focus to a subcontrol in dataGridCell, and this is what I did in the template:

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

      

you can try adding this to your template. This should convey your focus.

As far as accessibility goes, I don't think it helps, but I don't see any way to achieve what you want: - /

0


source







All Articles