0

I am trying to prevent the directional keys being used in a combobox after selecting the value in the combobox. The functionality of the combobox is that when a value is selected then it can no longer be clicked on, but after the dropdown closes the directional keys can then select a value already being used. I want to 'lose focus' of the combobox or prevent the directional keys from being used.

XAML

<Grid Grid.Row="1" Margin="20 10 20 0">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="40" />
        <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
    <Grid.Resources>
        <Style TargetType="ComboBoxItem">
            <Setter Property="FontFamily" Value="Segoe UI"/>
            <Setter Property="Background" Value="#242424"/>
            <Setter Property="Foreground" Value="#FFFFFF" />
            <Setter Property="MinHeight" Value="20"/>
            <Setter Property="FontSize" Value="14"/>
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="IsEnabled" Value="{Binding IsAvailable}" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ComboBoxItem">
                        <Grid Background="{TemplateBinding Background}">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="MouseOver">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="HighlightVisual">
                                                <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="Visible"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Disabled">
                                       <Storyboard>
                                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Content">
                                               <DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0.33"/>
                                            </DoubleAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="SelectionStates">
                                    <VisualState x:Name="Unselected"/>
                                    <VisualState x:Name="Selected">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="HighlightVisual2">
                                                <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="Visible"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="FocusStates">
                                    <VisualState x:Name="Focused"/>
                                    <VisualState x:Name="Unfocused"/>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Grid>
                                <Border x:Name="HighlightVisual" Width="{TemplateBinding Width}" BorderBrush="#88FFFFFF" Margin="1" BorderThickness="1" Background="#33FFFFFF" CornerRadius="1" Visibility="Collapsed"/>
                                <Border x:Name="HighlightVisual2" Width="{TemplateBinding Width}" Background="#33FFFFFF" Visibility="Collapsed"/>
                                <ContentPresenter x:Name="Content" ContentTemplate="{TemplateBinding ContentTemplate}" Margin="5 0 5 0" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                            </Grid>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Grid.Resources>

    <TextBlock Text="{Binding Path=StringLibrary.LM_Priority, Source={StaticResource Strings}}" FontFamily="Segoe UI" Foreground="#FFFFFF" FontSize="12" VerticalAlignment="Center" />

    <ComboBox Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Width="200" Margin="10 0 0 0" ItemsSource="{Binding Priorities}" SelectedValuePath="PriorityNumber" SelectedValue="{Binding SelectedPriority, Mode=TwoWay}">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid>
                        <TextBlock Text="{Binding PriorityNumber}" FontFamily="Segoe UI Semibold" Foreground="#FFFFFF" FontSize="12" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="4 0 0 0" />

                        <TextBlock Text="{Binding CurrentList}" FontFamily="Segoe UI" FontStyle="Italic" MaxWidth="150" Foreground="#FFFFFF" FontSize="12" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0 0 4 0" />
                    </Grid>
                </Grid>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>
daveskylark
  • 2,724
  • 4
  • 16
  • 30
  • Have you tried http://stackoverflow.com/questions/2914495/wpf-how-to-programmatically-remove-focus-from-a-textbox this should prevent the arrow keys from selecting stuff. So perhaps perform this after selecting an item – David Zech Aug 17 '15 at 19:49
  • In addition to Nightawk441's comment you found select another control by calling ctrlName.Focus() – Helix 88 Aug 17 '15 at 19:54
  • @DevinDuval: In my understanding what you are trying to do is: you want to have a _select-once-ComboBox_ / _one-shot-ComboBox_ and after the user selected a value it has to be impossible to change the selection in any way. Am I correct? – Martin Aug 18 '15 at 07:47
  • They can change the value by clicking on the ComboBox again. When they do the previously selected value will not be available so it is not an issue. The problem is after the ComboBox is closed it still has focus and can be manipulated with the arrow keys. – daveskylark Aug 18 '15 at 21:22

2 Answers2

0

Thanks for the comments. Nighthawk441's advice would have worked fine, but Helix 88 reminded me of just using a shortcut to lose focus of the ComboBox. I just created a 'dummy' TextBox and set the focus to that after the DropDown is closed. I added

DropDownClosed="ComboBox_DropDownClosed"

to the ComboBox Here are the changes I made for those interested. Thanks again.

