簡體   English   中英

如何在焦點輸入控件上抑制NotifyPropertyChanged事件?

[英]How to suppress a NotifyPropertyChanged event on a focused Input Control?

我的應用程序具有定期數據庫同步。 每當發生同步時,所有輸入控件的值都將重置為數據庫中的當前值。

但是,當在TextBox鍵入長文本時發生同步事件時,這不僅不方便。

期望的行為是,如果控件當前具有焦點,則輸入控件的值不會設置為bound屬性的值。 一旦鍵盤焦點丟失,當前值應該同步回綁定屬性,從而同步到數據庫(這將是默認行為)。

我的第一個想法是修改我的控件,以便在輸入具有鍵盤焦點時自動將綁定模式設置為OneWayToSource 目前我沒有看到另一種選擇,只是為了得到我在我的應用程序中的各種輸入控件,這將是很多工作。

您是否看到了在中心位置實現此類行為的方法,以便所有UI控件都使用它,最好不要對TextBoxComboBox等進行子類化?

您可以創建一個幫助程序來跟蹤IsKeyboardFocusWithin屬性,並僅在它不包含鍵盤焦點時更新目標值。 例如,您有每秒更改的特定來源:

    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();
    }
}

在這種情況下,這是Data屬性。 現在,幫手。 我決定將其創建為MarkupExtension以簡化XAML:

 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);
    }
}

我們有3個屬性:一個存儲來自源的實際值( Helper.SourceProperty )第二個 - 存儲目標值( Helper.TargetProperty ),第三個用於鎖定這些屬性之間的同步(Helper.FocusProperty)我們還有Binding屬性 - 這個是用於將Target屬性與源綁定的綁定(例如TextBox.TextMainWindow.Data )在ProvideValue方法中,我們:

  1. 使用Helper.FocusProperty綁定FrameworkElement.IsKeyboardFocusWithinProperty以鎖定updets
  2. 更新原始綁定使其成為TwoWay(更改后更新Data屬性)
  3. 將BindingExpression返回給Helper.TargetProperty

XAML將如下所示:

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

而短片則展示了結果

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM