J'ai un formulaire généré en fonction de plusieurs éléments de daTembles. L'un des éléments de DataTemplate crée une zone de texte d'une classe qui ressemble à ceci: J'ai besoin d'un moyen de "lier" la valeur dans la propriété de formatage de la propriété "StringFormat" du obligatoire. Jusqu'à présent, j'ai: p> Cependant, étant donné que StringFormat n'est pas une propriété de dépendance, je ne peux pas le lier. P> Ma prochaine pensée était de créer Un convertisseur de valeur et transmettez la valeur de la propriété de formatage dans le converterParameter, mais j'ai couru dans le même problème - ConverterParameter n'est pas une dépendanceProperty. P> Alors, maintenant je me tourne vers vous, alors. Comment définir dynamiquement le stringformat d'une liaison? Plus spécifiquement, sur une zone de texte? p> Je préférerais laisser Xaml faire le travail pour moi afin que je puisse éviter de jouer avec le code-derrière. J'utilise le motif MVVM et j'aimerais garder les limites entre le modèle de visualisation et la vision comme non floue que possible. P> Merci! P> P>
5 Réponses :
Une manière peut être de créer une classe qui hérite textbox de code> et dans cette classe Créez votre propre propriété de dépendance qui déléguette à
stringformat code> lors de la définition. Ainsi, au lieu d'utiliser
textbox code> dans votre XAML, vous utiliserez la zone de texte héritée et définissez votre propre propriété de dépendance dans la liaison. p>
C'est une bonne suggestion. Je vais devoir examiner cela. J'étais un peu en espérant qu'il y aurait une solution qui n'impliquait pas des contrôles personnalisés, mais je suis certainement ouvert à cela. Je reviendrai après un peu de recherche.
J'essaie de faire la même chose, mais je ne sais pas comment configurer les propriétés ci-jointes pour gérer cela. J'ai posté une nouvelle question: Stackoverflow.com/q/24119097/65461
Il suffit de lier la zone de texte à l'instance d'une myTextboxClass au lieu de myTextboxClass.value et utilisez un ValueConverter pour créer une chaîne de la valeur et de la mise en forme. p>
p>
Une autre solution consiste à utiliser un convertisseur de multivalue qui se lierait à la fois à la valeur et au formatage. p>
La première solution ne prend pas en charge les modifications apportées aux propriétés, c'est-à-dire si la valeur ou la formatage change le convertisseur de valeur ne sera pas appelée comme si vous utilisez un multivéeconverter et une liaison directement sur les propriétés. p>
La liaison à l'instance MyTextboxClass est quelque chose que j'ai essayé, mais la méthode de recto-enregistrement dans l'encéconnet sera un problème car il y en a beaucoup, de nombreuses propriétés que je n'ai pas de place pour un objet Textbox. Donc, je recevrais un objet incomplet revenir de la zone de texte. Je vais regarder dans le convertisseur multi-valeurs. Cependant, la formatage n'est pas liée car il s'agit d'une propriété de dépendance, alors je ne suis pas sûr que ça va travailler.
Comment est-ce censé travailler? Lorsque la zone de texte est mise à jour en utilisant la base de données, le texte est formaté à l'aide de la formatage. Lorsqu'un utilisateur met à jour la zone de texte, il peut entrer n'importe quel texte pouvant être incompatible avec la mise en forme de la formatage. Est-ce que ça va? Êtes-vous sûr de ne pas vouloir utiliser une zone de texte masquée à la place? En outre, la mise en forme est aussi liée que toute autre propriété publique.
"La formatrice est aussi bien liée que toute autre propriété publique" Expliquez pourquoi, alors vous obtiendrez une erreur indiquant que "une" liaison "ne peut pas être définie sur la propriété" StringFormat "de type" Binding ". Une" liaison "ne peut être définie que sur une dépendance spécifique d'une dépendanceObject. "
On pourrait créer un comportement attaché qui pourrait remplacer la liaison avec celui qui a le FormatString spécifié. Si la propriété de dépendance FormatString alors la liaison serait à nouveau être mis à jour. Si la liaison est mis à jour alors la FormatString serait à nouveau appliquée que la liaison. p>
Les deux seules choses délicates que je peux penser que vous auriez à traiter. Une question est de savoir si vous voulez créer deux propriétés attachées qui coordonnent entre eux pour le FormatString et le TargetProperty sur lequel la fixation exist que le FormatString doit être appliqué (ex. TextBox.Text) ou peut-être vous pouvez simplement supposer que la propriété de votre transaction avec selon le type de commande cible. L'autre question est peut-être qu'il peut être non trivial de copier une liaison existante et de modifier légèrement compte tenu des différents types de liaisons là-bas qui pourrait également inclure des liaisons personnalisées. P>
Il est important de considérer que si tous cela ne permette d'obtenir le formatage dans la direction de vos données à votre contrôle. Pour autant que je peux découvrir en utilisant quelque chose comme un MultiBinding avec une coutume MultiValueConverter à consommer à la fois la valeur initiale et la FormatString et produire la sortie désirée souffre toujours du même problème surtout parce que la méthode ConvertBack est seulement donné la chaîne de sortie et que vous souhaitez attendre à déchiffrer à la fois la FormatString et la valeur d'origine de celle-ci qui, à ce moment-là est presque toujours impossible. p>
Les solutions restantes qui devraient fonctionner pour le formatage bidirectionnel et unformatting serait le suivant: p>
Ce code (inspiré de defaultvalueconverter.cs @ Références.microsoft.com ) fonctionne pour une liaison à deux voies à une zone de texte ou à un contrôle similaire, à condition que la formatrice quitte la version de ToString () de la propriété source dans un état pouvant être converti.
(c.-à-d. format comme "#, 0,00" est correct car "1,234.56" peut être analysé, mais la formatrineString = "Certains texte de texte préfixe, 0,00" se convertiront en "un texte préfixe 1 234.56" qui ne peut pas être analysé.) xaml: p> notez une copie cibleNullvalue si la propriété source peut être null. p> C #: P> /// <summary>
/// Allow a binding where the StringFormat is also bound to a property (and can vary).
/// </summary>
public class ToStringFormatConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length == 1)
return System.Convert.ChangeType(values[0], targetType, culture);
if (values.Length >= 2 && values[0] is IFormattable)
return (values[0] as IFormattable).ToString((string)values[1], culture);
return null;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
var targetType = targetTypes[0];
var nullableUnderlyingType = Nullable.GetUnderlyingType(targetType);
if (nullableUnderlyingType != null) {
if (value == null)
return new[] { (object)null };
targetType = nullableUnderlyingType;
}
try {
object parsedValue = ToStringFormatConverter.TryParse(value, targetType, culture);
return parsedValue != DependencyProperty.UnsetValue
? new[] { parsedValue }
: new[] { System.Convert.ChangeType(value, targetType, culture) };
} catch {
return null;
}
}
// Some types have Parse methods that are more successful than their type converters at converting strings
private static object TryParse(object value, Type targetType, CultureInfo culture)
{
object result = DependencyProperty.UnsetValue;
string stringValue = value as string;
if (stringValue != null) {
try {
MethodInfo mi;
if (culture != null
&& (mi = targetType.GetMethod("Parse",
BindingFlags.Public | BindingFlags.Static, null,
new[] { typeof(string), typeof(NumberStyles), typeof(IFormatProvider) }, null))
!= null) {
result = mi.Invoke(null, new object[] { stringValue, NumberStyles.Any, culture });
}
else if (culture != null
&& (mi = targetType.GetMethod("Parse",
BindingFlags.Public | BindingFlags.Static, null,
new[] { typeof(string), typeof(IFormatProvider) }, null))
!= null) {
result = mi.Invoke(null, new object[] { stringValue, culture });
}
else if ((mi = targetType.GetMethod("Parse",
BindingFlags.Public | BindingFlags.Static, null,
new[] { typeof(string) }, null))
!= null) {
result = mi.Invoke(null, new object[] { stringValue });
}
} catch (TargetInvocationException) {
}
}
return result;
}
}
J'aime que cela utilise hors de la boîte WPF et que la méthode d'analyse pourrait facilement être adaptée à votre situation spécifique.
Ceci est une solution de Andrew Olson qui utilise des propriétés attachées et peut donc être utilisée dans différentes situations.
Utilisé comme ceci: p> L'aide requise: (public static class StringFormatHelper
{
#region Value
public static DependencyProperty ValueProperty = DependencyProperty.RegisterAttached(
"Value", typeof(object), typeof(StringFormatHelper), new System.Windows.PropertyMetadata(null, OnValueChanged));
private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
RefreshFormattedValue(obj);
}
public static object GetValue(DependencyObject obj)
{
return obj.GetValue(ValueProperty);
}
public static void SetValue(DependencyObject obj, object newValue)
{
obj.SetValue(ValueProperty, newValue);
}
#endregion
#region Format
public static DependencyProperty FormatProperty = DependencyProperty.RegisterAttached(
"Format", typeof(string), typeof(StringFormatHelper), new System.Windows.PropertyMetadata(null, OnFormatChanged));
private static void OnFormatChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
RefreshFormattedValue(obj);
}
public static string GetFormat(DependencyObject obj)
{
return (string)obj.GetValue(FormatProperty);
}
public static void SetFormat(DependencyObject obj, string newFormat)
{
obj.SetValue(FormatProperty, newFormat);
}
#endregion
#region FormattedValue
public static DependencyProperty FormattedValueProperty = DependencyProperty.RegisterAttached(
"FormattedValue", typeof(string), typeof(StringFormatHelper), new System.Windows.PropertyMetadata(null));
public static string GetFormattedValue(DependencyObject obj)
{
return (string)obj.GetValue(FormattedValueProperty);
}
public static void SetFormattedValue(DependencyObject obj, string newFormattedValue)
{
obj.SetValue(FormattedValueProperty, newFormattedValue);
}
#endregion
private static void RefreshFormattedValue(DependencyObject obj)
{
var value = GetValue(obj);
var format = GetFormat(obj);
if (format != null)
{
if (!format.StartsWith("{0:"))
{
format = String.Format("{{0:{0}}}", format);
}
SetFormattedValue(obj, String.Format(format, value));
}
else
{
SetFormattedValue(obj, value == null ? String.Empty : value.ToString());
}
}
}
J'ai besoin d'ajouter "chemin" et "RelateSource" pour le faire fonctionner. Stackoverflow.com/a/5832247/417939