我动态创建了添加到画布上的图像,稍后需要移动它们。但这段代码并没有完成这项工作:
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);
所以这段代码有效。请问有人知道为什么吗?
如果是这种情况,您可以尝试使用以下方法强制刷新:
canvas.Dispatcher.Invoke(() =>
{
canvas.InvalidateMeasure();
canvas.InvalidateArrange();
canvas.UpdateLayout();
});
这是我测试过的一个解决方案,它通过添加新的UpdateCardPositions
方法来工作,该方法更新 UI 并确保所有内容都正确刷新。我通过单击按钮调用该方法,但您可以使用您喜欢的任何事件触发它。
InitializeCardSlots方法使用虚拟数据初始化卡槽列表 (_cardSlots) 以用于测试目的。它创建几个 Image 元素,设置它们的大小和来源,并将它们放置在画布上。然后将这些图像添加到画布和 _cardSlots 列表中,每个图像都包含在带有 Card 和 ScreenRectangle 的 CardSlot 对象中。
UpdateCardPositions方法旨在更新画布上卡片的位置。它迭代卡槽列表 (_cardSlots)。对于每个卡槽,它根据当前索引 (i) 计算新的 X 和 Y 位置。 Dispatcher.Invoke 方法用于确保 UI 更新在主线程上执行,这在 WPF 中对于线程安全是必要的。然后使用 Canvas.SetLeft 和 Canvas.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>