سؤال

I'm having difficulty developing a WinRT control that can display an image as well as be focusable and receive keyboard input. The first part - displaying an image in a UserControl - is straightforward; using a child Rectangle whose background is an ImageBrush works fine.

However, calling UserControl.Focus(FocusState.Programmatic) (or any other focus state) does not work - it returns false and focus is not set to the user control.

Incidentally, this UserControl is currently being tested inside a ContentControl, not sure if that makes any difference.

How can I make this UserControl focusable and able to receive keyboard input?

هل كانت مفيدة؟

المحلول

You need to set IsTabStop="True" to let it focus. UserControl's default is False.

Another thing you need to do is to display a focus indicator, which you don't get with UserControl for free. Here's the way you can add the visuals for it - copied from a Button template:

<Grid>
   <VisualStateManager.VisualStateGroups>
        <VisualStateGroup
            x:Name="FocusStates">
            <VisualState
                x:Name="Focused">
                <Storyboard>
                    <DoubleAnimation
                        Duration="0"
                        To="1"
                        Storyboard.TargetProperty="Opacity"
                        Storyboard.TargetName="FocusVisualWhite" />
                    <DoubleAnimation
                        Duration="0"
                        To="1"
                        Storyboard.TargetProperty="Opacity"
                        Storyboard.TargetName="FocusVisualBlack" />
                </Storyboard>
            </VisualState>
            <VisualState
                x:Name="Unfocused" />
            <VisualState
                x:Name="PointerFocused" />
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <Rectangle
        x:Name="FocusVisualWhite"
        IsHitTestVisible="False"
        Opacity="0"
        StrokeDashOffset="1.5"
        StrokeEndLineCap="Square"
        Stroke="{ThemeResource FocusVisualWhiteStrokeThemeBrush}"
        StrokeDashArray="1,1" />
    <Rectangle
        x:Name="FocusVisualBlack"
        IsHitTestVisible="False"
        Opacity="0"
        StrokeDashOffset="0.5"
        StrokeEndLineCap="Square"
        Stroke="{ThemeResource FocusVisualBlackStrokeThemeBrush}"
        StrokeDashArray="1,1" />
</Grid>

You still need to switch the visual state and so you could do something like this:

protected override void OnGotFocus(RoutedEventArgs e)
{
    base.OnGotFocus(e);
    this.UpdateVisualState(true);
}

protected override void OnLostFocus(RoutedEventArgs e)
{
    base.OnLostFocus(e);
    this.UpdateVisualState(true);
}

private void UpdateVisualState(bool useTransitions)
{
    switch (this.FocusState)
    {
        case FocusState.Programmatic:
        case FocusState.Keyboard:
            VisualStateManager.GoToState(this, "Focused", useTransitions);
            break;
        case FocusState.Pointer:
            VisualStateManager.GoToState(this, "PointerFocused", useTransitions);
            break;
        case FocusState.Unfocused:
            VisualStateManager.GoToState(this, "Unfocused", useTransitions);
            break;
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top