WPF – DataBinding, ConverterParameter und Property in einem UserControl

Veröffentlicht von

Ein Problem von DataBinding in WPF ist, dass der ConverterParameter nicht an ein Property gebunden werden kann.

A ‚Binding‘ cannot be set on the ‚ConverterParameter‘ property of type ‚Binding‘.
A ‚Binding‘ can only be set on a DependencyProperty of a DependencyObject.

Soweit so gut. In meinem Fall wollte ich einem Converter die Anzahl der Nachkommastellen für ein Textfeld mitgeben:

Das Textfeld ist zudem ein UserControl, so dass ich die Anzahl nicht fest vorgeben möchte, sondern über ein Property des Controls.

Im Internet findet man viele Beispiele wie hier ein MultiBinding verwendet werden kann. Das funktioniert zwar, aber nur in eine Richtung. Die Konvertierung zurückmacht hier Probleme, da hier ein Array zurückgegeben wird.

Im Internet habe ich daher den folgenden Ansatz gefunden. Dem Konverter füge man ein eigenes Property hinzu, in meinem Fall die Anzahl der Nachkommastellen:

public class NumericUpDownDigitConverter : FrameworkElement, IValueConverter
{
    public int Digits { get; set; } = 1;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var decimalValue = (Decimal)value;

        string formatString = "0.";

        for (int i = 0; i < Digits; i++) formatString += "0";
        string result = decimalValue.ToString(formatString);

        return result;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        try
        {
            return System.Convert.ToDecimal(value);
        } catch (Exception)
        {
            return Binding.DoNothing;
        }
        
    }
}

Dies könnten wir nun dem Konverter in den Resourcen mitgeben:

<conv:NumericUpDownDigitConverter x:Key="NumericUpDownDigitConverter" Digits="3"></conv:NumericUpDownDigitConverter>

Allerdings ist hier nur eine statische Angabe möglich, ich möchtes dies ja dem UserControl als DependecyProperty mitgeben:

<components:NumericUpDownControl Grid.Column="1"
                                    Grid.Row="1"
                                    Digits="4"
                                    StepSize="5"
                                    ></components:NumericUpDownControl>

In den Resourcen können wir aber kein Binding verwenden, da dieses statisch eingebunden wird. Die Lösung ist, das Binding manuell im Code zu erstellen:

private Binding _inputBinding;
private NumericUpDownDigitConverter _converter;

Das Binding für die Textbox erstellen wir im Kontruktor des UserControls:

public NumericUpDownControl()
{
    //init binding
    _inputBinding = new Binding("Value");
    _inputBinding.Mode = BindingMode.TwoWay;
    _inputBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
    _converter = new NumericUpDownDigitConverter();
    _converter.Digits = this.Digits;
    _inputBinding.Converter = _converter;
    TextInput.SetBinding(TextBox.TextProperty, _inputBinding);
}

Ganz am Ziel sind wir noch nicht, da wir noch eine Aktualisierung benötigen, wenn sich das Property „Digits“ des UserControls von außen ändert. Dazu passen wir unser DependencyProperty entsprechend an:

public static readonly DependencyProperty DigitsProperty =
    DependencyProperty.Register("Digits", typeof(int),
        typeof(NumericUpDownControl), new PropertyMetadata(2, new PropertyChangedCallback(OnDigitsChanged)));

private static void OnDigitsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ((NumericUpDownControl)d).OnUnitChanged(e);
}

private void OnUnitChanged(DependencyPropertyChangedEventArgs e)
{
    if (_converter != null)
    {
        _converter.Digits = (int)e.NewValue;
        TextInput.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
    }                
}

In „OnUnitChanged“ aktualisieren wir bei Änderung der Anzahl der Nachkommastellen, das Property in unserem Konverter. Das wars, anschließend wird die Eigenschaft aus dem Xaml-Code übernommen:

Kommentar hinterlassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert