AvaloniaUI/Avalonia · error · NotSupportedException

Two way bindings are not supported with a string format

Error message

Two way bindings are not supported with a string format

What it means

StringFormatValueConverter applies a display format (string.Format) to a value flowing source-to-target. It is inherently one-directional: there is no reliable way to reverse-parse a formatted string back into the original source value, so ConvertBack unconditionally throws NotSupportedException. The library throws it to fail fast rather than silently produce wrong data on the source side.

Source

Thrown at src/Avalonia.Base/Data/Converters/StringFormatValueConverter.cs:49

        /// </summary>
        public string Format { get; }

        /// <inheritdoc/>
        public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
        {
            value = Inner?.Convert(value, targetType, parameter, culture) ?? value;
            var format = Format!;
            if (!format.Contains('{'))
            {
                format = $"{{0:{format}}}";
            }
            return string.Format(culture, format, value);
        }

        /// <inheritdoc/>
        public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
        {
            throw new NotSupportedException("Two way bindings are not supported with a string format");
        }
    }
}

View on GitHub (pinned to 11c5427268)

Solutions

  1. Set the binding Mode to OneWay (or OneTime) so ConvertBack is never invoked.
  2. Remove StringFormat and instead expose a pre-formatted string property on the viewmodel, or format in the target's own display logic.
  3. Keep TwoWay but drop the StringFormat and apply formatting through a custom IValueConverter that implements a real ConvertBack parse step.

Example fix

// before
<TextBox Text="{Binding Amount, StringFormat=C, Mode=TwoWay}" />
// after - OneWay display cannot edit; for editable, drop the format
<TextBox Text="{Binding Amount, Mode=TwoWay}" />
<TextBlock Text="{Binding Amount, StringFormat=C}" />
Defensive patterns

Strategy: validation

Validate before calling

// Validate before applying: StringFormat is only valid on one-way display bindings.
Binding ValidateStringFormat(Binding b)
{
    if (!string.IsNullOrEmpty(b.StringFormat) &&
        (b.Mode == BindingMode.TwoWay || b.Mode == BindingMode.OneWayToSource))
    {
        throw new InvalidOperationException(
            "StringFormat cannot be used with TwoWay/OneWayToSource bindings.");
    }
    // Mode.Default may resolve to TwoWay for some targets (e.g. TextBox.Text);
    // force OneWay when a format is present unless you are sure.
    if (!string.IsNullOrEmpty(b.StringFormat) && b.Mode == BindingMode.Default)
        b.Mode = BindingMode.OneWay;
    return b;
}

Try / catch

// ConvertBack is on the hot path; prefer the validation above. If you wrap converters:
try { var back = converter.ConvertBack(v, t, p, c); }
catch (NotSupportedException) { /* StringFormat/one-way converter: ignore write-back */ }

Prevention

When it happens

Trigger: A binding with BindingMode.TwoWay or BindingMode.OneWayToSource whose Binding/StringFormatValueConverter also has a non-null StringFormat. The mode default for some targets (e.g. TextBox.Text) is TwoWay, so simply adding a StringFormat to such a binding triggers it even when Mode is left unset.

Common situations: Adding StringFormat='C' or StringFormat='N2' to a TwoWay TextBox.Text binding to pretty-print currency/numbers; enabling StringFormat on a TwoWay Slider.Value or ComboBox.SelectedItem binding; upgrading a OneWay binding to TwoWay without removing the format.

Related errors


AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13). Data as JSON: /api/errors/49f1f134535fdaad. Report an issue: GitHub.