如何简单地将其绑定到ConverterParameter?
我有问题,我不知道如何解决这个简单,我有很多这样的点,那么解决方案应该不复杂。
我有主要项目设置和主要XAML。
我有Binding Converter和XAML文件的依赖项目看起来像:
此XAML文件由主项目的主XAML文件加载。
我必须将一个属性的值从Setting的传递给ConverterParameter
,这个参数可以在运行时更改,然后这必须是Binding
, Binding
我只能在这种情况下为DependencyProperty
做。
我必须为此Setting属性执行DependencyProperty
包装才能解决此问题?
当我尝试在ConverterParameter
设置Binding
,我将在运行时获得此exception:
无法在“绑定”类型的“ConverterParameter”属性上设置“绑定”。 ‘绑定’只能在DependencyObject的DependencyProperty上设置。
您可以绑定到任何属性,它不必是依赖属性。 但是,如果您希望UI在发生时立即反映属性中的更改,则有两种选择:
- 将属性设置为依赖项属性。
- 在保存属性的类型上实现
INotifyPropertyChanged
,并在属性更改时引发PropertyChanged
事件。
编辑:
正如在问题的编辑中指出的那样,无法绑定到ConverterParameter
。 但是你可以使用MultiBinding
。 例如,假设您要绑定到日期并将转换器文化规范作为参数并在文化更改时刷新绑定(我不确定这是一个好主意,但它很好地作为示例)。 你可以这样做:
这里, Date
和Settings
都是当前DataContext
属性。 DateCultureConverter
实现了IMultiValueConverter
,您可能会将它放在实际应用程序中层次结构中的几个级别的资源中。
您可以使用以下解决方案之一:
- BindableParameter(使用普通绑定+附加属性和MarkupExtension)
您必须集成类BindableParameter和BindableParameterExtension(见下文),然后您可以按如下方式使用它:
在XAML中:
xmlns:local="clr-namespace:BindableParameterExtension"
属性“TargetProperty”:
TargetProperty=TextBox.Text
必须将BindableParamerter设置为原始绑定属性(在本例中为“TextBox.Text”)。
样品转换器:
using System; using System.Windows.Data; namespace BindableParameterExtension { public class SampleConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value != null && parameter != null) { return value.ToString() + ", " + parameter.ToString(); } return null; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value is string && parameter is string) { string text1 = value as string; string textParamter = parameter as string; return text1.Replace(textParamter, ""); } return value; } } }
该参数可用于“Convert”和“ConvertBack”方法(用于绑定到视图模型)。
BindableParameter和BindableParameterExtension类(URL见上文(不是我的代码))
/* * Copyright - Everyone can use this code for any reason yet if you find a bug, I do not hold myself responsable :D */ using System.Windows.Data; using System.Windows.Markup; namespace BindableParameterExtension { /// /// BindableParameter is the class that changes the ConverterParameter Value /// This must inherit from freezable so that it can be in the inheritance context and thus be able to use the DataContext and to specify ElementName binding as a ConverterParameter /// http://www.drwpf.com/Blog/Default.aspx?tabid=36&EntryID=36 /// public class BindableParameter : Freezable { #region fields //this is a hack to trick the WPF platform in thining that the binding is not sealed yet and then change the value of the converter parameter private static FieldInfo isSealedFieldInfo; #endregion #region Properties #region Parameter /// /// Parameter Dependency Property /// public static readonly DependencyProperty ParameterProperty = DependencyProperty.Register("Parameter", typeof(object), typeof(BindableParameter), new FrameworkPropertyMetadata((object)null, (d, e) => { BindableParameter param = (BindableParameter)d; //set the ConverterParameterValue before calling invalidate because the invalidate uses that value to sett the converter paramter param.ConverterParameterValue = e.NewValue; //update the converter parameter InvalidateBinding(param); } )); /// /// Gets or sets the Parameter property. This dependency property /// indicates .... /// public object Parameter { get { return (object)GetValue(ParameterProperty); } set { SetValue(ParameterProperty, value); } } #endregion #region BindParameter /// /// BindParameter Attached Dependency Property /// public static readonly DependencyProperty BindParameterProperty = DependencyProperty.RegisterAttached("BindParameter", typeof(BindableParameter), typeof(BindableParameter), new FrameworkPropertyMetadata((BindableParameter)null, new PropertyChangedCallback(OnBindParameterChanged))); /// /// Gets the BindParameter property. This dependency property /// indicates .... /// public static BindableParameter GetBindParameter(DependencyObject d) { return (BindableParameter)d.GetValue(BindParameterProperty); } /// /// Sets the BindParameter property. This dependency property /// indicates .... /// public static void SetBindParameter(DependencyObject d, BindableParameter value) { d.SetValue(BindParameterProperty, value); } /// /// Handles changes to the BindParameter property. /// private static void OnBindParameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { FrameworkElement element = d as FrameworkElement; if (element == null) throw new InvalidOperationException("BindableParameter can be applied to a FrameworkElement only"); BindableParameter parameter = (BindableParameter)e.NewValue; element.Initialized += delegate { parameter.TargetExpression = BindingOperations.GetBindingExpression(element, parameter.TargetProperty); parameter.TargetBinding = BindingOperations.GetBinding(element, parameter.TargetProperty); //update the converter parameter InvalidateBinding(parameter); }; } #endregion public object ConverterParameterValue { get; set; } public BindingExpression TargetExpression { get; set; } public Binding TargetBinding { get; private set; } /// /// Gets the object being bound /// public DependencyObject TargetObject { get; private set; } /// /// Gets the dependency property being bound /// public DependencyProperty TargetProperty { get; internal set; } #endregion /// /// Static constructor to get the FieldInfo meta data for the _isSealed field of the BindingBase class /// static BindableParameter() { //initialize the field info once isSealedFieldInfo = typeof(BindingBase).GetField("_isSealed", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); if (isSealedFieldInfo == null) throw new InvalidOperationException("Oops, we have a problem, it seems like the WPF team decided to change the name of the _isSealed field of the BindingBase class."); } private static void InvalidateBinding(BindableParameter param) { if (param.TargetBinding != null && param.TargetExpression != null) { //this is a hack to trick the WPF platform in thining that the binding is not sealed yet and then change the value of the converter parameter bool isSealed = (bool)isSealedFieldInfo.GetValue(param.TargetBinding); if (isSealed)//change the is sealed value isSealedFieldInfo.SetValue(param.TargetBinding, false); param.TargetBinding.ConverterParameter = param.ConverterParameterValue; if (isSealed)//put the is sealed value back as it was... isSealedFieldInfo.SetValue(param.TargetBinding, true); //force an update to the binding param.TargetExpression.UpdateTarget(); } } #region Freezable Stuff protected override Freezable CreateInstanceCore() { //throw new NotImplementedException(); //return _bindableParam; return this; } #endregion } /// /// Markup extension so that it is easier to create an instance of the BindableParameter from XAML /// [MarkupExtensionReturnType(typeof(BindableParameter))] public class BindableParameterExtension : MarkupExtension { /// /// Gets or sets the Dependency property you want to change the binding's ConverterParameter /// public DependencyProperty TargetProperty { get; set; } /// /// Gets or sets the Binding that you want to use for the converter parameter /// public Binding Binding { get; set; } /// /// constructor that accepts a Dependency Property so that you do not need to specify TargetProperty /// /// The Dependency property you want to change the binding's ConverterParameter public BindableParameterExtension(DependencyProperty property) { TargetProperty = property; } public BindableParameterExtension() { } public override object ProvideValue(IServiceProvider serviceProvider) { _bindableParam = new BindableParameter(); //set the binding of the parameter BindingOperations.SetBinding(_bindableParam, BindableParameter.ParameterProperty, Binding); _bindableParam.TargetProperty = TargetProperty; return _bindableParam; } private BindableParameter _bindableParam; } }
- ObjectReference:
您必须集成ObjectReference类:
http://www.drwpf.com/blog/Portals/0/Code/ObjectReference.cs.txt
在XAML中:
xmlns:local="clr-namespace:WpfMarkupExtension"
剪辑:
local:ObjectReference.Declaration="{local:ObjectReference txtParam}"
在静态字典和部分中创建引用:
ConverterParameter={local:ObjectReference txtParam}}"
从字典中获取此对象引用 – >此处没有绑定,字典在解析时填充。
样品转换器:
using System; using System.Windows.Controls; using System.Windows.Data; namespace WpfMarkupExtension { public class SampleConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value != null && parameter is TextBox) { return value.ToString() + ", " + ((TextBox)parameter).Text; } return null; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value is string && parameter is TextBox) { string text1 = value as string; string textParamter = ((TextBox)parameter).Text; return text1.Replace(textParamter, ""); } return value; } } }
- 可绑定转换器参数(使用自定义绑定语法):
http://www.codeproject.com/Articles/456589/Bindable-Converter-Parameter
在XAML中:
xmlns:local="clr-namespace:BcpBindingExtension"
样品转换器:
using System; using System.Windows.Data; namespace BcpBindingExtension { public class SampleConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value != null && parameter is object[] && ((object[])parameter).Length > 0) { return value.ToString() + ", " + ((object[])parameter)[0].ToString(); } return null; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value is string && parameter is object[] && ((object[])parameter).Length > 0) { string text1 = value as string; string textParamter = ((object[])parameter)[0] as string; return text1.Replace(textParamter, ""); } return value; } } }