I’ve got an ItemsControl bound to a collection of extremely basic ViewModels, that each have a row\col Postion property. I’m also using Caliburn.Micro MVVM Framework, it automatically uses the matching View (Which is just a simple rectangle, with a Fill=”Transparent”) I’m filling the Grid up at the start with these, so I can add ContextMenus to them, and know what cell has been clicked etc.
The ItemsPanelTemplate is a Grid, and the ItemContainerStyle binds the Grid.Row\Column to the Position.X\Y property.
This screen is an Screen Editor for making emulations of an old 80×25 text mode system, that originally used a custom raster font to draw some simple graphics. Original system could handle 8 of those screens. I’m using rectangles and vector drawings for flexibility, as well as expand the screen size to any size.
First idea, was to simply for(i){for(j){Add}} loop through the grid, and add a new BlankVM to every cell.
It works, but as it has to do it 2000 time, it’s very slow. The binding etc is fast, but it adds up over that many. Since the potential screen size can be as large as needed, it’s
going to choke. Right now its about 40+ seconds.
I’m not that great a programmer (yet!) so I’m at a loss.
Can I replace the for loop with something more efficient?
Since the BlankCells are all the same except for a Position(row, column), can I take advantage of that?
Maybe I don’t even need to be adding all these to the grid, if there is a simpler way to be able to use a contextmenus and know what cell I’m clicking on…
here’s the code:
public class BlankCellViewModel : PropertyChangedBase, IEditorCell
{
public GridPosition Position { get; set; }
public BlankCellViewModel(GridPosition position) {
Position = position;
}
}
And the View
<UserControl x:Class="EditorCells.BlankCellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Rectangle>
<Rectangle.ContextMenu>
<ContextMenu>
<MenuItem Header="New Track Segment Here" />
</ContextMenu>
</Rectangle.ContextMenu>
<Rectangle.Style>
<Style>
<Setter Property="Rectangle.Fill"
Value="Transparent" />
<Style.Triggers>
<Trigger Property="Rectangle.IsMouseOver"
Value="True">
<Setter Property="Rectangle.Fill"
Value="White" />
</Trigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</UserControl>
From the containing Viewmodel, the loop in question
private void SetupEditorGrid()
{
EditorMap.Resize(MaxRow, MaxColumn);
for (int i = 0; i < MaxRow; i++)
{
for (int j = 0; j < MaxColumn; j++)
{
AddCell(new BlankCellViewModel(new GridPosition(j, i)));
}
}
}
and its view:
<UserControl x:Class="EditorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ap="clr-namespace:Support.AttachedProperties;assembly=Systems"
HorizontalAlignment="Center">
<ItemsControl x:Name="EditorCells">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid ShowGridLines="True"
Background="Black"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ap:GridHelpers.RowCount="{Binding RowCount}"
ap:GridHelpers.ColumnCount="{Binding ColumnCount}" >
<Grid.Resources>
<Style TargetType="{x:Type ColumnDefinition}">
<Setter Property="Width"
Value="8" />
</Style>
<Style TargetType="{x:Type RowDefinition}">
<Setter Property="Height"
Value="16" />
</Style>
</Grid.Resources>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Row"
Value="{Binding Position.Row}" />
<Setter Property="Grid.Column"
Value="{Binding Position.Column}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</UserControl>
Messed with thise some more.
Since the grid cells are a known, fixed sized, used MouseMove event handler to calc the cell the mouse is over, and used a contextmenu on the grid itself.