您的位置:首页 > 其它

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

2014-12-04 16:24 609 查看

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


 

参考

Automatically validating business entities in WPF using custom binding and attributes

Flexible and Powerful Data Binding with WPF, Part 2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: