2

I'm using this blog post to implement a dynamic grid.

However, I can't seem to get it working when I change the row count and column count on my global class variables.

I'm using the GridHelpers.cs class from the above link and my UserControl xaml looks like this

<UserControl x:Class="WPFPurpleButtonTest.InstrumentUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPFPurpleButtonTest"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Label x:Name="colourName" Content="PURPLE" HorizontalAlignment="Left" Height="93" Margin="284,88,0,0" VerticalAlignment="Top" Width="243" FontWeight="Bold" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontSize="50" Foreground="#FFDC00FF"/>
        <Button x:Name="testButton" Content="Button" HorizontalAlignment="Left" Margin="354,234,0,0" VerticalAlignment="Top" Width="75" Click="TestButton_Click"/>
        <Label x:Name="label" Content="Row Size" HorizontalAlignment="Left" Margin="222,296,0,0" VerticalAlignment="Top" Foreground="#FFDC00FF"/>
        <Label x:Name="label_Copy" Content="Column Size" HorizontalAlignment="Left" Margin="438,296,0,0" VerticalAlignment="Top" Foreground="#FFDC00FF"/>
        <Button x:Name="createGrid" Content="Create Grid" HorizontalAlignment="Left" Margin="357,348,0,0" VerticalAlignment="Top" Width="75" Click="CreateGrid_Click"/>
        <TextBox x:Name="rowSizeText" HorizontalAlignment="Left" Height="23" Margin="296,299,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="62"/>
        <TextBox x:Name="columnSizeText" HorizontalAlignment="Left" Height="23" Margin="528,300,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="62"/>
        <Grid local:GridHelpers.RowCount="{Binding RowCount}"
      local:GridHelpers.ColumnCount="{Binding ColumnCount}" ></Grid>
    </Grid>
</UserControl>

