1

私の WPF アプリケーションには、 databoundTextBoxと databoundがありItemsControlます。の内容は、 のItemsControl内容によって決まりTextBoxます。TextBoxに値を入力し、タブを押して最初の項目を入力できるようにしたいItemsControl(の値から作成されたTextBox)。私が抱えている問題は、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 }; }
    }
}

このコードでは、最初の に「A」と入力し、TextBoxTab キーを押しTextBoxて、テキスト「A-1」を持つ子にフォーカスを移動させます。代わりに、フォーカスはテキスト「Box2」を含む TextBox にスキップします。ここで探している動作をどのように達成できますか?

注: Julien Poulin が指摘したように、 を に切り替えることでこれを機能させることがUpdateSourceTriggerできTextBoxますPropertyChanged。ただし、これは「入力時」バインディングが許容される場合にのみ機能します。私の場合、値の設定とタブを 1 回のキーストロークで実行したいと考えています。オンデマンドでテンプレート化された項目を作成するように ItemsControl を強制する方法はありますか?

4

2 に答える 2

1

の を に設定してUpdateMode、がフォーカスを失ったときではなく、新しい値を入力したときに基になる値が設定されるようにしますTextBoxPropertyChangedTextBox

<TextBox Text="{Binding Path=Object.Value, UpdateMode=PropertyChanged}" />
于 2009-07-20T22:41:31.073 に答える
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アイテムの作成が行われたかどうかを検出する方法はありますか?

于 2009-07-23T16:26:11.973 に答える