So to be frank I have previously posed this on StackOverflow without getting any particularly helpfull answers, I accept there might be arguably better ways of structuring the code but I want partly to understand the limitations of the Canvas object (if indeed that is the problem) and as there were two
voices on SO suggesting the use of "ItemControls as layers", why that method might be a better solution.
So, I was intending to overlay multiple Canvas, between 4 and 6 layers, on top of a large Image, in order that I can set all objects in a given Canvas as visible or invisable with the simplicity of a show or Hide routine in a layer class. UpdateLayers simply has a set of calls to each layer.Update(). In the case of the settlementNames layer, it would seem that the Update code is not doing its job. It is supposed work like this;
private void ShowCities_Click(object sender, RoutedEventArgs e)
{
UpdateLayers();
settlements.Show(Settlements);
settlementNames.Show(SettlementNames);
}
public void Show(Canvas canvas)
{
canvas.Visibility = Visibility.Visible;
}
This worked perfectly with the first canvas containing icon sized BitmapImages at ZIndex 1 (the large Image is essentially the background with ZIndex 0). When I tried to add a further canvas at ZIndex 2, the code steps through as expected but does not show the contents. This time the contents is a set of TextBlocks.
The AssociatedCanvas property in the code, has been checked and is the correct Canvas instance, which was laid down in the XAML main window.
public void Update(string layerSelectSqlQuery, LayerType layerType)
{
DataTable layerDataTable = null;
int x = -1;
int y = -1;
string label;
using (MySqlClientWrapper db = new MySqlClientWrapper("Server = localhost; Database = tribes;Uid = root;Pwd = xxxxxxxxx;"))
{
layerDataTable = db.GetDataTable(layerSelectSqlQuery);
}
AssociatedCanvas.Children.Clear();
foreach (DataRow dataRow in layerDataTable.Rows)
{
x = (int)dataRow["MapX"];
y = (int)dataRow["MapY"];
label = dataRow["Name"].ToString();
if (x != -1 && y != -1)
{
switch (layerType)
{
case LayerType.Settlements:
DrawBitmapImage(x, y);
break;
case LayerType.SettlementNames:
WriteLabel(x, y, label, Color.FromRgb(0, 0, 0));
break;
case LayerType.Units:
break;
case LayerType.UnitNames:
break;
default:
break;
}
}
}
}
Public void WriteLabel(int x, int y, string text, Color color)
{
TextBlock textBlock = new TextBlock();
textBlock.Text = text;
textBlock.Foreground = new SolidColorBrush(color);
Canvas.SetLeft(textBlock, x);
Canvas.SetTop(textBlock, y);
AssociatedCanvas.Children.Add(textBlock);
}
The XAML looks like this in part:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ScrollViewer Name="mapScroller" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Grid Name="grid" RenderTransformOrigin="0.5,0.5">
<Grid.LayoutTransform>
<TransformGroup>
<ScaleTransform x:Name="scaleTransform" />
</TransformGroup>
</Grid.LayoutTransform>
<Viewbox Grid.Column="0" Grid.Row="0" >
<Image x:Name="MainMap" UseLayoutRounding="True" Stretch="Fill" HorizontalAlignment="Center" VerticalAlignment="Center"
MouseLeftButtonUp="MainMap_MouseLeftButtonUp" Source="{Binding MainTerrainMap}"></Image>
</Viewbox>
<Canvas x:Name="Settlements" Panel.ZIndex="1" />
<Canvas x:Name="SettlementNames" Panel.ZIndex="2" >
</Canvas>
</Grid>
</ScrollViewer>
</Grid>
What I have tried:
I had wondered if the size of the Image and thus the Canvas was an issue, 21600 x 10800 pixels, because after replacing this with a much smaller 400 x 400 Image, smaller than the ScrollViewer would normally be, the show hide functionality for the second canvas ("SettlmentNames") worked . But bare in mind I could show/hide the lower ZOrder Canvas ("Settlements") without problem. Perhaps a memory limitation then?