2017-06-22 40 views
0

语境WPF - 无法移动光标到视图模型属性更改一个TextBox

一个WPF基于MVVM(没有框架)应用程序。 XAML出现在下面。

问题 每当searchRegistration文本框失去焦点的视图模型属性EditingState获得通过一个ICommand改变。在这种情况下,EditingState更改为“搜索”,这会导致一些触发器。对于airframeBasicDetails网格,应该启用网格,具有蓝色背景并将编辑光标设置到typeName字段中。这工作,除了游标未设置。事实上,它在窗口的任何地方都不可见。这确定了状态改变发生并触发了触发器,但由于某种原因光标没有移动。

问题

如何将编辑光标移动到类型名称时EditingState成为“搜索”?

注意

我建立了这个应用程序,它完美的作品的一个简化版本。我已经寻找该版本和问题版本之间的差异,但找不到任何东西,因此我发布整个失败的脚本尽可能配对。我不愿意删除太多,以免我的问题存在。

<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> 
+0

重温我简单的例子,我注意,我用一个按钮来触发改变EditingState。当我按照我的问题代码将触发器更改为跳出TextBox时,问题就出现了。因此,我认为这与使用Tab键I.e的效果有关。在触发器完成其工作后,Tab键具有进一步改变焦点的效果。搜索继续... – ifinlay

+0

我相信如此 - 试图改变焦点,而UI线程已经忙于改变焦点,并在处理与焦点相关的事件时可能会遇到麻烦。为什么不尝试推迟焦点更改,直到UI线程完成所有与焦点相关的处理? (例如,通过在Dispatcher.BeginInvoke或Dispatcher.InvokeAsync的帮助下将相应的操作添加到调度程序队列中) – elgonzo

+0

@elgonzo好主意。这将是我第一次进入Dispatcher古怪的世界,所以我可能花一点时间把解决方案放在一起。我认为这将涉及降低ICommand的优先级,以便在ICommand导致状态更改和结果数据触发之前,可​​以在UI线程中完成Tab处理。当我开始工作时,我会发布一些内容,然后可以将您的观察结果标记为答案。 – ifinlay

回答

1

按elgonzo的意见,这已通过引入在ICommand的操作的执行短暂的延迟解决。这允许在更改EditingState并触发进一步的焦点更改之前,由Tab键导出字段来完成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"); 
     } 
    } 
相关问题