RidableCthulu
RidableCthulu

Reputation: 471

Creating a grid filled with rectangles

I want to make something like this

ing1

and I can do that by hard coding rectangles into a grid with this code:

<Rectangle Grid.Column="0" Grid.Row="0" Fill="Black" />
<Rectangle Grid.Column="1" Grid.Row="0" Fill="Black" />
<Rectangle Grid.Column="2" Grid.Row="0" Fill="Black" />
<Rectangle Grid.Column="3" Grid.Row="0" Fill="Black" />
<Rectangle Grid.Column="4" Grid.Row="0" Fill="Black" />

However that is just for one line, and if I need different dimensions it can get pretty messy. Is there an easier way of achieving this while still being able to add events to each rectangle?

Upvotes: 5

Views: 1331

Answers (1)

McGarnagle
McGarnagle

Reputation: 102793

It is a bit tricky to bind a runtime-variable number of items to a Grid. One option is to use an ItemsControl, with a Grid as the ItemsPanel.

You would have a 2-dimensional array in the view-model, with each cell containing its row and column numbers. Use the ItemContainerStyle to bind the container's Grid.Row and Grid.Column attached properties to the cell view-model properties.

<ItemsControl ItemsSource="{Binding Cells}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Grid />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Grid.Row" Value="{Binding RowNumber}" />
            <Setter Property="Grid.Column" Value="{Binding ColumnNumber}" />
        </Style>
    </ItemsControl.ItemContainerStyle>

    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Rectangle Fill="Black" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>

</ItemsControl>

The piece that needs to be added to the above is adding the row/column definitions to the Grid. For this I would use attached properties that add those definitions for you, allowing you to bind the definitions to a property in your view model. That way, you can write something like:

        <ItemsPanelTemplate>
            <Grid GridHelpers.RowCount="{Binding RowCount}" 
                  GridHelpers.ColumnCount="{Binding ColumnCount}" />
        </ItemsPanelTemplate>

Finally, for the events, you can use an EventTrigger along with an InvokeCommandAction to trigger an ICommand on any event of the Rectangles.

        <DataTemplate>
            <Rectangle>
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseDoubleClick">
                        <i:InvokeCommandAction Command="{Binding RectangleClickCommand}"
                                               CommandParameter="{Binding}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Rectangle>
        </DataTemplate>

Upvotes: 3

Related Questions