2016-07-22 5 views
3

私のアプリケーションには、定期的なデータベース同期機能があります。同期が発生するたびに、すべての入力コントロールの値がデータベースからの現在の値にリセットされます。フォーカスされた入力コントロールでNotifyPropertyChangedイベントを抑制する方法は?

ただし、TextBoxに長いテキストを入力しているときに同期イベントが発生すると、これは不便です。

入力コントロールの値に、現在コントロールにフォーカスがある場合のバウンドプロパティの値が設定されていないことが望ましいです。キーボードのフォーカスが失われるとすぐに、現在の値をバウンドプロパティに同期させ、データベースに同期させる必要があります(これがデフォルトの動作です)。

私の最初のアイデアは、入力にキーボードフォーカスがある間にバインディングモードが自動的にOneWayToSourceに設定されるようにコントロールを変更することでした。 現在のところ、別のオプションは表示されませんが、私のアプリケーションでは多くの作業が必要なすべての種類の入力コントロールを導き出すことができます。

すべてのUIコントロールで使用されるように、この種の動作を中央の場所に実装する方法があります。TextBoxComboBoxなどをサブクラス化することはできません。

+0

希望の動作が何であるかは不明です。フォーカスが移動したコントロールをスキップするか、バウンドプロパティの更新をスキップしますか?値が変更されている場合次の同期フェーズで、スキップされた値はどうなりますか? – Dennis

+0

私は、目的の動作を指定する段落を追加しました=) – Andre

+0

これは興味深い問題です。ユーザーが編集中で、フィールドを更新する必要があるときはどうしますか?ユーザーはいつも勝つのですか?ユーザーの入力を待ち受け、ソースからの更新をブロックするカスタムBinding実装が必要なようです。 – Will

答えて

2

IsKeyboardFocusWithinプロパティを追跡し、キーボードフォーカスが含まれていない場合にのみターゲット値を更新するヘルパーを作成できます。例では 、あなたは刻々と変化し、特定のソースがあります。これは、Dataプロパティである。この場合

public partial class MainWindow { 
    public static readonly DependencyProperty DataProperty = DependencyProperty.Register(
     "Data", typeof(string), typeof(MainWindow), new PropertyMetadata(default(string), OnDataChanged)); 

    static void OnDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { 
     Debug.WriteLine((string)e.NewValue); 
    } 

    public string Data { 
     get { return (string)GetValue(DataProperty); } 
     set { SetValue(DataProperty, value); } 
    } 
    public MainWindow() { 
     InitializeComponent(); 
     DispatcherTimer dt = new DispatcherTimer(); 
     dt.Interval = TimeSpan.FromMilliseconds(1000); 
     dt.Tick += Dt_Tick; 
     dt.Start(); 
    } 

    void Dt_Tick(object sender, EventArgs e) { 
     Data = new Random().Next(0, 100).ToString(); 
    } 
} 

を。今、助けてください。 - 記憶目標値(Helper.TargetProperty) とに使用される第3 1記憶ソースから実際の値秒(Helper.SourceProperty) :我々は、3つの特性を有する

public class SynchronizationHelperExtension : MarkupExtension { 
    public Binding Binding { get; set; } 
    class Helper {    
     static int index = 0; 
     bool locked = false; 
     public static readonly DependencyProperty HelperProperty = DependencyProperty.RegisterAttached(
      "Helper", typeof(Helper), typeof(Helper), new PropertyMetadata(default(Helper))); 

     public static void SetHelper(DependencyObject element, Helper value) { 
      element.SetValue(HelperProperty, value); 
     } 

     public static Helper GetHelper(DependencyObject element) { 
      return (Helper)element.GetValue(HelperProperty); 
     } 
     public static readonly DependencyProperty FocusProperty = DependencyProperty.RegisterAttached("FocusProperty", typeof(bool), typeof(Helper), new PropertyMetadata(false, (o, args) => GetHelper(o)?.OnFocusPropertyChanged(o, (bool)args.OldValue, (bool)args.NewValue)));    
     public static readonly DependencyProperty SourceProperty = DependencyProperty.RegisterAttached("SourceProperty", typeof(object), typeof(Helper), new PropertyMetadata(false, (o, args) => GetHelper(o)?.OnSourcePropertyChanged(o, args.OldValue, args.NewValue))); 
     public static readonly DependencyProperty TargetProperty = DependencyProperty.RegisterAttached("TargetProperty", typeof(object), typeof(Helper), new PropertyMetadata(false, (o, args) => GetHelper(o)?.OnTargetPropertyChanged(o, args.OldValue, args.NewValue))); 

     void OnTargetPropertyChanged(DependencyObject o, object oldValue, object newValue) { 
      o.SetValue(SourceProperty, newValue); 
     } 
     void OnSourcePropertyChanged(DependencyObject o, object oldValue, object newValue) { 
      if (locked) 
       return; 
      o.SetValue(TargetProperty, newValue); 
     } 
     void OnFocusPropertyChanged(DependencyObject o, bool oldValue, bool newValue) { 
      locked = newValue; 
     } 
    } 

    public override object ProvideValue(IServiceProvider serviceProvider) { 
     var helper = new Helper(); 
     var ipwt = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget; 
     var dObj = ipwt.TargetObject as DependencyObject; 
     BindingOperations.SetBinding(dObj, Helper.FocusProperty, new Binding() {Path = new PropertyPath(FrameworkElement.IsKeyboardFocusWithinProperty), RelativeSource = RelativeSource.Self}); 
     Binding.Mode = BindingMode.TwoWay; 
     BindingOperations.SetBinding(dObj, Helper.SourceProperty, Binding); 
     Helper.SetHelper(dObj, helper); 
     return new Binding() {Path = new PropertyPath(Helper.TargetProperty), Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.LostFocus, RelativeSource = RelativeSource.Self }.ProvideValue(serviceProvider); 
    } 
} 

:私はXAML簡単にするMarkupExtensionとして作成することを決めましたこれらのプロパティ(Helper.FocusProperty) 間のロックの同期また、我々は結合性を持っている - ProvideValueメソッドでは、これはあなたが(MainWindow.Dataで例えばTextBox.Text)ソースとターゲットのプロパティをバインドするために使用することを結合さ たち:

  1. Helper.FocusPropertyFrameworkElement.IsKeyboardFocusWithinPropertyは、それが双方向Helper.TargetProperty

XAMLへ

  • 返すBindingExpression(Data変更後のプロパティを更新するために)にするために、元の結合を更新
  • をupdetsロックする結合ます次のようになります。

    <StackPanel> 
        <TextBox Text="{local:SynchronizationHelper Binding={Binding Data, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}}"/> 
        <TextBox Text="{local:SynchronizationHelper Binding={Binding Data, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}}"/> 
        <TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=Data}"></TextBlock> 
    </StackPanel> 
    

    And the short video demonstrating the result

  • 関連する問題