自定义Binding
A base class for custom WPF binding markup extensions
BindingDecoratorBase
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>
效果图:
---------------------------------------------===================================------------------------------
DelayBinding: a custom WPF Binding
<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); } }