首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何简单地将其绑定到ConverterParameter?

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

Stack Overflow用户
提问于 2011-05-07 19:17:37
回答 2查看 32.6K关注 0票数 25

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

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

我有绑定转换器和XAML文件的依赖项目看起来像:

代码语言:javascript
运行
复制
<TextBlock Text="{Binding X.Y.Z, 
                 Converter={StaticResource ProbabilityConverter},                 
                 ConverterParameter=??????????????, Mode=OneWay}"
 />

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

我必须将一个属性的值从设置传递到ConverterParameter,这个参数可以在运行时更改,然后这个参数必须是BindingBinding在这种情况下,我只能对DependencyProperty执行此操作。

我必须为这个设置属性做DependencyProperty包装才能解决这个问题吗?

当我尝试在ConverterParameter中设置Binding时,我会在运行时得到以下异常:

Binding A‘

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-05-07 22:01:24

你可以绑定到任何属性,它不一定是依赖属性。但是,如果希望UI在发生更改时立即反映属性中的更改,则有两种选择:

依赖项

  • 使属性成为保存属性的类型的依赖项property.

编辑:

正如在问题的编辑中指出的,不可能绑定到ConverterParameter。但是你可以使用MultiBinding。例如,假设您想要绑定到一个日期,并将转换器区域性规范作为参数提供,并在区域性发生变化时刷新绑定(我不确定这是否是一个好主意,但它可以作为一个很好的示例)。你可以这样做:

代码语言:javascript
运行
复制
<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,在实际应用程序中,您可能会将其放在层次结构的上几层资源中。

票数 26
EN

Stack Overflow用户

发布于 2015-08-05 22:43:14

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

  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中:

代码语言:javascript
运行
复制
    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”属性:

代码语言:javascript
运行
复制
TargetProperty=TextBox.Text

必须设置为原始绑定属性(在本例中为"TextBox.Text")。

示例转换器:

代码语言:javascript
运行
复制
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(不是我的代码))

代码语言:javascript
运行
复制
/*
 * 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. ObjectReference:

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中:

代码语言:javascript
运行
复制
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>

被剪下的:

代码语言:javascript
运行
复制
local:ObjectReference.Declaration="{local:ObjectReference txtParam}"

在静态字典和部件中创建引用:

代码语言:javascript
运行
复制
ConverterParameter={local:ObjectReference txtParam}}" 

从字典中获取这个对象引用-->这里没有绑定,字典在解析时被填充。

示例转换器:

代码语言:javascript
运行
复制
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. Bindable转换器参数(使用自定义绑定syntax):

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

在XAML中:

代码语言:javascript
运行
复制
    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>

示例转换器:

代码语言:javascript
运行
复制
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;
        }
    }
}
票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5920684

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档