Toute tentative de modifier TextBox
propriétés de l'intérieur du ControlTemplate
sera en désordre, donc je vous recommande de le faire dans le Style
au lieu du ControlTemplate
si possible. Je vais commencer par expliquer comment le faire avec un Style
puis expliquer comment adapter la technique pour l'utiliser dans un ControlTemplate
si nécessaire.
Ce que vous devez faire est de créer une propriété attachée qui peut être utilisé comme ceci:
<Style x:Name="TextBoxStyleBase2" TargetType="TextBox">
<Setter Property="local:ConverterInstaller.TextPropetyConverter"
Value="{StaticResource MyConverter}" />
...
</Style>
La classe ConverterInstaller
a simple propriété jointe qui installe le convertisseur dans une Binding
initialement fixé sur le TextBox
:
public class ConverterInstaller : DependencyObject
{
public static IValueConverter GetTextPropertyConverter(DependencyObject obj) { return (IValueConverter)obj.GetValue(TextPropertyConverterProperty); }
public static void SetTextPropertyConverter(DependencyObject obj, IValueConverter value) { obj.SetValue(TextPropertyConverterProperty, value); }
public static readonly DependencyProperty TextPropertyConverterProperty = DependencyProperty.RegisterAttached("TextPropertyConverter", typeof(IValueConverter), typeof(Converter), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
var box = (TextBox)obj;
box.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
var binding = BindingOperations.GetBinding(box, TextBox.TextProperty);
if(binding==null) return;
var newBinding = new Binding
{
Converter = GetTextPropertyConverter(box),
Path = binding.Path,
Mode = binding.Mode,
StringFormat = binding.StringFormat,
}
if(binding.Source!=null) newBinding.Source = binding.Source;
if(binding.RelativeSource!=null) newBinding.RelativeSource = binding.RelativeSource;
if(binding.ElementName!=null) newBinding.ElementName = binding.ElementName;
BindingOperations.SetBinding(box, TextBox.TextProperty, newBinding);
}));
}
});
}
La seule complexité est ici:
- L'utilisation de Dispatcher.BeginInvoke pour s'assurer que la mise à jour de liaison se produit après le chargement du XAML et tous les styles sont appliqués, et
- La nécessité de copier les propriétés de liaison dans une nouvelle liaison pour changer le convertisseur, puisque la liaison d'origine est scellée
pour fixer cette propriété à un élément à l'intérieur du ControlTemplate au lieu de le faire dans le style, le même code est utilisé, sauf l'objet d'origine dans le passé PropertyChangedCallback est jeté var element = (FrameworkElement)obj;
et à l'intérieur de l'action Dispatcher.BeginInvoke la zone de texte réelle est trouvé avec var box = (TextBox)element.TemplatedParent;
Un grand merci! Cela a bien fonctionné. J'ai seulement dû modifier la copie de la nouvelle liaison puisque, Source et RelativeSource ne peuvent pas tous les deux être placés en même temps (même s'ils ont la valeur NULL). J'ai donc ajouté quelques vérifications avant de les attribuer. Si NULL, je ne définis pas la propriété. – joerage
Merci pour les commentaires. J'ai mis à jour ma réponse pour faire la même chose. –