Search code examples
c#uwpwindows-runtimeuwp-xaml

BindingExpression path error when attempting to bind to a C# class field


I have a fairly straightforward binding (with {Binding}, not {x:Bind}) that is not working:

<ListView
    ItemsSource="{x:Bind ViewModel.Items, Mode=OneWay}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:Item">
            <StackPanel>
                <TextBlock Text="{Binding MyField}" />
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

It compiles, but fails with the error message:

Error: BindingExpression path error: 'MyField' property not found on 'MyNamespace.Item'. BindingExpression: Path='MyField' DataItem='MyNamespace.Item'; target element is 'Windows.UI.Xaml.Controls.TextBlock' (Name='null'); target property is 'Text' (type 'String')

The same binding works with x:Bind:

<TextBlock Text="{x:Bind MyField}" />

ViewModel and Item definitions


namespace MyNamespace
{
    public class Item : INotifyPropertyChanged
    {
        public Item()
        {
            // ...
        }

        public readonly string MyField = "Foo";

        // ...
    }
    
    public class MainPageViewModel : INotifyPropertyChanged
    {
        public MainPageViewModel()
        {
            // ...
        }

        private ItemsCollection _itemsCollection = new ItemsCollection();
        public ObservableCollection<Item> Items
        {
            get { return _itemsCollection.Items; }
        }
        
        // ...
    }
}

Disclaimer: I work for Microsoft.


Solution

  • MyField is a C# class field, which cannot be bound to with {Binding}.

    To avoid this, change MyField to a property:

    public class Item : INotifyPropertyChanged
    {
        // ...
        private readonly string m_myField = "Foo";
        public string MyField { get => m_myField; }
    
    }
    

    Then {Binding MyField} will work properly.

    See this StackOverflow question about the difference between C# fields and properties:

    4. Only Properties can be used in Binding Source

    Binding Source helps us to decrease the number of lines of code. Fields are not accepted by BindingSource. We should use Properties for that.

    This seems to be similar to WPF (which also can't bind on fields).