我有一个自定义画布应该填充最大量的Tile对象。
如果它被调整为更大,它会用额外的Tiles填充空白区域。 如果它被调整为更小,则删除了不再可见的Tiles。
这只有在我非常缓慢地调整大小时才有效,否则一切都开始变得混乱。
Correct Image http://imageshack.us/a/img585/105/50186779.png Correct Image http://imageshack.us/a/img267/3179/76648216.png
我显然做错了,下面的代码是画布:
using System;
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1.View
{
public class TileCanvas : Canvas
{
#region Fields
private Boolean _firstCreation;
private Double _heightDifference;
private Double _widthDifference;
#endregion // Fields
#region Properties
public static readonly DependencyProperty TileSizeProperty =
DependencyProperty.Register("TileSize", typeof (Int32), typeof (TileCanvas),
new PropertyMetadata(30));
public Int32 TileSize
{
get { return (Int32) GetValue(TileSizeProperty); }
set { SetValue(TileSizeProperty, value); }
}
public Int32 Columns { get; private set; }
public Int32 Rows { get; private set; }
#endregion // Properties
#region Constructors
public TileCanvas()
{
_firstCreation = true;
}
#endregion // Constructors
#region Methods
#region Public
#endregion // Methods - Public
#region Protected
/// <summary>
/// Gets called when the rendering size of this control changes.
/// </summary>
/// <param name="sizeInfo">Information on the size change.</param>
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
Console.WriteLine("{0}x{1}", sizeInfo.NewSize.Width, sizeInfo.NewSize.Height);
_widthDifference += sizeInfo.NewSize.Width - sizeInfo.PreviousSize.Width;
_heightDifference += sizeInfo.NewSize.Height - sizeInfo.PreviousSize.Height;
int columnDifference = 0;
int rowDifference = 0;
if (_widthDifference > TileSize || _widthDifference < TileSize*-1)
{
columnDifference = ((Int32) _widthDifference)/TileSize;
Columns += columnDifference;
_widthDifference = 0;
}
if (_heightDifference > TileSize || _heightDifference < TileSize*-1)
{
rowDifference = ((Int32) _heightDifference)/TileSize;
Rows += rowDifference;
_heightDifference = 0;
}
UpdateTileSet(columnDifference, rowDifference);
}
#endregion // Methods - Protected
#region Private
/// <summary>
/// Updates the number of tiles if the control changed in size.
/// </summary>
private void UpdateTileSet(Int32 columnChange, Int32 rowChange)
{
// Exit if there's no practical change
if (columnChange == 0 && rowChange == 0)
{
return;
}
// Delete all tiles that fall out on vertical resize
if (rowChange < 0)
{
for (var row = Rows; row > Rows + rowChange; row--)
{
for (var column = 0; column < Columns; column++)
{
Children.RemoveRange(GetListIndex(0, Rows), Columns);
}
}
}
// Delete all tiles that fall out on horizontal resize
if (columnChange < 0)
{
for (var column = Columns; column > Columns + columnChange; column--)
{
for (var row = 0; row < Rows; row++)
{
Children.RemoveAt(GetListIndex(column, row));
}
}
}
// Fill new rows with tiles on vertical resize
if (rowChange > 0)
{
for (var row = Rows - rowChange; row < Rows; row++)
{
for (var column = 0; column < Columns; column++)
{
var tile = new Tile(column, row);
Point position = GetCanvasPosition(column, row);
var index = GetListIndex(column, row);
SetLeft(tile, position.X);
SetTop(tile, position.Y);
Children.Insert(index, tile);
}
}
}
// The first population is a special case that can be handled
// by filling rows only.
if (_firstCreation)
{
_firstCreation = false;
return;
}
// Fill new columns with tiles on horizontal resize
if (columnChange > 0)
{
for (var column = Columns - columnChange; column < Columns; column++)
{
for (var row = 0; row < Rows; row++)
{
var tile = new Tile(column, row);
Point position = GetCanvasPosition(column, row);
var index = GetListIndex(column, row);
SetLeft(tile, position.X);
SetTop(tile, position.Y);
Children.Insert(index, tile);
}
}
}
}
/// <summary>
/// Returns the index a tile should occupy based on its column and row.
/// </summary>
/// <param name="column">The column in which this tile resides.</param>
/// <param name="row">The row in which this tile resides.</param>
/// <returns></returns>
private Int32 GetListIndex(Int32 column, Int32 row)
{
return row*Columns + column;
}
/// <summary>
/// Returns the coordinates of a specific position.
/// </summary>
/// <param name="column">The column the position is in.</param>
/// <param name="row">The row the position is in.</param>
/// <returns></returns>
private Point GetCanvasPosition(Int32 column, Int32 row)
{
var positionX = column*TileSize;
var positionY = row*TileSize;
return new Point(positionX, positionY);
}
#endregion // Methods - Private
#endregion // Methods
}
}
这是Tile.cs
using System;
using System.Windows.Controls;
namespace WpfApplication1.View
{
/// <summary>
/// Interaction logic for Tile.xaml
/// </summary>
public partial class Tile : Border
{
public Tile(Int32 column, Int32 row)
{
InitializeComponent();
Textfield.Text = String.Format("{0}x{1}", column, row);
}
}
}
和Tile.xaml
<Border x:Class="WpfApplication1.View.Tile"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Width="40" Height="40">
<TextBlock x:Name="Textfield" FontSize="8" HorizontalAlignment="Center" VerticalAlignment="Top"/>
</Border>
问题出在哪里?
答案 0 :(得分:1)
以下是有关如何在WPF控件中的自定义位置放置元素的良好信息来源:http://codeblitz.wordpress.com/2009/03/20/wpf-auto-arrange-animated-panel/
我不知道它是否适用于canvas,但是将代码放在Measure / Arrange Override方法中可能会产生更好的结果。