WPF - 无法将光标移动到ViewBox上的TextBox属性更改

时间:2017-06-22 16:55:26

标签: c# wpf xaml mvvm

上下文

基于MVVM的WPF应用程序(无框架)。 XAML出现在下面。

问题 只要searchRegistration TextBox失去焦点,ViewModel属性EditingState就会通过ICommand进行更改。在这种情况下,EditingState更改为“Search”,这会导致许多触发器。对于airframeBasicDetails网格,网格应该启用,具有蓝色背景并将编辑光标设置到typeName字段中。除了没有设置光标外,它的工作原理。事实上,它在窗口的任何地方都看不到。这确定了状态发生了变化并触发了触发但由于某种原因光标没有移动。

问题

当EditingState变为“Search”时,如何将编辑光标移动到typeName?

注意

我构建了这款应用的简化版,效果很好。我已经找到了那个版本和问题版本之间的差异,但找不到任何东西,因此我发布的整个失败的脚本尽可能地配对。我不愿意删除太多,以免我已删除的问题存在。

<Window x:Class="ADB_Desktop.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ADB_Desktop"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:controls="clr-namespace:System.Windows.Controls;assembly=DotNetProjects.Input.Toolkit"
        mc:Ignorable="d"
        Title="ADB Desktop"
        Width="1100"
        Height="800"
        FocusManager.FocusedElement="{Binding ElementName=searchRegistration}">
    <Window.Resources>
        <!-- Binding proxy-->
        <local:BindingProxy x:Key="proxy" Data="{Binding}"/>
    </Window.Resources>
    <DockPanel Name="mainDockPanel" LastChildFill="True">
        <Menu Name="mainMenu" DockPanel.Dock="Top">
            <Menu.Background>
                <SolidColorBrush Color="{DynamicResource ADBMenuStatusBarColour}"/>
            </Menu.Background>
            <MenuItem Header="_Maintenance"/>
            <MenuItem Header="_Reports"/>
        </Menu>
        <StatusBar x:Name="statusBar" DockPanel.Dock="Bottom" Height="25">
            <StatusBar.Background>
                <SolidColorBrush Color="{DynamicResource ADBMenuStatusBarColour}"/>
            </StatusBar.Background>
        </StatusBar>
        <TabControl x:Name="mainTabControl" Background="{DynamicResource ADBMainBackgroundColour}" SelectedIndex="1">
            <TabItem Header="Gallery"/>
            <TabItem Header="Airframes">
                <Grid x:Name="airframesGrid">
                    <Grid.RowDefinitions>
                        <RowDefinition x:Name="airframeAndImageRow" Height="380"/>
                        <RowDefinition x:Name="identitiesRow"/>
                    </Grid.RowDefinitions>
                    <Grid Grid.Row="0">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition x:Name="airframeCell" Width="400"/>
                            <ColumnDefinition x:Name="pictureCell"/>
                        </Grid.ColumnDefinitions>
                        <Grid Grid.Column="0">
                            <Grid.RowDefinitions>
                                <RowDefinition x:Name="searchRow" Height="80"/>
                                <RowDefinition x:Name="detailsRow" Height="180"/>
                                <RowDefinition x:Name="sightingsFlightRow" Height="120"/>
                            </Grid.RowDefinitions>
                            <Border Grid.Row="0" BorderBrush="DarkGray" BorderThickness="2" CornerRadius="4" Margin="2">
                                <Grid Grid.Row="0" Margin="5">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition x:Name="searchLabelCell" MaxWidth="100"/>
                                        <ColumnDefinition x:Name="searchCell" MinWidth="180"/>
                                        <ColumnDefinition x:Name="researchCell"/>
                                    </Grid.ColumnDefinitions>
                                    <StackPanel Grid.Column="0">
                                        <Label VerticalAlignment="Top" Content="Registration:"/>
                                    </StackPanel>
                                    <StackPanel Grid.Column="1">
                                        <StackPanel Orientation="Horizontal">
                                            <TextBox x:Name="searchRegistration" CharacterCasing="Upper" Grid.Column="0" Margin="5" Height="20" Width="80" HorizontalAlignment="Left"
                                                     Text="{Binding SearchRegistration, UpdateSourceTrigger=LostFocus}">
                                                <i:Interaction.Triggers>
                                                    <i:EventTrigger EventName="LostFocus">
                                                        <i:InvokeCommandAction Command="{Binding SearchSaveCommand}"/>
                                                    </i:EventTrigger>
                                                </i:Interaction.Triggers>
                                                <TextBox.Style>
                                                    <Style TargetType="TextBox">
                                                        <Style.Triggers>
                                                            <DataTrigger Binding="{Binding Path=EditingState}" Value="{x:Static local:EditingState.Initial}">
                                                                <Setter Property="IsEnabled" Value="True"/>
                                                            </DataTrigger>
                                                            <DataTrigger Binding="{Binding Path=EditingState}" Value="{x:Static local:EditingState.Search}">
                                                                <Setter Property="IsEnabled" Value="False"/>
                                                            </DataTrigger>
                                                            <DataTrigger Binding="{Binding Path=EditingState}" Value="{x:Static local:EditingState.New}">
                                                                <Setter Property="IsEnabled" Value="False"/>
                                                            </DataTrigger>
                                                        </Style.Triggers>
                                                    </Style>
                                                </TextBox.Style>
                                            </TextBox>
                                            </StackPanel>
                                      </StackPanel>
                                </Grid>
                            </Border>
                            <Border Grid.Row="1" BorderBrush="DarkGray" BorderThickness="2" CornerRadius="4" Margin="2">
                                <Grid Name="airframeBasicDetails" Grid.Row="1" Margin="5">
                                    <Grid.Style>
                                        <Style TargetType="{x:Type Grid}">
                                            <Style.Triggers>
                                                <DataTrigger Binding="{Binding Path=EditingState}" Value="{x:Static local:EditingState.Initial}">
                                                    <Setter Property="IsEnabled" Value="False"/>
                                                </DataTrigger>
                                                <DataTrigger Binding="{Binding Path=EditingState}" Value="{x:Static local:EditingState.Search}">
                                                    <Setter Property="IsEnabled" Value="True"/>
                                                    <Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=typeName}"/>
                                                    <Setter Property="Background" Value="Blue"/>
                                                </DataTrigger>
                                                <DataTrigger Binding="{Binding Path=EditingState}" Value="{x:Static local:EditingState.New}">
                                                    <Setter Property="IsEnabled" Value="True"/>
                                                    <Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=typeName}"/>
                                                    <Setter Property="Background" Value="Blue"/>
                                                </DataTrigger>
                                            </Style.Triggers>
                                        </Style>
                                    </Grid.Style>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition x:Name="airframeLabels" MaxWidth="100"/>
                                        <ColumnDefinition x:Name="airframeDetails"/>
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <RowDefinition x:Name="typeRow"/>
                                        <RowDefinition x:Name="constructionNoRow"/>
                                        <RowDefinition x:Name="remarksRow"/>
                                        <RowDefinition x:Name="rolledOutDateRow"/>
                                        <RowDefinition x:Name="firstFlightDateRow"/>
                                        <RowDefinition x:Name="statusRow"/>
                                    </Grid.RowDefinitions>
                                    <Label Grid.Column="0" Grid.Row="0">Type</Label>
                                    <controls:AutoCompleteBox Grid.Column="1" Grid.Row="0" Margin="5" Height="20" Width="270" HorizontalAlignment="Left" VerticalAlignment="Center"
                                             Name="typeName"
                                             Text="{Binding Path=AirframeCollectionView/TypeName, UpdateSourceTrigger=PropertyChanged}"
                                                    ItemsSource="{Binding Path=TypeNames}"
                                                    IsTextCompletionEnabled="True"
                                                    FilterMode="Contains" >
                                     </controls:AutoCompleteBox>
                                    <Label Grid.Column="0" Grid.Row="1">Construction no</Label>
                                    <TextBox Grid.Column="1" Grid.Row="1" Margin="5" x:Name="constructionNo" Height="20" Width="80" HorizontalAlignment="Left" VerticalAlignment="Center"
                                             Text="{Binding AirframeCollectionView/ConstructionNumber}"/>
                                    </Grid>
                            </Border>
                        </Grid>
                    </Grid>
                    <Image x:Name="airframePicture" Grid.Row="0" Grid.Column="1"/>
                                   </Grid>
            </TabItem>
        </TabControl>
    </DockPanel>
</Window>

1 个答案:

答案 0 :(得分:1)

根据elgonzo的建议,通过在ICommand动作的执行中引入短暂的延迟来解决这个问题。这允许在更改EditingState并触发对焦点的进一步更改之前,Tabbing out of a field导致的UI焦点更新完成。为了实现这一点,ICommand类中包含以下内容:

    public delegate void ChangeEditingStateDelegate();

    public void Execute(object parameter)
    {
        // Actions defered through Dispatcher because:
        // - The actions invoke triggers which change focus
        // - User may Tab out of a field invoking this command.
        // - If so, the UI thread needs to finish default Tab focus updates before these further actions occur.
        System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new ChangeEditingStateDelegate(this.ChangeEditingState));
    }

    private void ChangeEditingState()
    {
        // The current editing state determines what this command button should be doing
        switch (this.viewModel.EditingState)
        {
            case EditingState.Initial:
                // Search for airframes
                this.SearchForAirframes();
                break;
            case EditingState.Search:
                // Save edits
                this.SaveUpdates();
                break;
            case EditingState.New:
                // Save new airframe
                this.SaveUpdates();
                break;
            default:
                throw new ArgumentException("Unknown editing state");
        }
    }