繁体   English   中英

如何简单地将其绑定到ConverterParameter?

[英]How to simply bind this to ConverterParameter?

我有问题,我不知道如何解决这个简单问题,我有很多观点,那么解决方案应该不复杂。

我有带有设置和主要XAML的主项目。

我有绑定转换器和XAML文件的依赖项目,如下所示:

<TextBlock Text="{Binding X.Y.Z, 
                 Converter={StaticResource ProbabilityConverter},                 
                 ConverterParameter=??????????????, Mode=OneWay}"
 />

该XAML文件由主项目中的主XAML文件加载。

我必须将一个属性的值从Setting的值传递给ConverterParameter ,此参数可以在运行时更改,然后必须是Binding ,在这种情况下, Binding只能对DependencyProperty进行。

我必须对此Setting属性进行DependencyProperty包装,以解决此问题吗?

当我尝试在ConverterParameter设置Binding ,我将在运行时收到此异常:

不能在“绑定”类型的“ ConverterParameter”属性上设置“绑定”。 只能在DependencyObject的DependencyProperty上设置“绑定”。

您可以绑定到任何属性,它不必是依赖项属性。 但是,如果希望用户界面在发生更改时立即反映出属性中的更改,则有两个选择:

  1. 使该属性成为依赖项属性。
  2. 在保存属性的类型上实现INotifyPropertyChanged ,并在属性更改时引发PropertyChanged事件。

编辑:

如问题编辑所指出的,不可能绑定到ConverterParameter 但是您可以使用MultiBinding 例如,假设您要绑定日期,并指定转换器的区域性规范作为参数,并在区域性更改时刷新绑定(我不确定这是个好主意,但可以很好地作为示例)。 您可以这样做:

<TextBlock>
    <TextBlock.Resources>
        <local:DateCultureConverter x:Key="converter" />
    </TextBlock.Resources>
    <TextBlock.Text>
        <MultiBinding Converter="{StaticResource converter}">
            <Binding Path="Date" />
            <Binding Path="Settings.Culture" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

在这里, DateSettings都是当前DataContext属性。 DateCultureConverter实现IMultiValueConverter ,您可能会将其放在资源中,而不是实际应用程序中层次结构IMultiValueConverter几个级别。

您可以使用以下解决方案之一:

  1. BindableParameter(使用常规绑定+附加属性和MarkupExtension)

https://marlongrech.wordpress.com/2008/08/03/my-wish-came-true-i-can-now-use-databinding-in-a-converterparameter/

您必须集成类BindableParameter和BindableParameterExtension(如下所示),然后可以按以下方式使用它:

在XAML中:

    xmlns:local="clr-namespace:BindableParameterExtension"

    <local:SampleConverter x:Key="sampleConverter" />

    <StackPanel Orientation="Vertical">
        <TextBox Name="txtContent" Text="Text from txtContent" />
        <TextBox Name="txtParameter" Text="Text from txtParameter" />
        <TextBox Name="txtBindingSample" 
                 Text="{Binding ElementName=txtContent, Path=Text, Converter={StaticResource sampleConverter}}"
                 local:BindableParameter.BindParameter="{local:BindableParameter TargetProperty=TextBox.Text,
                               Binding={Binding ElementName=txtParameter, Path=Text} }" />
    </StackPanel>

属性“ TargetProperty”:

TargetProperty=TextBox.Text

必须将BindableParamerter的设置为原始bound属性(在本例中为“ 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;
       }
    }
}    

该参数可以在“转换”和“转换后退”方法中使用(用于绑定到视图模型)。

类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
{
    /// <summary>
    /// 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
    /// </summary>
    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

        /// <summary>
        /// Parameter Dependency Property
        /// </summary>
        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);
                    }
                    ));

        /// <summary>
        /// Gets or sets the Parameter property.  This dependency property 
        /// indicates ....
        /// </summary>
        public object Parameter
        {
            get { return (object)GetValue(ParameterProperty); }
            set { SetValue(ParameterProperty, value); }
        }

        #endregion

        #region BindParameter

        /// <summary>
        /// BindParameter Attached Dependency Property
        /// </summary>
        public static readonly DependencyProperty BindParameterProperty =
            DependencyProperty.RegisterAttached("BindParameter", typeof(BindableParameter), typeof(BindableParameter),
                new FrameworkPropertyMetadata((BindableParameter)null,
                    new PropertyChangedCallback(OnBindParameterChanged)));

        /// <summary>
        /// Gets the BindParameter property.  This dependency property 
        /// indicates ....
        /// </summary>
        public static BindableParameter GetBindParameter(DependencyObject d)
        {
            return (BindableParameter)d.GetValue(BindParameterProperty);
        }

        /// <summary>
        /// Sets the BindParameter property.  This dependency property 
        /// indicates ....
        /// </summary>
        public static void SetBindParameter(DependencyObject d, BindableParameter value)
        {
            d.SetValue(BindParameterProperty, value);
        }

        /// <summary>
        /// Handles changes to the BindParameter property.
        /// </summary>
        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; }

        /// <summary>
        /// Gets the object being bound
        /// </summary>
        public DependencyObject TargetObject { get; private set; }

        /// <summary>
        /// Gets the dependency property being bound
        /// </summary>
        public DependencyProperty TargetProperty { get; internal set; }
        #endregion

        /// <summary>
        /// Static constructor to get the FieldInfo meta data for the _isSealed field of the BindingBase class
        /// </summary>
        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

    }

    /// <summary>
    /// Markup extension so that it is easier to create an instance of the BindableParameter from XAML
    /// </summary>
    [MarkupExtensionReturnType(typeof(BindableParameter))]
    public class BindableParameterExtension : MarkupExtension
    {
        /// <summary>
        /// Gets or sets the Dependency property you want to change the binding's ConverterParameter
        /// </summary>
        public DependencyProperty TargetProperty { get; set; }

        /// <summary>
        /// Gets or sets the Binding that you want to use for the converter parameter
        /// </summary>
        public Binding Binding { get; set; }

        /// <summary>
        /// constructor that accepts a Dependency Property so that you do not need to specify TargetProperty
        /// </summary>
        /// <param name="property">The Dependency property you want to change the binding's ConverterParameter</param>
        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;

    }
}
  1. 对象参考:

http://drwpf.com/blog/2007/09/02/supplying-an-object-reference-in-the-constructorparameters-collection-of-an-objectdataprovider/

您必须集成ObjectReference类:

http://www.drwpf.com/blog/Portals/0/Code/ObjectReference.cs.txt

在XAML中:

xmlns:local="clr-namespace:WpfMarkupExtension"

<local:SampleConverter x:Key="sampleConverter" />

<StackPanel Orientation="Vertical">
    <TextBox Name="txtContent" Text="Text from txtContent" />
    <TextBox Name="txtParameter" Text="Text from txtParameter" local:ObjectReference.Declaration="{local:ObjectReference txtParam}" />
    <TextBox Name="txtBindingSample" 
             Text="{Binding ElementName=txtContent, Path=Text, 
                            Converter={StaticResource sampleConverter},
                            ConverterParameter={local:ObjectReference txtParam}}" />
</StackPanel>

片段:

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;
        }
    }
}
  1. 可绑定转换器参数(使用自定义绑定语法):

http://www.codeproject.com/Articles/456589/Bindable-Converter-Parameter

在XAML中:

    xmlns:local="clr-namespace:BcpBindingExtension"

    <local:SampleConverter x:Key="sampleConverter" />

    <StackPanel Orientation="Vertical">
        <TextBox Name="txtContent" Text="Text from txtContent" />
        <TextBox Name="txtParameter" Text="Text from txtParameter" />
        <TextBox Name="txtBindingSample">
                 <TextBox.Text>
                    <local:BcpBinding Path="Text" ElementName="txtContent"
                                      Converter="{StaticResource sampleConverter}"
                                      ConverterParameters="Binding Path=Text ElementName=txtParameter"
                                      Mode="TwoWay"/>
                 </TextBox.Text>
        </TextBox>
    </StackPanel>

样本转换器:

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;
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM