Comment lier simplement ceci à ConverterParameter?
j'ai des problèmes et je ne sais pas comment résoudre ce simple, j'ai beaucoup de points comme celui-ci, alors la solution ne devrait pas être compliquée.
j'ai le projet principal avec les paramètres et le XAML principal.
j'ai dépendance projet avec la Liaison Convertisseur et Fichier XAML ressemble à:
<TextBlock Text="{Binding X.Y.Z, Converter={StaticResource ProbabilityConverter}, ConverterParameter=??????????????, Mode=OneWay}"/>
ce fichier XAML est chargé par le fichier XAML principal du projet principal.
je dois passer la valeur d'une propriété de Setting à ConverterParameter
, ce paramètre peut changer au moment de l'exécution, alors ce doit être Binding
, Binding
je peux le faire uniquement pour DependencyProperty
dans ce cas.
je dois faire DependencyProperty
wrapper pour cette propriété de réglage pour résoudre ce problème?
Quand j'essaie set Binding
ConverterParameter
je vais obtenir cette exception à l'exécution:
un "Binding" ne peut pas être Propriété "ConverterParameter" de type "Liant". Une "liaison" ne peut être définie sur une DependencyProperty d'un DependencyObject.
2 réponses
vous pouvez vous lier à n'importe quelle propriété, il n'est pas nécessaire que ce soit une propriété de dépendance. Mais si vous voulez que votre UI reflète les changements dans la propriété immédiatement quand ils se produisent, vous avez deux options:
- faire de la propriété une propriété de dépendance.
- implémenter
INotifyPropertyChanged
sur le type qui détient la propriété et relance lePropertyChanged
événement lors de la modification de la propriété.
EDIT:
Comme indiqué dans l'édition de la question, il n'est pas possible de se lier à ConverterParameter
. Mais vous pouvez utiliser MultiBinding
. Par exemple, supposons que vous voulez lier à une date et donner la spécification de culture de convertisseur comme paramètre et rafraîchir la liaison lorsque la culture Change (Je ne suis pas sûr que ce soit une bonne idée, mais il sert bien d'exemple). Vous pourriez le faire comme ceci:
<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>
ici, les deux Date
et Settings
sont des propriétés de l'actuel DataContext
. DateCultureConverter
implémente IMultiValueConverter
et vous probablement mettre dans les ressources peu de niveaux de la hiérarchie dans l'application réelle.
Vous pouvez utiliser l'une des solutions suivantes:
- BindableParameter (à l'aide de la normale de liaison + une propriété attachée et MarkupExtension)
vous devez intégrer la classe BindableParameter et Bindableparametererextension (voir ci-dessous) et ensuite vous pouvez l'utiliser comme suit:
In 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>
La Propriété "TargetProperty":
TargetProperty=TextBox.Text
du BindableParamerter doit être défini à la propriété originale liée (dans ce cas "TextBox.Texte.)"
L'Exemple De Convertisseur:
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;
}
}
}
le paramètre peut être utilisé dans la méthode "Convert" et la méthode "ConvertBack" (utile pour se lier à un modèle de vue).
Class BindableParameter and Bindableparametererextension (URL see above) mon code))
/*
* 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;
}
}
- ObjectReference:
vous devez intégrer la classe ObjectReference:
http://www.drwpf.com/blog/Portals/0/Code/ObjectReference.cs.txt
In 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>
le ciselée:
local:ObjectReference.Declaration="{local:ObjectReference txtParam}"
crée la référence dans un dictionnaire statique et de la partie:
ConverterParameter={local:ObjectReference txtParam}}"
prend cette référence d'objet du dictionnaire -- > pas de reliure ici, le dictionnaire est rempli à l'Heure de l'analyse.
L'Exemple De Convertisseur:
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;
}
}
}
- paramètre de convertisseur liable (utilisant la liaison personnalisée la syntaxe):
http://www.codeproject.com/Articles/456589/Bindable-Converter-Parameter
In 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>
L'Exemple De Convertisseur:
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;
}
}
}