none
Globally removing focus rectangle RRS feed

  • Question

  • Hey folks,

     

    Like many people, I am trying to remove the FocusVisualStyle from my controls.  The application I am working on is a Tablet PC app and a focus rectangle in not appropriate.  My deliverables are nearly finished and I'd like a global way to do this.  For this project I am only wearing the "Designer" cap and I'd really like a purely xaml-based way to pull this off. 

     

    I have tried:

     

    1) Global styles, but since many of my controls already have explicitly set styles, the global style never gets reached.

    2) Setting Focusable="false" on parent container, but apparently Focusable is not inherited by children.

     

    I realize that I can do this on an individual basis, but I'd rather not do that.  My current solutions is being handled in the Code-behind file by traversing the visual tree and setting Focusable to false.  This seems archaic.

     

    Any thoughts on a purely xaml approach?

     

    Thanks,

    Jeff

    Wednesday, January 2, 2008 11:58 PM

Answers

  • The FocusVisualStyle property is declared from FrameworkContentElement class and FrameworkElement class, so you should replace searching Control class to FrameworkContentElement and FrameworkElement classes.

     

    Furthermore, you could also try to use following code to do this. The following code defines an attached property which in its PropertyChangedCallback method to change element's FocusVisualStyle.

     

    Code Block

    namespace ForumProjects

    {

        public partial class MainWindow : Window

        {

            public MainWindow()

            {

                InitializeComponent();

            }

        }

     

        public class FocusVisualTreeChanger

        {

            public static bool GetIsChanged(DependencyObject obj)

            {

                return (bool)obj.GetValue(IsChangedProperty);

            }

     

            public static void SetIsChanged(DependencyObject obj, bool value)

            {

                obj.SetValue(IsChangedProperty, value);

            }

     

            public static readonly DependencyProperty IsChangedProperty =

                DependencyProperty.RegisterAttached("IsChanged", typeof(bool), typeof(FocusVisualTreeChanger), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits, IsChangedCallback));

     

            private static void IsChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)

            {

                if (true.Equals(e.NewValue))

                {

                    FrameworkContentElement contentElement = d as FrameworkContentElement;

                    if (contentElement != null)

                    {

                        contentElement.FocusVisualStyle = null;

                        return;

                    }

     

                    FrameworkElement element = d as FrameworkElement;

                    if (element != null)

                    {

                        element.FocusVisualStyle = null;

                    }

                }

            }

        }

    }

    <Window x:Class="ForumProjects.MainWindow"

           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

           xmlns:local="clr-namespace:ForumProjects"

           x:Name="Window" Title="MainWindow" Height="600" Width="800">

        <StackPanel Name="RootLayout">

            <StackPanel local:FocusVisualTreeChanger.IsChanged="True">

                <ListView>

                    <ListViewItem>AAA</ListViewItem>

                    <ListViewItem>AAA</ListViewItem>

                    <ListViewItem>AAA</ListViewItem>

                    <ListViewItem>AAA</ListViewItem>

                </ListView>

                <Button>AAA</Button>

                <CheckBox>AAA</CheckBox>

                <TextBox>AAA</TextBox>

            </StackPanel>

            <StackPanel Background="Gray">

                <ListView>

                    <ListViewItem>AAA</ListViewItem>

                    <ListViewItem>AAA</ListViewItem>

                    <ListViewItem>AAA</ListViewItem>

                    <ListViewItem>AAA</ListViewItem>

                </ListView>

                <Button>AAA</Button>

                <CheckBox>AAA</CheckBox>

                <TextBox>AAA</TextBox>

            </StackPanel>

        </StackPanel>

    </Window>

     

     

    Best Regards,

    Wei Zhou

    Friday, January 4, 2008 2:19 AM
    Moderator
  • That's a great way to change the default value of a DP, but it will not help in situations where a control's style explicitly changes the property value.  Unfortunately, FocusVisualStyle is one such property.  More specifically, styles for controls like Button, ComboBox, ListBox, etc. tend to explicitly contain a Setter for the FocusVisualStyle property. This setter will override the default value that you establish by overriding the metadata.

     

    It should work well for the Focusable property, as you have noted, since styles don't tend to contain a Setter for Focusable... they just rely on the default value (which is typically True).  So overriding the metadata to set this default value to False should work for most scenarios.

    Saturday, January 5, 2008 12:49 AM