<!--DROPDOWN-->
<ComboBox Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Width="200" Margin="10 0 0 0" ItemsSource="{Binding Priorities}" SelectedValuePath="PriorityNumber" SelectedValue="{Binding SelectedPriority, Mode=TwoWay}" DropDownClosed="ComboBox_DropDownClosed">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid>
                    <!--PRIORITY NUMBER-->
                    <TextBlock Text="{Binding PriorityNumber}" FontFamily="Segoe UI Semibold" Foreground="#FFFFFF" FontSize="12" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="4 0 0 0" />

                    <!--CURRENT LIST-->
                    <TextBlock Text="{Binding CurrentList}" FontFamily="Segoe UI" FontStyle="Italic" MaxWidth="150" Foreground="#FFFFFF" FontSize="12" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0 0 4 0" />
                </Grid>
            </Grid>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

The 'dummy' textbox

<!--used to lose focus when dropdown is closed-->
    <TextBox x:Name="dummyTB" Width="0" Height="0" Opacity="0" VerticalAlignment="Top" HorizontalAlignment="Right" />

And the Code-Behind

private void ComboBox_DropDownClosed(object sender, EventArgs e)
    {
        dummyTB.Focus();
    }
daveskylark
  • 2,724
  • 4
  • 16
  • 30
  • Pray tell, what prevents the user from just shift+tab-ing back to the ComboBox and arrowkey-ing the selected item to something else? – Martin Aug 18 '15 at 07:43
  • This solution fixes the problem I am having for users. None of them will shift+tab back to the ComboBox. So for me this is a easy shortcut to fix the issue I was having. If you would like to show how I can't prevent that please do so. – daveskylark Aug 18 '15 at 21:20
  • I just tried to shift+tab back to the ComboBox and doing that didn't focus back to the ComboBox so everything is working properly! – daveskylark Aug 18 '15 at 21:46
0

The same problem happens when scrolling with the MouseWheel over the newly closed ComboBox, be it in a Standalone Combobox or, as in my case, in a Combobox added to a DataGrid via a DataGridTemplateColumn, like this:

    <DataGrid x:Name="dgvFieldsMapping" Grid.Row="1" ItemsSource="{Binding}">
        <DataGrid.Columns>
            ...
            <DataGridTemplateColumn Width="*" Header="Destination Field" >
                <DataGridTemplateColumn.CellTemplate >
                    <DataTemplate >
                        <ComboBox ItemsSource="{Binding Source={StaticResource CustomerDbFields}}" SelectedValue="{Binding destinationField, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ></ComboBox>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            ...
        </DataGrid.Columns>
    </DataGrid>

So, whenever the DropDown is closed, the Mousewheel would still scroll that Combobox's Items and modify the Selection.

I ended up modifying my XAML to look like this:

    <DataGrid x:Name="dgvFieldsMapping" Grid.Row="1" ItemsSource="{Binding}">
        <DataGrid.Resources>
            <Style x:Key="dgvComboBox_Loaded" TargetType="ComboBox">
                <EventSetter Event="Loaded" Handler="dgvCombobox_Loaded" />
            </Style>
        </DataGrid.Resources>
        <DataGrid.Columns>
            ...
            <DataGridTemplateColumn Width="*" Header="Destination Field" >
                <DataGridTemplateColumn.CellTemplate >
                    <DataTemplate >
                        <ComboBox Style="{StaticResource dgvComboBox_Loaded}" ItemsSource="{Binding Source={StaticResource CustomerDbFields}}" SelectedValue="{Binding destinationField, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ></ComboBox>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            ...
        </DataGrid.Columns>
    </DataGrid>

And adding these lines in codebehind

        public void dgvCombobox_Loaded(Object sender, RoutedEventArgs e)
        {
            ((ComboBox)sender).DropDownClosed -= ComboBox_OnDropDownClosed;
            ((ComboBox)sender).DropDownClosed += new System.EventHandler(ComboBox_OnDropDownClosed);
        }

        void ComboBox_OnDropDownClosed(object sender, System.EventArgs e)
        {
            dgvFieldsMapping.Focus();
        }

In this way I just move the Focus away from the ComboBox to the outer DataGrid after closing its corresponding DropDown, and I don't need to add any dummy FrameWorkElement