首页 > 代码库 > [WPF系列]-DataBinding(数据绑定)

[WPF系列]-DataBinding(数据绑定)

自定义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);    }}

[WPF系列]-DataBinding(数据绑定)