All replies

  • There is no magic global setting that will affect all controls.  Also, you cannot use a generic style because nearly every theme-based style explicitly contains a Setter for FocusVisualStyle.

     

    The only XAML-based solution is to update all of your existing styles to include the necessary setters for FocusVisualStyle and Focusable (although I doubt that you really want to make all controls unfocusable... even for a tablet app...  as this totally destroys accessibility).

     

    For any controls that do not have explicit styles, you will need to define a type-based style in your application resources (typically in App.xaml), as shown here:

     

    Code Block

     

    <Style TargetType="{x:Type Button}">

      <Setter Property="FocusVisualStyle" Value="{x:Null}" />

      <Setter Property="Focusable" Value="False" />

    </Style>

    <Style TargetType="{x:Type ComboBoxItem}">

      <Setter Property="FocusVisualStyle" Value="{x:Null}" />

      <Setter Property="Focusable" Value="False" />

    </Style>

    <Style TargetType="{x:Type TextBox}">

      <Setter Property="FocusVisualStyle" Value="{x:Null}" />

      <Setter Property="Focusable" Value="False" />

    </Style>

      .

      .

      .

     

     

    You will find tools like Snoop/Mole invaluable for tracking down the controls that are still showing focus visuals... just tab to the offending control and then snoop the FocusManager.FocusedElement property.  This will tell you which control needs to have the above setters added to its default style.

     

    • Proposed as answer by OmarLara Tuesday, January 20, 2009 10:52 PM
    Thursday, January 3, 2008 9:48 AM
  • Thanks doc.  I'm not sure if setting Focusable to false for all controls is really a bad thing for my application.  It is a kiosk style app meant to be navigated with the users' fingers.  There is no keyboard and no events based on focus (as far as I can tell).  In this situation, can you think of any reasons why it would be bad?

     

    At this point, I am leaning towards the C# solution:

     

    private static void HideBoundingBox( object root )

    {

    Control control = root as Control;

     

    if (control != null)

    control.FocusVisualStyle = null;

     

    if ( root is DependencyObject )

    {

        foreach(object child in LogicalTreeHelper.GetChildren((DependencyObject)root))

    {

        HideBoundingBox( child );

    }

    }

    }

     

    Thanks to this thread for how to iterate through all children.

     

    Thursday, January 3, 2008 4:32 PM
  • The FocusVisualStyle property is declared from FrameworkContentElement class and FrameworkElement class, so you should replace searching Control class to FrameworkContentElement and FrameworkElement classes.

     

    Furthermore, you could also try to use following code to do this. The following code defines an attached property which in its PropertyChangedCallback method to change element's FocusVisualStyle.

     

    Code Block

    namespace ForumProjects

    {

        public partial class MainWindow : Window

        {

            public MainWindow()

            {

                InitializeComponent();

            }

        }

     

        public class FocusVisualTreeChanger

        {

            public static bool GetIsChanged(DependencyObject obj)

            {

                return (bool)obj.GetValue(IsChangedProperty);

            }

     

            public static void SetIsChanged(DependencyObject obj, bool value)

            {

                obj.SetValue(IsChangedProperty, value);

            }

     

            public static readonly DependencyProperty IsChangedProperty =

                DependencyProperty.RegisterAttached("IsChanged", typeof(bool), typeof(FocusVisualTreeChanger), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits, IsChangedCallback));

     

            private static void IsChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)

            {

                if (true.Equals(e.NewValue))

                {

                    FrameworkContentElement contentElement = d as FrameworkContentElement;

                    if (contentElement != null)

                    {

                        contentElement.FocusVisualStyle = null;

                        return;

                    }

     

                    FrameworkElement element = d as FrameworkElement;

                    if (element != null)

                    {

                        element.FocusVisualStyle = null;

                    }

                }

            }

        }

    }

    <Window x:Class="ForumProjects.MainWindow"

           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

           xmlns:local="clr-namespace:ForumProjects"

           x:Name="Window" Title="MainWindow" Height="600" Width="800">

        <StackPanel Name="RootLayout">

            <StackPanel local:FocusVisualTreeChanger.IsChanged="True">

                <ListView>

                    <ListViewItem>AAA</ListViewItem>

                    <ListViewItem>AAA</ListViewItem>

                    <ListViewItem>AAA</ListViewItem>

                    <ListViewItem>AAA</ListViewItem>

                </ListView>

                <Button>AAA</Button>

                <CheckBox>AAA</CheckBox>

                <TextBox>AAA</TextBox>

            </StackPanel>

            <StackPanel Background="Gray">

                <ListView>

                    <ListViewItem>AAA</ListViewItem>

                    <ListViewItem>AAA</ListViewItem>

                    <ListViewItem>AAA</ListViewItem>

                    <ListViewItem>AAA</ListViewItem>

                </ListView>

                <Button>AAA</Button>

                <CheckBox>AAA</CheckBox>

                <TextBox>AAA</TextBox>

            </StackPanel>

        </StackPanel>

    </Window>

     

     

    Best Regards,

    Wei Zhou

    Friday, January 4, 2008 2:19 AM
    Moderator
  • Ok, got something I like:

     

    FocusableProperty.OverrideMetadata(typeof(ContentControl), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));

     

    Earlier I had read that you could "Opt-in" to the hierarchy inheritence by overriding the Metatdata.  However, I had never changed existing DependencyProperties, only made new ones.  Today I came across some code that changed a DP and got excited.  Tried the above in my constructor and after fiddling with the type, got it to work.

     

    Although this is not a xaml-based approach, it certainly is global.  I think you could do the same for FocusVisualStyle, but for this application Focusable made more sense.

     

    -Jeff

    Friday, January 4, 2008 11:15 PM
  • That's a great way to change the default value of a DP, but it will not help in situations where a control's style explicitly changes the property value.  Unfortunately, FocusVisualStyle is one such property.  More specifically, styles for controls like Button, ComboBox, ListBox, etc. tend to explicitly contain a Setter for the FocusVisualStyle property. This setter will override the default value that you establish by overriding the metadata.

     

    It should work well for the Focusable property, as you have noted, since styles don't tend to contain a Setter for Focusable... they just rely on the default value (which is typically True).  So overriding the metadata to set this default value to False should work for most scenarios.

    Saturday, January 5, 2008 12:49 AM
  • Hey

    You can use this code block in your DictionaryResource

    <Style TargetType="{x:Type Button}">

      <Setter Property="FocusVisualStyle" Value="{x:Null}" />

    </Style>

    <Style TargetType="{x:Type ComboBoxItem}">

      <Setter Property="FocusVisualStyle" Value="{x:Null}" />

    </Style>

    <Style TargetType="{x:Type TextBox}">

      <Setter Property="FocusVisualStyle" Value="{x:Null}" />

    </Style>

    Global controls , only u need specify what control u need FocusVisualStyle Null


    • Edited by OmarLara Tuesday, January 20, 2009 11:02 PM spell
    Tuesday, January 20, 2009 10:54 PM