wis.niowy
wis.niowy

Reputation: 87

WPF list binding fails

I've followed the instruction from here. Nevertheless my binding seems to fail for I have no result in my window. What I want to do is simply to bind a list if items to ListView. XAML file content:

<Window x:Class="IV_sem___PwSG___WPF_task1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:IV_sem___PwSG___WPF_task1"
    mc:Ignorable="d"
    Title="MainWindow" Height="600" Width="800"
    MinHeight="500" MinWidth="500">
<Window.Resources>
    <DataTemplate x:Key="MyItemTemplate">
        <Grid Margin="5" Background="Aqua">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding Name}" Grid.Column="0" Grid.Row="0"
                       FontSize="18" FontFamily="Arial"></TextBlock>
            <TextBlock Text="{Binding Description}" Grid.Column="0" Grid.Row="1"
                       FontSize="14" FontFamily="Arial"></TextBlock>
            <TextBlock Text="{Binding Category}" Grid.Column="0" Grid.Row="2"
                       FontSize="12" FontFamily="Arial"></TextBlock>
            <TextBlock Text="{Binding Price}" Grid.Column="1" Grid.RowSpan="1"></TextBlock>
            <Button Content="Add to cart" Grid.Column="2" Grid.Row="1"/>
        </Grid>
    </DataTemplate>
</Window.Resources>
<!--<Window.DataContext>
    <local:MainWindow />
</Window.DataContext>-->

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <Menu Grid.Column="0" Grid.Row="0">
        <MenuItem Header="File">
            <MenuItem Header="Load"/>
            <MenuItem Header="Save"/>
            <Separator/>
            <MenuItem Header="Exit" Click="ExitMenuItem_Click"/>
        </MenuItem>
        <MenuItem Header="Products">
            <MenuItem Header="Add products" Click="AddProductMenuItem_Click"/>
            <MenuItem Header="Clear products"/>
        </MenuItem>
        <MenuItem Header="About" Click="AboutMenuItem_Click"/>
    </Menu>

    <TabControl Grid.Column="0" Grid.Row="1">
        <TabItem Header="Shop">
            <!--<Grid>-->
            <ListView ItemsSource="{Binding itemList}"
                      ItemTemplate="{StaticResource MyItemTemplate}"/>
            <!--</Grid>-->
        </TabItem>
        <TabItem Header="Warehouse">

        </TabItem>
    </TabControl>
</Grid>

.cs file content:

namespace IV_sem___PwSG___WPF_task1{
public partial class MainWindow : Window
{
    public List<Item> itemList { get; set; }

    public MainWindow()
    {
        itemList = new List<Item>();
        InitializeComponent();
    }

    private void AboutMenuItem_Click(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("This is simple shop manager.", "About application", MessageBoxButton.OK, MessageBoxImage.Information);
    }

    private void ExitMenuItem_Click(object sender, RoutedEventArgs e)
    {
        this.Close();
    }

    public class Item
    {
        string Name { get; set; }
        string Description { get; set; }
        Category Category { get; set; }
        double Price { get; set; }
        public Item(string a, string b, Category c, double d)
        {
            Name = a; Description = b; Category = c; Price = d;
        }

    }

    private void AddProductMenuItem_Click(object sender, RoutedEventArgs e)
    {
        itemList.Add(new Item("Computer", "Computer's description", Category.Electronics, 2499.99));
        itemList.Add(new Item("Apple", "Apple's description", Category.Food, 1.99));
        itemList.Add(new Item("Computer", "Computer's description", Category.Electronics, 2499.99));
    }
}

public enum Category
{
    Electronics, Food
}
}

Category is an enum type. List is a property of MainWindow class. It should be working according to the link above.

Upvotes: 1

Views: 104

Answers (2)

user2819245
user2819245

Reputation:

The code in the question has three problems.

1. The ListView.ItemsSource binding

The program does not set the DataContext for the ListView or one of its parent containers. So the binding in <ListView ItemsSource="{Binding itemList}" ... /> cannot be resolved.

Since itemList is a property of the MainWindow itself, as a quick fix i suggest to bind the MainWindow DataContext to the MainWindow itself:

<Window x:Class="IV_sem___PwSG___WPF_task1.MainWindow"
    ...
    ...
    x:Name="Self"
    DataContext="{Binding ElementName=Self}"
>


2. The itemList

itemList is just a simple List<T> collection. List<T> does not have a built-in mechanism to inform the ListView and the binding engine whenever items have been added to or removed from the list. When the program adds items to the itemList in the AddProductMenuItem_Click handler, the ListView will not update, simply because it is not being notified that the itemList has been changed.

The fix is rather simple: Use ObservableCollection<T> instead of List<T>. ObservableCollection provides notifications about item addition and removal. These notifications are being understood by WPF and enable the ListView to refresh its view whenever the collection has been altered.


3. The Item class

The itemList collection contains Item objects. UI elements in the item template used by the ListView bind to properties of these Item objects. However, the properties of the Item class are not public. The binding to these properties fails if they are not public.

The fix, again, is rather straightforward: Make all properties participating in bindings public.

Upvotes: 1

A. S. Mahadik
A. S. Mahadik

Reputation: 625

Use Observable collection instead of List as below

public ObservableCollection<Item> itemList { get; set; }

because Observable Collection implemented using INotifyCollectionChanged, INotifyPropertyChanged it's notify collection change event and update UI.

Upvotes: 1

Related Questions