C# UIElement在哪一点加载?
我有以下代码:C# UIElement在哪一点加载?,c#,wpf,loaded,C#,Wpf,Loaded,我有以下代码: <Window x:Class="Demo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.m
<Window x:Class="Demo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Canvas Name="Canvas_Main" />
</Window>
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
加载+=主窗口\u加载;
}
已加载私有void主窗口(对象发送器、路由目标)
{
矩形lastRectangle=null;
随机数=新随机数(0);
用于(Int32计数器=0;计数器<5;计数器++)
{
矩形=新矩形();
矩形。填充=画笔。蓝色;
矩形.Width=random.Next(100200);
矩形。高度=计数器*100;
Canvas_Main.Children.Add(矩形);
if(lastRectangle==null){
Canvas.SetLeft(矩形,0);
Canvas.SetTop(矩形,0);
}
其他的
{
SetLeft(矩形,lastRectangle.ActualWidth);
Canvas.SetTop(矩形,0);
}
lastRectangle=矩形;
}
}
}
这没有按预期工作(将每个矩形彼此对角放置),因为lastRectangle.ActualWidth
为0。据我所知,这是因为lastRectangle没有被测量和排列
我很好奇,如果添加到一个已经可见并已装载的容器中,测量和排列将在什么时候完成?窗口的测量和排列已经完成。但是您现在正在创建新的子控件,通常在窗口的下一个布局过程之前不会对其进行测量/排列
通过调用循环末尾每个矩形的
Measure
方法,可以立即强制执行此操作。元素的Framework.Loaded
事件在度量和排列布局过程之后,但在呈现元素之前引发
当在元素上调用异步布局过程的UIElement.InvalidateMeasure
或同步布局过程的UIElement.UpdateLayout
时,初始化完整布局过程
在您的场景中,将调用Window.Loaded
事件处理程序,这意味着Window
和Canvas
都已加载(但未呈现)。现在开始向
画布添加新的UIElement
元素
Canvas.Children.Add
应调用InvalidateMeasure
方法。由于InvalidateMeasure
触发异步布局过程,因此Canvas
和当前子元素将被排入布局队列,上下文将继续执行(添加更多矩形)。
由于新添加的元素已经有一个挂起的布局过程,因此应该避免手动调用UIElement.Measure
(这是递归调用,在考虑性能时非常昂贵)
上下文完成后,队列中等待布局传递和最终呈现的元素将被处理,并对这些元素(Canvas
及其子元素)递归调用MeasureOverride
和ArrangeOverride
。
因此,UIElement.renderize
可以由布局系统计算。
此时,新的框架元素.ActualWidth
将可用
这是添加元素(矩形)的FrameworkElement.Loaded
事件最终引发的时刻
要解决您的问题,您必须使用Rectangle.Width
代替
或者在添加下一个事件之前,等待每个矩形.Laoded
事件:
private int ShapeCount { get; set; }
private const int MaxShapes = 5;
private Point ShapeBPosition { get; set; }
private void MainWindow_Loaded(Object sender, RoutedEventArgs e)
{
this.ShapePosition = new Point();
AddRectangle(this.ShapePosition);
}
private void AddRectangle(Point position)
{
Random random = new Random();
Rectangle rectangle = new Rectangle();
rectangle.Fill = Brushes.Blue;
rectangle.Width = random.Next(100, 200);
rectangle.Height = ++this.ShapeCount * 100;
Canvas_Main.Children.Add(rectangle);
Canvas.SetLeft(rectangle, position.X);
Canvas.SetTop(rectangle, position.Y);
rectangle.Loaded += OnRectangleLoaded;
}
private void OnRectangleLoaded(object sender, RoutedEventArgs e)
{
var rectangle = sender as Rectangle;
rectangle.Loaded -= OnRectangleLoaded;
if (this.ShapeCount == MainWindow.MaxShapes)
{
return;
}
// this.ShapePosition is struct => modify copy
Point position = this.ShapePosition;
position.Offset(rectangle.ActualWidth, 0);
this.ShapePosition = position;
AddRectangle(this.ShapePosition);
}
非常感谢。但是,是什么导致调用窗口的布局方法呢?我无法想象这在计时器中运行,但添加或删除子项不会触发布局?如果您能扩展您的答案,我们将不胜感激。在每个UI应用程序的顶部都有一个while
循环,它会反复运行,直到应用程序退出。布局过程是WPF循环执行的阶段之一。(为了避免您可能提出的下一个问题,请避免阻塞CPU内核。在操作系统提示循环继续之前,循环会一直处于空闲状态,例如,通知它用户输入。)谢谢-您为我提供了大量的方法和事件以查找更多详细信息。
private int ShapeCount { get; set; }
private const int MaxShapes = 5;
private Point ShapeBPosition { get; set; }
private void MainWindow_Loaded(Object sender, RoutedEventArgs e)
{
this.ShapePosition = new Point();
AddRectangle(this.ShapePosition);
}
private void AddRectangle(Point position)
{
Random random = new Random();
Rectangle rectangle = new Rectangle();
rectangle.Fill = Brushes.Blue;
rectangle.Width = random.Next(100, 200);
rectangle.Height = ++this.ShapeCount * 100;
Canvas_Main.Children.Add(rectangle);
Canvas.SetLeft(rectangle, position.X);
Canvas.SetTop(rectangle, position.Y);
rectangle.Loaded += OnRectangleLoaded;
}
private void OnRectangleLoaded(object sender, RoutedEventArgs e)
{
var rectangle = sender as Rectangle;
rectangle.Loaded -= OnRectangleLoaded;
if (this.ShapeCount == MainWindow.MaxShapes)
{
return;
}
// this.ShapePosition is struct => modify copy
Point position = this.ShapePosition;
position.Offset(rectangle.ActualWidth, 0);
this.ShapePosition = position;
AddRectangle(this.ShapePosition);
}