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: