zoukankan      html  css  js  c++  java
  • [WPF系列]-DataBinding(数据绑定) 自定义Binding

    自定义Binding

    A base class for custom WPF binding markup extensions

    BindingDecoratorBase

    image

    Code:

    public class LookupExtension : BindingDecoratorBase
    {
      //A property that can be set in XAML
      public string LookupKey { get; set; }
    
      public override object ProvideValue(IServiceProvider provider)
      {
        //delegate binding creation etc. to the base class
        object val = base.ProvideValue(provider);
    
        //try to get bound items for our custom work
        DependencyObject targetObject;
        DependencyProperty targetProperty;
        bool status = TryGetTargetItems(provider, out targetObject,
                                                  out targetProperty);
    
        if (status)
        {
          //associate an input listener with the control
          InputHandler.RegisterHandler(targetObject, LookupKey);
        }
    
        return val;
      }
    }

    XAML:

    <TextBox Name="txtZipCode">
      <TextBox.Text>
        <local:LookupExtension Source="{StaticResource MyAddress}"
                               Path="ZipCode"
                               LookupKey="F5" />
      </TextBox.Text>
    </TextBox>

    效果图:

    Markup Extension Sample

    ---------------------------------------------===================================------------------------------

    DelayBinding: a custom WPF Binding

    ...but after the short delay, the results change

    <TextBox Text="{z:DelayBinding Path=SearchText, Delay='00:00:01'}" />
    [MarkupExtensionReturnType(typeof(object))]
    public class DelayBindingExtension : MarkupExtension
    {
        public DelayBindingExtension()
        {
            Delay = TimeSpan.FromSeconds(0.5);
        }
    
        public DelayBindingExtension(PropertyPath path) 
            : this()
        {
            Path = path;
        }
    
        public IValueConverter Converter { get; set; }
        public object ConverterParamter { get; set; }
        public string ElementName { get; set; }
        public RelativeSource RelativeSource { get; set; }
        public object Source { get; set; }
        public bool ValidatesOnDataErrors { get; set; }
        public bool ValidatesOnExceptions { get; set; }
        public TimeSpan Delay { get; set; }
        [ConstructorArgument("path")]
        public PropertyPath Path { get; set; }
        [TypeConverter(typeof(CultureInfoIetfLanguageTagConverter))]
        public CultureInfo ConverterCulture { get; set; }
    
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            var valueProvider = serviceProvider.GetService(typeof (IProvideValueTarget)) as IProvideValueTarget;
            if (valueProvider != null)
            {
                var bindingTarget = valueProvider.TargetObject as DependencyObject;
                var bindingProperty = valueProvider.TargetProperty as DependencyProperty;
                if (bindingProperty == null || bindingTarget == null)
                {
                    throw new NotSupportedException(string.Format(
                        "The property '{0}' on target '{1}' is not valid for a DelayBinding. The DelayBinding target must be a DependencyObject, "
                        + "and the target property must be a DependencyProperty.", 
                        valueProvider.TargetProperty, 
                        valueProvider.TargetObject));
                }
    
                var binding = new Binding();
                binding.Path = Path;
                binding.Converter = Converter;
                binding.ConverterCulture = ConverterCulture;
                binding.ConverterParameter = ConverterParamter;
                if (ElementName != null) binding.ElementName = ElementName;
                if (RelativeSource != null) binding.RelativeSource = RelativeSource;
                if (Source != null) binding.Source = Source;
                binding.ValidatesOnDataErrors = ValidatesOnDataErrors;
                binding.ValidatesOnExceptions = ValidatesOnExceptions;
    
                return DelayBinding.SetBinding(bindingTarget, bindingProperty, Delay, binding);
            }
            return null;
        }
    }
    public class DelayBinding
    {
        private readonly BindingExpressionBase _bindingExpression;
        private readonly DispatcherTimer _timer;
    
        protected DelayBinding(BindingExpressionBase bindingExpression, DependencyObject bindingTarget, DependencyProperty bindingTargetProperty, TimeSpan delay)
        {
            _bindingExpression = bindingExpression;
    
            // Subscribe to notifications for when the target property changes. This event handler will be 
            // invoked when the user types, clicks, or anything else which changes the target property
            var descriptor = DependencyPropertyDescriptor.FromProperty(bindingTargetProperty, bindingTarget.GetType());
            descriptor.AddValueChanged(bindingTarget, BindingTarget_TargetPropertyChanged);
    
            // Add support so that the Enter key causes an immediate commit
            var frameworkElement = bindingTarget as FrameworkElement;
            if (frameworkElement != null)
            {
                frameworkElement.KeyUp += BindingTarget_KeyUp;
            }
    
            // Setup the timer, but it won't be started until changes are detected
            _timer = new DispatcherTimer();
            _timer.Tick += Timer_Tick;
            _timer.Interval = delay;
        }
    
        private void BindingTarget_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key != Key.Enter) return;
            _timer.Stop();
            _bindingExpression.UpdateSource();
        }
    
        private void BindingTarget_TargetPropertyChanged(object sender, EventArgs e)
        {
            _timer.Stop();
            _timer.Start();
        }
    
        private void Timer_Tick(object sender, EventArgs e)
        {
            _timer.Stop();
            _bindingExpression.UpdateSource();
        }
    
        public static object SetBinding(DependencyObject bindingTarget, DependencyProperty bindingTargetProperty, TimeSpan delay, Binding binding)
        {
            // Override some specific settings to enable the behavior of delay binding
            binding.Mode = BindingMode.TwoWay;
            binding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
    
            // Apply and evaluate the binding
            var bindingExpression = BindingOperations.SetBinding(bindingTarget, bindingTargetProperty, binding);
    
            // Setup the delay timer around the binding. This object will live as long as the target element lives, since it subscribes to the changing event, 
            // and will be garbage collected as soon as the element isn't required (e.g., when it's Window closes) and the timer has stopped.
            new DelayBinding(bindingExpression, bindingTarget, bindingTargetProperty, delay);
    
            // Return the current value of the binding (since it will have been evaluated because of the binding above)
            return bindingTarget.GetValue(bindingTargetProperty);
        }
    }

    参考

    Automatically validating business entities in WPF using custom binding and attributes

    Flexible and Powerful Data Binding with WPF, Part 2

  • 相关阅读:
    Yii调试插件yii-debug-toolbar的使用
    IE8不支持indexOf的解决办法
    使用wkhtmltopdf的一些事情
    mac sourcetree 启用 Beyond compare
    Java基础学习之(5)--impact和package
    Java基础学习之(3)--面向对象2--重载
    Java基础学习之(4)--面向对象3--this+static关键字
    Java基础学习之(2)--面向对象1
    Java基础学习之(1)--标识符、关键字、数据类型
    java学习(7)iterator迭代器
  • 原文地址:https://www.cnblogs.com/HQFZ/p/4143149.html
Copyright © 2011-2022 走看看