【问题标题】:Element position in Canvas not updating画布中的元素位置未更新
【发布时间】:2018-08-01 21:46:21
【问题描述】:

我无法弄清楚如何获取元素相对于画布的更新位置。

在我的代码示例中,我将标签添加到画布中的位置 (100,100),然后打印标签相对于画布的位置。我还有一个按钮,点击时会打印位置。

当我运行代码时,它会打印 (0,0) 而不是 (100,100)。但是当我单击按钮时,它会打印 (100,100)。

MainWindow 构造函数中的代码与我单击按钮时激活的代码之间会发生什么,以更新标签的位置?我怎样才能在我想要的时候实现它?

我尝试在将标签添加到画布后直接在标签和画布上使用 UpdateLayout(),但都没有成功。

代码隐藏:

public partial class MainWindow : Window
{
    Label label;

    public MainWindow()
    {
        InitializeComponent();

        label = new Label();
        label.Content = "Boop";
        Canvas.SetLeft(label, 100);
        Canvas.SetTop(label, 100);

        canvas.Children.Add(label);
        Point p = label.TranslatePoint(new Point(0, 0), canvas);

        Console.WriteLine(p);
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Point p = label.TranslatePoint(new Point(0, 0), canvas);
        Console.WriteLine(p);
    }
}

xaml:

<Window x:Class="CanvasTest.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"
        xmlns:local="clr-namespace:CanvasTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Canvas x:Name="canvas" Margin="0">
        <Button Content="Button" Canvas.Left="0" Canvas.Top="0" Width="50" Click="Button_Click"/>
    </Canvas>
</Window>

更新:

我有同样的问题,在构造函数之外有相同的代码,即在按钮点击逻辑内。如果我尝试在画布上添加一些东西,然后尝试立即获取位置,我得到 0,0 而不是我设置的位置。

新的代码隐藏:

public partial class MainWindow : Window
{
    Label label;

    public MainWindow()
    {
        InitializeComponent();
    }

    private void PrintLabelLocation()
    {
        Point p = label.TranslatePoint(new Point(0, 0), canvas);
        Console.WriteLine(p);
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        label = new Label();
        label.Content = "Boop";

        Canvas.SetLeft(label, 100);
        Canvas.SetTop(label, 100);
        canvas.Children.Add(label);

        PrintLabelLocation();
    }
}

更新 2: 添加异步延迟以留出时间让 UI 呈现可解决问题。

代码隐藏:

公共部分类 MainWindow : Window { 标签标签;

    public MainWindow()
    {
        InitializeComponent();
    }

    private void PrintLabelLocation()
    {
        Point p = label.TranslatePoint(new Point(0, 0), canvas);
        Console.WriteLine(p);
    }

    private async void Wait(int ms)
    {
        await Task.Delay(ms);
        PrintLabelLocation();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        label = new Label();
        label.Content = "Boop";

        Canvas.SetLeft(label, 100);
        Canvas.SetTop(label, 100);
        canvas.Children.Add(label);

        Wait(1);
    }
}

【问题讨论】:

  • 你试过调用 InvalidateVisual 吗?
  • @PaulBaxter 既然你提出了建议,我就试了一下,但似乎并不能解决问题。
  • 即使您在构造函数中编写代码以在画布内添加控件,它也会在页面加载时呈现。到那时该值将为零
  • @VimalCK 如果我有代码在按钮单击逻辑中添加控件,则会发生同样的问题。添加控件并尝试在同一代码“块”中获取位置似乎存在一些问题。

标签: c# wpf canvas


【解决方案1】:

内容尚未呈现,这就是为什么一开始它没有显示您设置的位置。查看我在您的后台代码中所做的更改:

public partial class MainWindow : Window
{
    Label label;

    public MainWindow()
    {
        InitializeComponent();

        label = new Label();
        label.Content = "Boop";
        Canvas.SetLeft(label, 100);
        Canvas.SetTop(label, 100);

        canvas.Children.Add(label);

        // Render event - when the controls are at the set location.
        ContentRendered += MainWindow_ContentRendered;
    }

    private void MainWindow_ContentRendered(object sender, EventArgs e)
    {
        PrintLabeLocation();
    }

    // This method allows reuse of code.
    private void PrintLabeLocation()
    {
        Point p = label.TranslatePoint(new Point(0, 0), canvas);
        Console.WriteLine(p);
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        PrintLabeLocation();
    }
}

这将使您对发生的事情有更多的了解。控件被渲染后,它们会显示在你设置的位置,这发生在构造函数结束并且窗口变得可见之后。

【讨论】:

  • 这确实使我的示例代码工作,并回答了我的问题。但我想我的示例代码毕竟不能完美地代表我的实际应用程序。我有一个向画布添加元素的函数,然后根据元素相对于画布的位置立即执行操作。问题是,我似乎总是把 0,0 作为位置。这发生在用户控件内部,通过一些 ui 逻辑,而不是在 MainWindow 的构造函数中,所以我认为我不能利用 ContentRendered。
  • 您可以在添加控件后添加一段设定时间的异步等待。这将允许 UI 呈现控件。如果这回答了您的问题,请将其标记为答案,或使用新信息更新问题。
  • 添加延迟就可以了!即使只是增加 1 毫秒的延迟似乎就足够了。谢谢。
猜你喜欢
  • 1970-01-01
  • 2012-01-26
  • 2012-01-12
  • 1970-01-01
  • 2010-12-17
  • 1970-01-01
  • 2016-08-18
  • 2021-06-05
  • 2012-06-13
相关资源
最近更新 更多