Search code examples
c#wpfxamlbinding

Why am I not able to bind StringFormat on code behind the same way I did on XAML?


Here's my working example, which bind correctly the ViewModel and trigger correctly StringFormat and ValidateMaskDecimal:

<ListBox x:Name="Difetti"
         ItemsSource="{Binding Difetti}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBox x:Name="Metro"
                         controls:TextBoxHelper.Watermark="Metro"
                         PreviewTextInput="ValidateMaskDecimal">
                    <TextBox.Text>
                        <Binding Path="Metro"
                                 StringFormat="{}{0:0.0##########}">
                        </Binding>
                    </TextBox.Text>
                </TextBox>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Now, if I try to do somethings similar on code behind (removing ListBox, and bind a unique TextBox to the data model at some specific index = 0):

<TextBox x:Name="Metro"
         controls:TextBoxHelper.Watermark="Metro"
         PreviewTextInput="ValidateMaskDecimal" />
    var data = DataContext as ViewModelData;
    if (data != null && data.Difetti.Count > 0) {   
        int difettoIndex = 0;   
        Metro.SetBinding(TextBox.TextProperty, new Binding
        {
            Source = data,
            Path = new PropertyPath($"Difetti[{difettoIndex}].Metro"),
            StringFormat = "{}{0:0.0##########}"
        });
    }

it throws a ValueStringBuilder's ThrowFormatError exception: System.FormatException: 'Input string was not in a correct format.'.

I don't get why. Where am I wrong? Shouldn't the code give to me the same result?

Metro on DataModel its configured this way (nullable decimal):

private decimal? metro;
public decimal? Metro
{
    get { return metro; }
    set { SetField(ref metro, value, "Metro"); }
}

Solution

  • {} prefixed to the string format is specific for XAML. You don't need it in code.

    Of course, you can check the string format text created in XAML.

    BindingExpression expression = BindingOperations.GetBindingExpression(Metro, TextBox.TextProperty);
    string format = expression.ParentBinding.StringFormat;
    Debug.WriteLine(format);