Custom control not moving to correct grid location
Just to give you a quick overview, just trying to create somewhat of a tile editor. So I made custom tile objects which will be represted through a contenttemplate displaying each as a rectangle. I am using a listbox as my container but I set the ItemsPanelTemplate of that container to use a grid. The problem is, setting Grid.Row or Grid.Column in my contenttemplate does nothing. I'm sure it has something to do with the fact that my grid is defined within the template but I'm not sure how.
Here is my XAML:
<Window x:Class="InvisTile.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControls"
Title="MainWindow" Height="200" Width="200">
<Window.Resources>
<ControlTemplate x:Key="TileTemplate" TargetType="{x:Type ListBoxItem}">
//Hard coded to grid location but only staying in 0,0
<local:Tile BorderBrush="Aqua" MouseDown="Tile_MouseDoubleClick" Grid.Row="1" Grid.Column="1">
<Rectangle Fill="Transparent" Stroke="Green"></Rectangle>
</local:Tile>
</ControlTemplate>
</Window.Resources>
<ListBox Name="lstTiles">
<ListBox.ItemContainerStyle>
<Style>
<Setter Property="Control.Template" Value="{StaticResource TileTemplate}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<local开发者_JS百科:Tile></local:Tile>
</ListBox>
The reason is that Grid.Row
and Grid.Column
only have effect on the direct children of the Grid
control. The children of your Grid
, however, are not the Tile
controls, but the ListBoxItem
controls that are created implicitly. Therefore, you must set the position like this:
ListBoxItem li = new ListBoxItem();
li.Content = "item1";
Grid.SetColumn(li, 1);
Grid.SetRow(li, 1);
lstTiles.Items.Add(li);
You also can do it like this in the ItemContainerStyle:
<Setter Property="Grid.Row" Value="1"/>
<Setter Property="Grid.Column" Value="1"/>
You even can use data binding:
<Setter Property="Grid.Row" Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=Content.Row}"/>
<Setter Property="Grid.Column" Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=Content.Column}"/>
Here, Row
and Column
must be public properties of the ListBox items.
Here is a complete example to make it clear:
<Window x:Class="InvisTile.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:InvisTile"
Title="Window1" Height="200" Width="200">
<Window.Resources>
<ControlTemplate x:Key="TileTemplate" TargetType="{x:Type ListBoxItem}">
<Border BorderThickness="1" BorderBrush="Aqua" Background="LightGray" Margin="4">
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<ContentPresenter/>
</Grid>
</Border>
</ControlTemplate>
</Window.Resources>
<ListBox Name="lstTiles">
<ListBox.ItemContainerStyle>
<Style>
<Setter Property="Control.Template" Value="{StaticResource TileTemplate}" />
<Setter Property="Grid.Row" Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=Content.Row}"/>
<Setter Property="Grid.Column" Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=Content.Column}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.Items>
<local:Tile Text="(0,0)" Row="0" Column="0"/>
<local:Tile Text="(0,1)" Row="0" Column="1"/>
<local:Tile Text="(1,0)" Row="1" Column="0"/>
<local:Tile Text="(1,1)" Row="1" Column="1"/>
</ListBox.Items>
</ListBox>
</Window>
The Tile
class is defined as follows:
public class Tile
{
public Tile() {}
public string Text { get; set; }
public int Row { get; set; }
public int Column { get; set; }
public override string ToString() { return Text; }
}
精彩评论