Print Page | Close Window

DialogManager stealing focus

Printed From: IdeaBlade
Category: Cocktail
Forum Name: Community Forum
Forum Discription: A professional application framework using Caliburn.Micro and DevForce
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=3399
Printed Date: 22-Jan-2026 at 6:08am


Topic: DialogManager stealing focus
Posted By: JohnBloom
Subject: DialogManager stealing focus
Date Posted: 19-Apr-2012 at 12:06pm
We have written our own behavior that sets the focus to a specific control on the screen. We have some dialogs that start with the focus on a specific control.
When the dialog pops up ee see the focus in our control for a split second and then the childwindow steals it. It takes 3 tabs to get back to our control. Any idea about what is going on?

-------------
-John Bloom



Replies:
Posted By: mgood
Date Posted: 19-Apr-2012 at 12:31pm
Yes, that's an annoying problem. The culprits are the ContentControl and ItemControl. They are tab stops by default and steal the focus. No idea why anybody throught making them tab stops was a good idea. You can easily fix it for your entire application if you add the following two implicit styles to your app. The ContentControl style as seen below also fixes the sizing problem in Silverlight. You can see these in use in TempHire.
 
    <Style TargetType="ContentControl">
        <Setter Property="IsTabStop" Value="False" />
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        <Setter Property="VerticalContentAlignment" Value="Stretch" />
    </Style>
 
    <Style TargetType="ItemsControl">
        <Setter Property="IsTabStop" Value="False" />
    </Style>


Posted By: JohnBloom
Date Posted: 19-Apr-2012 at 2:09pm
Thanks, those worked. Now I am only one tab stop away. Our control is getting focus and then the ok button is taking it. I think that most cases focus on the button would be preferred but in this case we want the focus to be in our control ready for user input. How can we keep the button from stealing focus away from our control?

-------------
-John Bloom


Posted By: mgood
Date Posted: 19-Apr-2012 at 2:30pm
Don't know how you implemented your behavior. Have you tried the InitialFocusBehavior from TempHire? I'm doing the same thing as you are describing and it works in my case.
 
    [TypeConstraint(typeof(Control))]
    public class InitialFocusBehavior : Behavior<Control>
    {
        protected override void OnAttached()
        {
            base.OnAttached();
 
#if SILVERLIGHT
            if (!Application.Current.IsRunningOutOfBrowser)
                HtmlPage.Plugin.Focus();
#endif
 
            AssociatedObject.Loaded += (sender, args) => AssociatedObject.Focus();
        }
    }


Posted By: JohnBloom
Date Posted: 20-Apr-2012 at 7:04am
Ok I am able to repo this in TempHire now.
 
In the Styles.xaml file you have the buttons set to IsTabStop = false:
<Style TargetType="Button">
        <Setter Property="FontFamily" Value="Verdana" />
        <Setter Property="FontSize" Value="10.667" />
        <Setter Property="Background" Value="#FFFF0000" />
        <Setter Property="Foreground" Value="#FFFFFFFF" />
        <Setter Property="Padding" Value="3" />
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="IsTabStop" Value="False" />
If you remove the setter property you can see the button steal focus. 
We have a few places where we rely on the buttons being tab stops so we cant turn them all off like that.
Any suggestions?
 


-------------
-John Bloom


Posted By: mgood
Date Posted: 20-Apr-2012 at 12:23pm
Nice find. I had somebody else do the styles for me. I didn't realize he turned of the tab stop for the buttons. When I was implementing the behavior for TempHire I was finding numerous posts from people struggling with this. I thought I had it nailed, but apparently not.
I'm not sure how to make this work based on these findings. I saw a suggestion from somebody to use a delay before assigning focus. So, in the Loaded event instead of calling SetFocus right away, start a timer and then set the focus to essentially steal it back from the button. Don't realy like that approach, but don't have anything better at the moment.
 
I'll play around with it when I get a chance to see if I can do anything in the DialogManager.


Posted By: mgood
Date Posted: 23-Apr-2012 at 5:37pm
John,
I looked into it some more and apparently we've both been over-engineering this. To set the initial focus you don't need a behavior. You simply set TabIndex="0" as in the following example.

        <TextBox TabIndex="0" />
The missing link in Cocktail is to set TabIndex="0" on the ContentControl in the dialog host. I will change this for the next release, but you don't have to wait for it. Cocktail actually allows you to replace the out-of-the-box dialog host with your own. 

To do this, add a ChildWindow to your solution and replace the XAML with the following. This is the exact same XAML taken from Cocktail except for TabIndex="0" on the ContentControl. Make sure you replace the x:Class with whatever you want to call it.

<controls:ChildWindow x:Class="MyApp.CustomDialogHostView"
                      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                      xmlns:cal="http://www.caliburnproject.org"
                      xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
                      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                      d:DesignHeight="277"
                      d:DesignWidth="800"
                      HasCloseButton="False"
                      mc:Ignorable="d">
 
    <Grid x:Name="LayoutRoot"
          MinWidth="166"
          Margin="2">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
 
        <ItemsControl x:Name="DialogButtons" Grid.Row="1">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel HorizontalAlignment="Right" Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button Width="75"
                            Height="23"
                            Margin="5"
                            cal:Message.Attach="Close($dataContext)"
                            Content="{Binding Content}"
                            IsEnabled="{Binding Enabled}" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        <ContentControl x:Name="ActiveItem"
                        Width="Auto"
                        Height="Auto"
                        HorizontalContentAlignment="Stretch"
                        VerticalContentAlignment="Stretch"
                        TabIndex="0" />
    </Grid>
</controls:ChildWindow>
Now, all you have to do is create a corresponding ViewModel that extends from DialogHostBase. Cocktail will discover your custom ViewModel and through the normal Caliburn.Micro convention it will find your custom view.

namespace MyApp
{
    public class CustomDialogHostViewModel : DialogHostBase
    {
    }
}


Posted By: mgood
Date Posted: 23-Apr-2012 at 5:43pm
Just to be clear, you still need to keep the styles for the ContentControl and ItemsControl, otherwise the ContentControl will actually get the initial focus. You can also set IsTabStop to false in your custom view, which is what I'm going to add to the out-of-the-box view in Cocktail.


Posted By: giotis
Date Posted: 25-Feb-2013 at 8:58am
Reading the above I want to add a strange behavior of GridView in
StaffingResourceSearchView when clicked (left button of mouse)
two times in same line loosing the focus.
I tried to find the error without success, why happen this?(wpf ver)




Print Page | Close Window