具有不同数量对象的 WPF MVVM 视图.如何? [英] WPF MVVM View with varying number of objects. How to?
问题描述
嗨!我想设计包含不同位置的多个对象的视图.例如 - 如果 viewmodel 可以有像对象列表(矩形)这样的字段,并且当我更改/添加成员到列表时,新的矩形会出现在指定位置的视图上,那就太好了.我如何创建这样的视图/视图模型?
HI! I want to design view which will contain multiple objects in different locations. For example - it would be great if viewmodel could have field like list of objects (rectangles) and when i change/add members to list, new rectangles appear on view in specified positions. How do i create such view/viewmodel?
推荐答案
您可以在 ViewModel 中有一个 ICollectionView
或 ObservableCollection
属性并绑定 ItemsSource
属性的 ItemsControl
到此属性.然后这将显示您的集合中的所有项目(视图).但是,它通常会在 StackPanel
中显示它们,因为这是 ItemsControl
的默认项目容器.据我了解您的问题,您希望将项目放置在屏幕上的任何位置.这可以通过使用 Canvas
作为 ItemsControl
的 ItemsPanel
,然后绑定 Canvas.Left
来完成和 Canvas.Top
属性到您的 ViewModel 中的属性.当然,每个项目都需要一个 Left
和 Top
属性(也许还有一个 Width
和 Height
属性).
You could have an ICollectionView
or ObservableCollection<T>
property in your ViewModel and bind the ItemsSource
property of an ItemsControl
to this property. Then this will display all the items in your collection(view). However, it will typically display them in a StackPanel
as this is the default item container for an ItemsControl
. As far as I understood your question, you want the items to be placed anywhere on your screen. This could be done by using a Canvas
as the ItemsControl
's ItemsPanel
, and then binding the Canvas.Left
and Canvas.Top
properties to properties in your ViewModels. Of course, every item would need a Left
and Top
property then (and maybe also a Width
and Height
property).
public class ItemViewModel
{
public double Left { get; set; }
public double Top { get; set; }
public double Width { get; set; }
public double Height { get; set; }
// whatever you need...
}
public class CollectionViewModel
{
public ObservableCollection<ItemViewModel> Collection { get; }
// some code which fills the Collection with items
}
还有你的 XAML:
<ItemsControl ItemsSource="{Binding Collection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:ItemViewModel}">
<Rectangle Width="{Binding Width}" Height="{Binding Height}"
Canvas.Left="{Binding Left}" Canvas.Top="{Binding Top}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
在最后一步中,您可能希望 Left
和 Top
属性相对于 Canvas
的大小,以便如果 Canvas
的大小发生变化,项目将保持在相对位置.这是更多的工作:
In a final step, you might want the Left
and Top
properties to be relative to the size of the Canvas
, so that the items remain at the relative positions if the size of the Canvas
changes. This is some more work:
<DataTemplate DataType="{x:Type local:ItemViewModel}">
<Rectangle Width="{Binding Width}" Height="{Binding Height}">
<!-- Make the left position of the item depend on the ActualWidth of the Canvas,
the relative Left position (between 0 and 1) from the ItemViewModel, and the ActualWidth
of the item itself. This is needed because the Canvas.Left property defines the
position of the left side, not the center. Therefore, we calculate the position of
the center this way:
(Canvas.ActualWidth * ItemViewModel.Left) - (Item.ActualWidth / 2)
-->
<Canvas.Left>
<MultiBinding>
<MultiBinding.Converter>
<converters:ExpressionConverter Expression="{}({0} * {1}) - ({2} / 2)"/>
</MultiBinding.Converter>
<Binding Path="ActualWidth" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Canvas}}"/>
<Binding Path="Left"/>
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</Canvas.Left>
<!-- the top position of the items is determined the same way as the left position
which is described above -->
<Canvas.Top>
<MultiBinding>
<MultiBinding.Converter>
<converters:ExpressionConverter Expression="{}({0} * {1}) - ({2} / 2)"/>
</MultiBinding.Converter>
<Binding Path="ActualHeight" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Canvas}}"/>
<Binding Path="Top"/>
<Binding Path="ActualHeight" RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</Canvas.Top>
</Rectangle>
</DataTemplate>
代码的描述已经在 XAML 注释中.但是,我应该注意到我使用了 Kent Boogart 的转换器集合中的 ExpressionConverter
.我从我的一个应用程序中复制并粘贴了上述代码,因此由于根据您的场景快速调整属性,其中可能存在一些不一致之处.但是,我认为原则应该是明确的.祝你好运!
The description of the code is already in the XAML comments. However, I should note that I have used the ExpressionConverter
from Kent Boogart's Converter collection. I copied and pasted the above code from one of my applications, so there might be some inconsistencies in there because of quickly adjusting the properties to your scenario. However, the principle should be clear, I think. Good luck!
这篇关于具有不同数量对象的 WPF MVVM 视图.如何?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!