嗨! 我想设计将在不同位置包含多个对象的 View 。例如 - 如果 viewmodel 可以具有像对象列表(矩形)这样的字段,并且当我将成员更改/添加到列表时,新矩形会出现在指定位置的 View 中,那就太好了。 我如何创建这样的 View / View 模型?
最佳答案
你可以有一个 ICollectionView
或 ObservableCollection<T>
ViewModel 中的属性并绑定(bind) ItemsSource
ItemsControl
的属性到这个属性。然后这将显示您的收藏( View )中的所有项目。但是,它通常会将它们显示在 StackPanel
中。因为这是 ItemsControl
的默认项目容器.据我了解您的问题,您希望将项目放置在屏幕上的任何位置。这可以通过使用 Canvas
来完成。作为 ItemsControl
的 ItemsPanel
, 然后绑定(bind) Canvas.Left
和 Canvas.Top
属性到 ViewModel 中的属性。当然,每个项目都需要 Left
和 Top
然后属性(也可能是 Width
和 Height
属性)。
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
的大小,则项目保留在相对位置变化。这是一些更多的工作:
<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 注释中。但是,我应该注意我使用了 ExpressionConverter
来自 Kent Boogart's Converter collection .我从我的一个应用程序中复制并粘贴了上面的代码,因此由于根据您的情况快速调整了属性,因此其中可能存在一些不一致之处。但是,我认为原则应该很清楚。祝你好运!
关于c# - 具有不同数量对象的 WPF MVVM View 。如何?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2957159/