我有一个带有图像及其左/上位置的列表,我将其添加到Canvas中。但是,我希望能够将相同的图像(相同的源)添加到Canvas,没有任何问题。
当我使用以下代码时:
Image img = ImagesList[i].Image; // ImagesList is a list of MyClass (containing Image Image; double Left; double Top)
img.Name = "img" + i; // where i is the nr in the list
Canvas.SetLeft(img, ImagesList[i].Left); // Left default = 0
Canvas.SetTop(img, ImagesList[i].Top); // Top default = 0
MyCanvas.Children.Add(img);
OnPropertyChanged("MyCanvas");
当Canvas上已存在相同的Image(-source)时(具有不同的Left / Top位置和Name),我得到以下异常:
ArgumentException: Specified Visual is already a child of another Visual or the root of a CompositionTarget.
所以我知道我不允许将相同的UIElement(在我的情况下为Image)添加到同一个Canvas中。
我将代码修改为:
// If the Image already exists on the Canvas, we need to make a clone of the image
if (MyCanvas.Children.Contains(img)) {
Image cloneImg = new Image();
cloneImg.Source = img.Source;
cloneImg.Name = img.Name;
Canvas.SetLeft(cloneImg, Left);
Canvas.SetTop(cloneImg, Top);
MyCanvas.Children.Add(cloneImg);
}
else
MyCanvas.Children.Add(img);
OnPropertyChanged("MyCanvas");
这解决了错误,但现在我遇到了一个新问题..我在画布上得到了两个图像,但是已经存在的图像将它的位置(左和上)重置为0,0(与新的相同)添加了Image),当我进行Console.Write测试时,我也注意到Canvas上两个图像的名称现在都是一样的。
克隆的错误是什么?第一个图像的名称,左边,顶部(可能还有其他东西)与第二个图像(“克隆”)相同?
提前感谢您的回复。
<Canvas Name="MyCanvas" Background="LimeGreen"/>
要:
<ItemsControl ItemsSource="{Binding MyField.ImagesList}"> <!-- MyField is the class where I have my list -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Name="FieldCanvas" Background="LimeGreen" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Left}"/>
<Setter Property="Canvas.Top" Value="{Binding Top}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding ImageSource}" AllowDrop="True" PreviewMouseLeftButtonDown="Image_PreviewMouseLeftButtonDown" PreviewMouseMove="Image_PreviewMouseMove" PreviewMouseLeftButtonUp="Image_PreviewMouseLeftButtonUp"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
ImagesList现在还包含BitmapImage ImagesSource而不是Image Image。
但是我还没能测试它,因为它给出了一堆错误。我使用Canvas作为ViewModel的构造函数中的参数,但现在不知道如何访问它现在它在ItemsControl中。 我在MouseEvent函数中也遇到了一些错误,我使用img.Parent来获取Canvas(不再使用上面的代码)和canvas.Children来获取所有图像,包括它们的ZIndex(也是不再工作了。
EDIT2 / SOLUTION:
撤消上面的编辑之后因为我的其他糟糕的代码部分导致了很多错误,除了我保存在列表而不是图像本身的ImageSource之外,它现在证明它可以正常工作。
答案 0 :(得分:3)
您通常使用ItemsControl
执行此操作,其中Canvas为ItemsPanel
,ItemContainerStyle
将Canvas.Left
和Canvas.Top
属性绑定到适当的属性在您的数据项类中。
如果这是您的数据项类:
public class ImageItem
{
public string Source { get; set; }
public double Left { get; set; }
public double Top { get; set; }
}
public class ViewModel
{
public ViewModel()
{
ImageItems = new ObservableCollection<ImageItem>();
}
public ObservableCollection<ImageItem> ImageItems { get; private set; }
}
ItemsControl的XAML如下所示。请注意,其ItemsSource
属性绑定到ViewModel类中的ImageItems
属性。
<ItemsControl ItemsSource="{Binding ImageItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Path=Left}"/>
<Setter Property="Canvas.Top" Value="{Binding Path=Top}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path=Source}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
MainWindow初始化代码中的某处:
var vm = new ViewModel();
DataContext = vm;
vm.ImageItems.Add(
new ImageItem
{
Source = @"C:\Users\Public\Pictures\Sample Pictures\Koala.jpg",
Left = 100,
Top = 50
});
vm.ImageItems.Add(
new ImageItem
{
Source = @"C:\Users\Public\Pictures\Sample Pictures\Desert.jpg",
Left = 200,
Top = 100
});
答案 1 :(得分:0)
在我用Clemens建议回复所有内容之后,在我的列表中保持BitmapImage ImageSource而不是Image Image的更改时,它现在可以正常工作。
我知道我的代码不是最好的,Clemens代码确实好多了。但是因为我已经拥有了相当多的代码,并且(在我看来)将其更改为Clemens代码同时保持与其他代码一样的工作太麻烦了,除了更改BitmapImage ImageSource之外我还原了它,事实证明它现在有效。
如果我做过类似的项目,我会从一开始就使用你的代码Clemens,因为它在WPF编程方面要好得多。代码的体系结构。谢谢你的回复。
我的问题的解决方案:我没有将图像本身保存在列表中并对其进行“克隆”,而是将我的ImageSource保存在列表中。所以我总是创建一个新的Image(),我可以从中更改Source。