我正在制作一个简单的 WPF 应用程序,其中包含在画布上绘制的形状。该视图由一张地图组成,该地图在地图上不同的静态位置上有几个正方形的复杂序列。
MapView 是一个包含视图框和画布的用户控件。正方形由带有简单画布和形状(代码中的椭圆)的 UserControl 表示:
<Canvas>
<Canvas.Resources>
<BooleanToVisibilityConverter x:Key="boolToVisibility" />
</Canvas.Resources>
<Ellipse Stroke="Black" Fill="{Binding Color}" Width="{Binding Dimension}" Height="{Binding Dimension}" />
<Ellipse Stroke="Black" Fill="Black" Canvas.Top="15" Canvas.Left="15" Width="20" Height="20" Visibility="{Binding IsOccupied, Converter={StaticResource boolToVisibility}}" />
</Canvas>
Run Code Online (Sandbox Code Playgroud)
视图显然都有一个 ViewModel(通过视图的 DataContext 属性绑定),由模型支持。
我的问题:
我地图上的 SquareViews 都有一个 mousedown 事件,每个视图都代表一个模型,我很困惑如何在我的应用程序中以优雅的方式实现它(关于 MVVM 模式)。我应该在 XAML 中预定义 SquareViews,然后生成模型,还是预先生成模型,并根据运行时对模型所做的更改动态创建视图。
如何区分SquareViews?基于(视图)模型参考?位置坐标?我想避免给每个单独的方块一个单独的名字......
将视图的 DataContext 设置为其相应视图模型的其他方法(无需使用框架),而不是将其添加到视图的代码隐藏中。
有没有更好的方法在我的地图上定位方块?(我知道画布在缩放、不同分辨率、dpi 等方面不是很灵活,但据说 viewbox 应该改进这一点,尽管我还没有完全测试过)
PS 如果我的描述/问题含糊不清/抽象,请告诉我。
如果我理解你的问题......
我认为您可以采取的方法是使用 DataTemplates、ItemsControl 或许还有 ContentPresentor。
实际上,您想要做的是告诉 WPF“显示”您的视图模型。因为您的视图模型只是普通类,所以 WPF 不知道如何“渲染”它们。这就是 DataTemplate 的用武之地。这种方法的好处是 DataTemplate 内容的 DataContext 将自动设置为视图模型。DataTemplates 在您的 Window 或 UserControl 资源中定义:
<Window.Resources>
<DataTemplate DataType="{x:Type ViewModels:SquareViewModel}">
<Views:SquareView />
</DataTemplate>
</Window.Resources>
Run Code Online (Sandbox Code Playgroud)
当 WPF 遇到 SquareViewModel 时,上面的代码将渲染 SquareView 用户控件(并将 SquareView 上的 DataContext 设置为 SquareViewModel)。
要将视图模型放置在视图中,您可以使用 ContentPresenter(对于单个 ViewModel):
<ContentPresenter Content="{Binding SingleSquare}" />
Run Code Online (Sandbox Code Playgroud)
在您的情况下,您将希望显示 SquareViewModel 项目的集合,因此您将希望使用 ItemsControl:
<ItemsControl ItemsSource="{Binding Squares}" />
Run Code Online (Sandbox Code Playgroud)
然而,这不会给您想要的结果,因为默认情况下这将像列表框一样。您需要将模板应用到 ItemsControl 才能使用底层 Canvas。有关可能的实现,请参阅Pete Brown 的博客。
祝你好运!
编辑:附加代码示例
查看型号:
public class MainViewModel
{
public IEnumerable<SquareViewModel> Squares { get; set; }
public MainViewModel()
{
var squares = new List<SquareViewModel>();
squares.Add(new SquareViewModel(15, 15,100,100, Brushes.CadetBlue, "Square One"));
squares.Add(new SquareViewModel(75,125, 80, 80, Brushes.Indigo, "Square Two"));
Squares = squares;
}
}
public class SquareViewModel
{
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public Brush Color { get; set; }
public string Name { get; set; }
public SquareViewModel(int x, int y, int width, int height, Brush color, string name)
{
X = x;
Y = y;
Width = width;
Height = height;
Color = color;
Name = name;
}
}
Run Code Online (Sandbox Code Playgroud)
意见
<UserControl x:Class="MapView.Views.SquareView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Grid Background="{Binding Color, FallbackValue=Azure}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Name, FallbackValue=None}" />
</Grid>
</UserControl>
<Window x:Class="MapView.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:MapView.ViewModels"
xmlns:Views="clr-namespace:MapView.Views" Title="Window1" Height="300" Width="300">
<Window.Resources>
<DataTemplate DataType="{x:Type ViewModels:SquareViewModel}">
<Views:SquareView />
</DataTemplate>
</Window.Resources>
<ItemsControl ItemsSource="{Binding Squares}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Beige" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left"
Value="{Binding X}" />
<Setter Property="Canvas.Top"
Value="{Binding Y}" />
<Setter Property="Width"
Value="{Binding Width}" />
<Setter Property="Height"
Value="{Binding Height}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Window>
Run Code Online (Sandbox Code Playgroud)
在 Window1 构造函数中:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2637 次 |
| 最近记录: |