Click here to Skip to main content
15,867,568 members
Articles / Desktop Programming / WPF

Grid with Dynamic Number of Rows and Columns - Part 1

Rate me:
Please Sign up or sign in to vote.
5.00/5 (6 votes)
3 Jan 2017CPOL2 min read 31.8K   2.9K   11   2
WPF datagrid that has same sized dynamically defined number of rows and columns
The post demonstrates WPF data grid with dynamically defined number of rows and columns, but all cells have the same size.

Introduction

The post is devoted to the WPF data grid with dynamically defined number of rows and columns, but all cells have the same width and the same height. For example, such grid could be used in chess or checkers games for 8x8 field.

Image 1

The application has the following features:

  1. Number of rows and columns can be changed at run-time
  2. All cells has the same width and the same height
  3. Grid occupies as much space as possible
  4. Input click switches the state of the cell

Background

The solution uses C#6, .NET 4.6.1, WPF with MVVM pattern.

Solution

WPF Application

Image 2WPF application is done in MVVM pattern with one main window. Dynamic grid is implemented as user control that contains DataGrid control bound to observable collection of collections of cell view models. In this implementation, collection of cells is recreated each time if grid width or grid height is changed, and it leads to some application pauses. In the following post, this issue is solved with asynchronous method that updates cell array. Also, other implementation for cells could be used; for example, 2-dimensional array of cells ICellViewModels[][] works well.

Behind Code

Image 3

Dynamic grid view model implements IDynamicGridViewModel interface that has two size’s properties for grid width and height that are number of rows and columns, observable collection of collections of cell view models, and several color properties:

C#
public interface IDynamicGridViewModel
{
  /// <summary>
  /// 2-dimensional collections for CellViewModels.
  /// </summary>
  ObservableCollection<ObservableCollection<ICellViewModel>>
    Cells { get; }

  /// <summary>
  /// Number of grid columns.
  /// </summary>
  int GridWidth { get; }

  /// <summary>
  /// Number of grid rows.
  /// </summary>
  int GridHeight { get; }

  /// <summary>
  /// Start, the lightest, color of cells.
  /// </summary>s
  Color StartColor { get; set; }

  /// <summary>
  /// Finish, the darkest, color of cells.
  /// </summary>
  Color FinishColor { get; set; }

  /// <summary>
  /// Color of borders around cells.
  /// </summary>
  Color BorderColor { get; set; }
}

Values of color properties are assigned to corresponding properties of CellView control. View model for each cell implements ICellViewModel interface that defines property for data model that implements ICell interface and command for changing state for the cell.

C#
public interface ICellViewModel
{
  ICell Cell { get; set; }
  ICommand ChangeCellStateCommand { get; }
}

And, finally, ICell interface contains one Boolean property State:

C#
public interface ICell
{
  /// <summary>
  /// State of the cell.
  /// </summary>
  bool State { get; set; }
}

XAML

The same height of cells is controlled by RowHeight property defined in style of DataGrid:

XML
<Style TargetType="{x:Type DataGrid}">
  <Setter Property="RowHeight">
    <Setter.Value>
      <MultiBinding Converter="{StaticResource DivideDoubleConverter}"
                    ConverterParameter="2">
        <Binding RelativeSource="{RelativeSource Self}"
                 Path="ActualHeight" Mode="OneWay"
                 Converter="{StaticResource SubstractConverter}"
                 ConverterParameter="2"/>
        <Binding Path="DataContext.GridHeight"
                 RelativeSource="{RelativeSource Self}"
                 Mode="OneWay"/>
      </MultiBinding>
    </Setter.Value>
  </Setter>
</Style>

Cell height equals to actual height of data grid minus 2 divided by number of rows. The same width of cells is controlled by Width property of cell data template:

XML
<DataTemplate x:Key="CellTemplate">
  <Border BorderBrush="Transparent"
      BorderThickness="1 0 1 0"
      DataContext="{Binding}">
    <Border.Width>
      <MultiBinding Converter="{StaticResource DivideDoubleConverter}" ConverterParameter="2">
        <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}"
              Path="ActualWidth" Mode="OneWay"
              Converter="{StaticResource SubstractConverter}" ConverterParameter="2"/>
        <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}"
              Path="DataContext.GridWidth" Mode="OneWay"/>
      </MultiBinding>
    </Border.Width>

    <views:CellView
      DataContext="{Binding}"
      BorderColor="{Binding DataContext.BorderColor,
              RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}},
              Mode=OneWay, FallbackValue=#FF000000}"
      StartColor="{Binding DataContext.StartColor,
              RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}},
              Mode=OneWay, FallbackValue=#FFF0F0F0}"
      FinishColor="{Binding DataContext.FinishColor,
              RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}},
              Mode=OneWay, FallbackValue=#FF0F0F0F}"/>
  </Border>
</DataTemplate>

Similarly, cell width equals to actual width of data grid minus 2 divided by number of columns. And there is a definition of DataGrid control:

XML
<DataGrid
  x:Name="DynamicGrid"
  DataContext="{Binding}"
  ItemsSource="{Binding Path=Cells}"
  IsEnabled="True"
  IsTabStop="False">

  <DataGrid.Columns>
    <DataGridTemplateColumn Width="*">
      <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
          <ItemsControl ItemsSource="{Binding}"
                ItemTemplate="{DynamicResource CellTemplate}">
            <ItemsControl.ItemsPanel>
              <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"/>
              </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
          </ItemsControl>
        </DataTemplate>
      </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
  </DataGrid.Columns>
</DataGrid>

Conclusion

In the following article, the following features will be implemented:

  1. Asynchronous method of adding/deleting cells
  2. Resize timer that prevents too frequent cell updating
  3. Preserve active cells
  4. Fixed size of cells
  5. Dependency container
  6. Logging

History

  • 3rd January, 2017: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Ukraine Ukraine
• Have more than 25 years of the architecting, implementing, and supporting various applications from small desktop and web utilities up to full-fledged cloud SaaS systems using mainly Microsoft technology stack and implementing the best practices.
• Have significant experience in the architecting applications starting from the scratch and from the existent application (aka “legacy”) where it is required to review, refactor, optimise the codebase and data structure, migrate to new technologies, implement new features, best practices, create tests and write documentation.
• Have experience in project management, collecting business requirements, creating MVP, working with stakeholders and end users, and tasks and backlog management.
• Have hands-on experience in the setting up CI/CD pipelines, the deploying on-premise and cloud systems both in Azure and AWS, support several environments.
• As Mathematician, I interested much in the theory of automata and computer algebra.

Comments and Discussions

 
Questionsource code download links are broken. Pin
Tridip Bhattacharjee3-Jan-17 21:42
professionalTridip Bhattacharjee3-Jan-17 21:42 
AnswerRe: source code download links are broken. Pin
Illya Reznykov4-Jan-17 0:24
Illya Reznykov4-Jan-17 0:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.