2009-07-20 142 views
1

在我的WPF应用程序中,我有一个数据绑定TextBox和一个数据绑定ItemsControlItemsControl的内容取决于TextBox的内容。我希望能够在TextBox中键入一个值,然后按Tab键并输入ItemsControl中的第一项(由TextBox中的值创建)。我遇到的问题是在WPF在ItemsControl中创建模板项目之前评估选项卡操作。下面的代码演示了此问题:WPF Tab Into Databound ItemsControl

<Window x:Class="BindingExample.Window1" x:Name="SelfControl" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:loc="clr-namespace:BindingExample" Title="Window1" Height="300" Width="400"> 
    <Window.Resources> 
     <DataTemplate DataType="{x:Type loc:ChildClass}"> 
      <TextBox Text="{Binding Value}" /> 
     </DataTemplate> 
    </Window.Resources> 
    <StackPanel DataContext="{Binding ElementName=SelfControl}" Focusable="False"> 
     <Label Content="Options: A, B, C" /> 
     <TextBox Text="{Binding Object.Value}" /> 
     <ItemsControl Margin="16,0,0,0" ItemsSource="{Binding Object.Children}" Focusable="False"> 
      <ItemsControl.ItemsPanel> 
       <ItemsPanelTemplate> 
        <StackPanel Orientation="Horizontal" /> 
       </ItemsPanelTemplate> 
      </ItemsControl.ItemsPanel> 
     </ItemsControl> 
     <TextBox Text="Box2" /> 
    </StackPanel> 
</Window> 

using System.Collections.Generic; 
using System.ComponentModel; 
using System.Windows; 

namespace BindingExample 
{ 
    public partial class Window1 
    { 
     public static readonly DependencyProperty ObjectProperty = DependencyProperty.Register("Object", typeof(ParentClass), typeof(Window1)); 
     public ParentClass Object 
     { 
      get { return GetValue(ObjectProperty) as ParentClass; } 
      set { SetValue(ObjectProperty, value); } 
     } 

     public Window1() 
     { 
      InitializeComponent(); 
      Object = new ParentClass(); 
     } 
    } 

    public class ParentClass : INotifyPropertyChanged 
    { 
     private string value; 
     public string Value 
     { 
      get { return value; } 
      set { this.value = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Children")); } 
     } 

     public IEnumerable<ChildClass> Children 
     { 
      get 
      { 
       switch (Value.ToUpper()) 
       { 
        case "A": return new ChildClass[] { "A-1", "A-2", "A-2" }; 
        case "B": return new ChildClass[] { "B-1", "B-2", "B-3" }; 
        case "C": return new ChildClass[] { "C-1", "C-2", "C-2" }; 
        default: return new ChildClass[] { "Unknown" }; 
       } 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
    } 

    public class ChildClass 
    { 
     public string Value { get; set; } 
     public static implicit operator ChildClass(string value) { return new ChildClass { Value = value }; } 
    } 
} 

在这段代码中,我想输入“A”到第一TextBox,按Tab键,并有重点转移到孩子TextBox文本“A-1”。相反,焦点跳转到文本框“文本2”。我如何实现我在这里寻找的行为?

注:作为朱利安波林所指出的,可以通过对TextBoxPropertyChanged切换UpdateSourceTrigger,使这项工作。然而,这只适用于“如键入”绑定的情况。在我的情况下,我还想通过一次按键来设置值和标签。有没有办法强制ItemsControl按需创建其模板化项目?

回答

1

尝试设置TextBoxPropertyChanged所以底层的值设置当你输入一个新值,而不是当TextBox失去焦点的UpdateMode

<TextBox Text="{Binding Path=Object.Value, UpdateMode=PropertyChanged}" /> 
+0

This works。然而,理想情况下,我希望在控件失去焦点时发生绑定,而不是在用户输入时发生。 – 2009-07-20 22:51:29

0

这里是一个替代的解决方案。这有点破解,但似乎工作。由于ItemsControl中的模板对象直到主线程执行暂停时才会创建,因此此代码将捕获该选项卡,更新绑定并设置一个定时器,以便在有可能创建项目时移动焦点。

... 
<TextBox Text="{Binding Object.Value}" KeyDown="TextBox_KeyDown" /> 
... 

public partial class Window1 
{ 
    private DispatcherTimer timer; 

    ... 

    private void TextBox_KeyDown(object sender, KeyEventArgs e) 
    { 
     if (e.Key == Key.Tab && e.KeyboardDevice.Modifiers != ModifierKeys.Shift) 
     { 
      e.Handled = true; 
      var textbox = (TextBox)sender; 
      textbox.GetBindingExpression(TextBox.TextProperty).UpdateSource(); 
      (timer = new DispatcherTimer(
       new TimeSpan(100000), // 10 ms 
       DispatcherPriority.Normal, 
       delegate 
       { 
        textbox.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next)); 
        timer.Stop(); 
       }, Dispatcher)).Start(); 
     } 
    } 
} 

我这个代码中看到的唯一的问题是,ItemsControl可能需要更长的时间超过10毫秒来填充,在这种情况下,Tab键将跳过这些项目。是否有任何方法检测ItemsControl项目的创建是否已经发生?