My CS code looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WPFPurpleButtonTest
{
    /// <summary>
    /// Interaction logic for InstrumentUserControl.xaml
    /// </summary>
    public partial class InstrumentUserControl : UserControl
    {
        // We should put this in a separate user control, but for now for testing
        // let's put the grid configuration in here
        public int RowCount { get; set; }
        public int ColumnCount { get; set; }

        public InstrumentUserControl()
        {
            InitializeComponent();
            DataContext = this;
        }

        private void TestButton_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("HELLO!", "Greetings", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        private void CreateGrid_Click(object sender, RoutedEventArgs e)
        {
            if (int.TryParse(rowSizeText.Text, out int rowResult))
            {
                RowCount = rowResult;
            }

            if (int.TryParse(columnSizeText.Text, out int columnResult))
            {
                ColumnCount = rowResult;
            }
        }
    }
}

Any help would be appreciated where I'm going wrong as I type the row count and column count into the text boxes and press my button, but the GridHelpers row count and column count changed event don't get called.

Also I changed my properties to this, but in the GridHelpers class in the change event, the obj comes up as InstrumentUserControl rather than Grid so it just returns.

public int RowCount
{
    get { return (int)GetValue(GridHelpers.RowCountProperty); }
    set { SetValue(GridHelpers.RowCountProperty, value); }
}
public int ColumnCount
{
    get { return (int) GetValue(GridHelpers.ColumnCountProperty); }
    set { SetValue(GridHelpers.ColumnCountProperty, value); }
}
CSDev
  • 3,177
  • 6
  • 19
  • 37
slickchick2
  • 137
  • 9

1 Answers1

0

You have to implement INotifyPropertyChanged on the ViewModel class. In your case you have set "DataContext = this", so you have to implement INotifyPropertyChanged on the UserControl class.

I have defined more or less the minimum possible implementation ...

using System.Windows;
using System.ComponentModel;

namespace GridHelperTest
{
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow : Window, INotifyPropertyChanged
  {
    public int RowCount { get; set; }
    public int ColumnCount { get; set; }

    public MainWindow ( )
    {
      InitializeComponent ();
      DataContext = this ;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void TestButton_Click (object sender, RoutedEventArgs e)
    {
      MessageBox.Show ( "HELLO!", "Greetings", MessageBoxButton.OK, MessageBoxImage.Information );
    }

    private void CreateGrid_Click (object sender, RoutedEventArgs e)
    {
      if (int.TryParse ( rowSizeText.Text, out int rowResult ))
      {
        RowCount = rowResult;
        OnPropertyChanged("RowCount");
      }

      if (int.TryParse ( columnSizeText.Text, out int columnResult ))
      {
        ColumnCount = rowResult;
        OnPropertyChanged("ColumnCount");
      }
    }
    protected virtual void OnPropertyChanged(string propertyName = null)
    {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
  }
}

calling OnPropertyChanged after setting the properties. Normally you would want to do this in a property setter method.

To test it, I defined some colored rectangles in the grid. These are initially on top of one another, but after setting the number of rows and columns they are positioned in separate cells.

<Window x:Class="GridHelperTest.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:GridHelperTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="900" Width="800">

  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="*"/>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <Grid Grid.Row="0">
      <Label x:Name="colourName" Content="PURPLE" HorizontalAlignment="Left" Height="93" Margin="284,88,0,0" VerticalAlignment="Top" Width="243" FontWeight="Bold" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontSize="50" Foreground="#FFDC00FF"/>
      <Button x:Name="testButton" Content="Button" HorizontalAlignment="Left" Margin="354,234,0,0" VerticalAlignment="Top" Width="75" Click="TestButton_Click"/>
      <Label x:Name="label" Content="Row Size" HorizontalAlignment="Left" Margin="222,296,0,0" VerticalAlignment="Top" Foreground="#FFDC00FF"/>
      <Label x:Name="label_Copy" Content="Column Size" HorizontalAlignment="Left" Margin="438,296,0,0" VerticalAlignment="Top" Foreground="#FFDC00FF"/>
      <Button x:Name="createGrid" Content="Create Grid" HorizontalAlignment="Left" Margin="357,348,0,0" VerticalAlignment="Top" Width="75" Click="CreateGrid_Click"/>
      <TextBox x:Name="rowSizeText" HorizontalAlignment="Left" Height="23" Margin="296,299,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="62"/>
      <TextBox x:Name="columnSizeText" HorizontalAlignment="Left" Height="23" Margin="528,300,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="62"/>

    </Grid>
    <Grid Grid.Row="1"
          local:GridHelpers.RowCount="{Binding RowCount}"
          local:GridHelpers.ColumnCount="{Binding ColumnCount}">
      <Rectangle Grid.Row="0" Grid.Column="0" Fill="Red" Width="100" Height="100"/>
      <Rectangle Grid.Row="0" Grid.Column="1" Fill="Green" Width="100" Height="100"/>
      <Rectangle Grid.Row="1" Grid.Column="0" Fill="Blue" Width="100" Height="100"/>
      <Rectangle Grid.Row="1" Grid.Column="1" Fill="Yellow" Width="100" Height="100"/>

    </Grid>
  </Grid>
</Window>

That is not exactly identical to your XAML, because I defined it in a Window not a UserControl.

Phil Jollans
  • 3,605
  • 2
  • 37
  • 50
  • Ah this is awesome Phil! It works! So all I was doing wrong was not calling the OnPropertyChanged and implementing INotifyPropertyChanged? I wonder why I needed to implement that.... – slickchick2 Jul 30 '19 at 21:51
  • That is how the Binding mechanism works. The PropertyChanged event is what tells WPF that the property has changed. – Phil Jollans Jul 30 '19 at 21:54
  • I seeeeeeeee.. *sighs* i've got alot to learn... thanks man! You've saved me a headache.... I've been stressing for hours! – slickchick2 Jul 30 '19 at 22:02
  • Would it be easy to create a collection of "rectangles" for example? So if your grid has 3 rows and 3 columns, it'll populate with 9 rectangles? – slickchick2 Jul 30 '19 at 22:13
  • @Phil looks like an error propagated through in the body of the second if statement. rowResult should be columnResult – namg_engr Aug 22 '19 at 05:21