为什么 Canvas.SetLeft 和 .SetTop 在此 WPF 代码中不起作用?

问题描述 投票:0回答:1

我动态创建了添加到画布上的图像,稍后需要移动它们。但这段代码并没有完成这项工作: int slotCount = _cardSlots.Count; for (int i = 0; i < slotCount; i++) { Canvas.SetLeft(_cardSlots[i].Card.CardImage.Image, _cardSlots[i].ScreenRectangle.X ); Canvas.SetTop(_cardSlots[i].Card.CardImage.Image, _cardSlots[i].ScreenRectangle.Y); }

图像不会改变位置。我尝试了 canvas.invalidatevisual 但这没有什么区别。

但是,如果我使用相同的代码但不在循环中,则图像会移动位置。例如:

Canvas.SetLeft(_cardSlots[0].Card.CardImage.Image, _cardSlots[0].ScreenRectangle.X); Canvas.SetTop(_cardSlots[0].Card.CardImage.Image, _cardSlots[0].ScreenRectangle.Y); Canvas.SetLeft(_cardSlots[1].Card.CardImage.Image, _cardSlots[1].ScreenRectangle.X); Canvas.SetTop(_cardSlots[1].Card.CardImage.Image, _cardSlots[1].ScreenRectangle.Y);

所以这段代码有效。请问有人知道为什么吗?

c# wpf windows canvas
1个回答
0
投票

如果是这种情况,您可以尝试使用以下方法强制刷新:

canvas.Dispatcher.Invoke(() => { canvas.InvalidateMeasure(); canvas.InvalidateArrange(); canvas.UpdateLayout(); });

这是我测试过的一个解决方案,它通过添加新的 
UpdateCardPositions

方法来工作,该方法更新 UI 并确保所有内容都正确刷新。我通过单击按钮调用该方法,但您可以使用您喜欢的任何事件触发它。

InitializeCardSlots

方法使用虚拟数据初始化卡槽列表 (_cardSlots) 以用于测试目的。它创建几个 Image 元素,设置它们的大小和来源,并将它们放置在画布上。然后将这些图像添加到画布和 _cardSlots 列表中,每个图像都包含在带有 CardScreenRectangleCardSlot 对象中。

UpdateCardPositions

方法旨在更新画布上卡片的位置。它迭代卡槽列表 (_cardSlots)。对于每个卡槽,它根据当前索引 (i) 计算新的 X 和 Y 位置。 Dispatcher.Invoke 方法用于确保 UI 更新在主线程上执行,这在 WPF 中对于线程安全是必要的。然后使用 Canvas.SetLeftCanvas.SetTop 在画布上更新图像的位置。

CanvasButton_Click

方法是按钮单击事件的事件处理程序。单击按钮时,会触发 UpdateCardPositions 方法来更新画布上的卡片位置。 using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Media.Imaging; namespace Namespace { public partial class MainWindow : Window { private List<CardSlot> _cardSlots; public MainWindow() { InitializeComponent(); InitializeCardSlots(); } private void InitializeCardSlots() { // Initializing _cardSlots with dummy data for testing purposes _cardSlots = new List<CardSlot>(); for (int i = 0; i < 5; i++) { var cardImage = new Image { Width = 100, Height = 150, Source = new BitmapImage(new Uri("https://via.placeholder.com/100x150")) }; Canvas.SetLeft(cardImage, i * 110); Canvas.SetTop(cardImage, i * 160); canvas.Children.Add(cardImage); _cardSlots.Add(new CardSlot { Card = new Card { CardImage = new CardImage { Image = cardImage } }, ScreenRectangle = new Rect(i + 110, i + 160, 100, 150) }); } } private async void UpdateCardPositions() { int slotCount = _cardSlots.Count; for (int i = 0; i < slotCount; i++) { var image = _cardSlots[i].Card.CardImage.Image; var x = _cardSlots[i].ScreenRectangle.X * i; var y = _cardSlots[i].ScreenRectangle.Y - i; canvas.Dispatcher.Invoke(() => { Canvas.SetLeft(image, x); Canvas.SetTop(image, y); }); // Small delay to resamble an animated affect await Task.Delay(50); } } private void CanvasButton_Click(object sender, RoutedEventArgs e) { UpdateCardPositions(); } } public class CardSlot { public Card Card { get; set; } public Rect ScreenRectangle { get; set; } } public class Card { public CardImage CardImage { get; set; } } public class CardImage { public Image Image { get; set; } } }

确保您的 XAML 设置如下:

<StackPanel> <Canvas x:Name="canvas" HorizontalAlignment="Left" /> <Button x:Name="CanvasButton" Content="Press me!" HorizontalAlignment="Center" Click="CanvasButton_Click" /> </StackPanel>

	
© www.soinside.com 2019 - 2024. All rights reserved.