Search code examples
wpfbindingtextboxobservablecollectionuniformgrid

How to bind TextBoxes to an ObservableCollection in an ItemsControl with UniformGrid


If in WPF I have this code:

using System.Collections.ObjectModel;

...
...

public partial class MainWindow : Window
{
    public ObservableCollection<String> myMatrixData = new ObservableCollection<String>();
    public MainWindow()
    {
        InitializeComponent();

        int i;
        for (i = 0; i < 100; i++)
            myMatrixData.Add("Test");

        myMatrix.ItemsSource = myMatrixData;
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        Cell00.Text = myMatrixData[0];
    }
}

XAML:

    xmlns:sys="clr-namespace:System;assembly=mscorlib" 
...
...
<Grid>
    <StackPanel>
        <ItemsControl x:Name="myMatrix">
            <ItemsControl.Resources>

            </ItemsControl.Resources>

            <ItemsControl.ItemsPanel>
                <!-- specify the panel that is the container for the items -->
                <ItemsPanelTemplate>
                    <UniformGrid Rows="10" Columns="10" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <!-- specify the template used to render each item -->
            <ItemsControl.ItemTemplate>
                <DataTemplate DataType="{x:Type sys:String[]}">
                    <TextBox Text="{Binding Path=., UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        <Button Content="Read cell 0/0" Click="Button_Click_1"/>
        <TextBlock x:Name="Cell00"/>
    </StackPanel>
</Grid>

I just want to reflect the elements in the ObservableCollection myMatrixData to be reflected in a UniformGrid-style ItemsControl named myMatrix. Changing the text in the first cell and pressing the button reveals that this doesn't work.

What am I missing?


Solution

  • ObservableCollection<string> does not update changes to the string because string itself does not implement INotifypropertyChanged

    try createing a simple model for your collection

    Example:

    private ObservableCollection<Matrix> _myMatrix = new ObservableCollection<Matrix>();
    
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
    
        for (int i = 0; i < 100; i++)
        {
            MyMatrix.Add(new Matrix { Value = "Test" + i });
        }
    }
    
    public ObservableCollection<Matrix> MyMatrix
    {
        get { return _myMatrix; }
        set { _myMatrix = value; }
    }
    
    .......
    
    
    public class Matrix : INotifyPropertyChanged
    {
        private string _value;
        public string Value
        {
            get { return _value; }
            set { _value = value; NotifyPropertyChanged("Value"); }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
    }
    

    Xaml:

    <Window x:Class="WpfApplication9.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication9"
            Title="MainWindow" Height="350" Width="525" Name="UI">
        <StackPanel>
            <ItemsControl x:Name="myMatrix" ItemsSource="{Binding MyMatrix}" >
                <ItemsControl.ItemsPanel>
                    <!-- specify the panel that is the container for the items -->
                    <ItemsPanelTemplate>
                        <UniformGrid Rows="10" Columns="10" />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <!-- specify the template used to render each item -->
                <ItemsControl.ItemTemplate>
                    <DataTemplate DataType="{x:Type local:Matrix}">
                        <TextBox Text="{Binding Path=Value, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
            <Button Content="Read cell 0/0" Click="Button_Click_1" />
            <TextBlock x:Name="Cell00" />
        </StackPanel>
    
    </Window>