2009-07-20 8 views
1

私のWPFアプリケーションでは、データバインドTextBoxとデータバインドItemsControlがあります。 ItemsControlの内容はTextBoxの内容によって決まります。 TextBoxに値を入力し、タブを押してItemsControlの最初の項目(TextBoxの値から作成)を入力したいと考えています。私が抱えている問題は、WPFがテンプレート項目をItemsControlに作成する前に、タブアクションが評価されることです。WPFタブをデータバインド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 }; } 
    } 
} 

が、私は、最初のTextBoxに「A」と入力し、Tabキーを押して、子供TextBoxにフォーカスシフトを有するがしたい:次のコードは、この問題を示していますテキスト「A-1」。代わりに、フォーカスはテキストボックス "Box2"でスキップします。ここで私が探している行動をどのように達成することができますか?

注:ジュリアン・プーランが指摘したように、PropertyChangedTextBoxUpdateSourceTriggerを切り替えることによって、この作業を行うことが可能です。しかし、これは、 "あなたが入力するように"バインディングが受け入れられる場合にのみ機能します。私の場合は、1回のキーストロークで値とタブを設定したいと思います。 ItemsControlにテンプレートアイテムをオンデマンドで作成させるための方法はありますか?

答えて

1

TextBoxがフォーカスを失ったとき、あなたが代わりに新しい値を入力する際に​​基本となる値が設定されているPropertyChangedTextBoxUpdateModeを設定してください:ここで

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

これは機能します。しかし、理想的には、コントロールがフォーカスを失ったときにバインディングを発生させたいのですが、ユーザーが入力している間ではありません。 –

+0

最初のTextBoxがフォーカスを失ったときにまだ作成されていないため、ItemsControl内のTextBoxにフォーカスを自動的に設定することはできません。フォーカスを元の位置に戻すコードを書くこともできますが、実際には面倒なように見えます。 –

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ミリ秒よりも長い時間がかかるかもしれないということです。 ItemsControlアイテムの作成が行われたかどうかを検出する方法はありますか?

関連する問題