2011-03-09 75 views
4

我正在制作一个简单的WPF应用程序,并在画布上绘制形状。该视图由地图组成,其在地图上的不同静态位置上具有几个方块的稍微复杂的序列。在WPF应用程序中应用MVVM模式

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> 

的观点显然都具有一个ViewModel(通过视图的DataContext属性绑定),备份由:平方被通过一个用户控件以简单的画布和形状(在代码椭圆)表示模型。

我的问题:

  • 在我的地图都有一个鼠标按下事件,每个视图表示模型,我就如何落实这在我的应用程序优雅的方式混淆(与该SquareViews关注MVVM模式)。我是否应该预先定义XAML中的SquareView,然后生成模型,或者事先生成模型,并根据运行时对模型所做的更改动态创建视图。

  • 如何区分SquareViews?基于(查看)模型参考?位置坐标?我想避免给每个单独的方块分别命名...

  • 其他方式将DataContext设置为相应的viewmodel(而不必使用框架),而不是将其添加到代码隐藏在视图后面。

  • 有没有更好的方法在我的地图上定位正方形? (我知道,当谈到缩放,不同的分辨率,DPI等画布是不是很灵活,但据说视框应该改善这一点,虽然我还没有完全测试过了没有)

PS请让我知道我的描述/问题是模糊/抽象的。

回答

3

如果我理解你的问题....

我想你可以采取的方法是使用的DataTemplates,ItemsControl的也许ContentPresentor。

实际上,你想要做的是告诉WPF“显示”你的视图模型。因为你的视图模型只是普通的类,所以WPF不知道如何“渲染”它们。这就是DataTemplates的用武之地。这种方法的好处是,DataTemplate内容的DataContext将自动设置为视图模型。的DataTemplates在你的窗口或用户控件资源定义:WPF时遇到一个SquareViewModel

<Window.Resources> 
    <DataTemplate DataType="{x:Type ViewModels:SquareViewModel}"> 
     <Views:SquareView /> 
    </DataTemplate> 
</Window.Resources> 

上面的代码将呈现SquareView用户控件(和设置的DataContext上SquareView到SquareViewModel)。

要放置您的视图模型视图中可以使用ContentPresenter(单个视图模型):

<ContentPresenter Content="{Binding SingleSquare}" /> 

在你的情况,你会希望有显示的,所以你会想的SquareViewModel项目的集合使用ItemsControl:

<ItemsControl ItemsSource="{Binding Squares}" /> 

但是,这不会给你你想要的结果,因为这将默认情况下像一个列表框。您需要将一个模板应用于ItemsControl以使用底层画布。有关可能的实现请参见this blog by 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; 
    } 
} 

查看

<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> 

而且在T他Window1构造函数:

public partial class Window1 : Window 
{ 
    public Window1() 
    { 
     InitializeComponent(); 
     DataContext = new MainViewModel(); 
    } 
} 
+0

如何在您的解决方案中生成(视图)模型?我不确定如何实现这一点,你可以用其他代码来澄清它吗? – tman 2011-03-09 11:03:05

+0

您通常需要将DataContext显式设置为至少一次视图模型。在我的例子中,我将创建一个MainViewModel并设置MainWindow.DataContext = new MainViewModel()。 MainViewModel有一个属性集合IEnumerable Squares {get;设置;}。因为我已经将我的ItemsSource绑定到方块WPF将要渲染这些方块。因为它们只是类,它将使用DataTemplate来确定它实际上应该呈现SquareView(自动将每个SquareView的datacontext设置为关联的SquareViewModel) – 2011-03-09 15:36:16

+0

向Answer添加了其他代码示例。请注意,我正在使用一个窗口,但您可以使用MapView用户控件。如果你有一个用户控件,那么在用户控制的“hosts”视图上,你可以使用一个ContentPresenter绑定到一个MapViewModel,并且有一个DT将你的MapViewModel匹配到你的MapView(然后不需要显式地设置DataContext那里)。 – 2011-03-09 15:53:55

1

看看Ryan Cromwell的blog。基本上,你想在画布上显示一个“列表”方块。他解释了如何完全想要我想你的要求。

1

你必须想出一些网格结构(WPF Datagrid会为你做的)。网格的优势在于它可以像行一样用作x坐标和列作为y坐标。在开始实施之前,想象一下你想要在UI上展示什么。 WPF只是一种将您的想象力变为现实的技术。如果您的应用程序是由UI驱动的,那么首先需要收集UI中所有可能的操作,然后在视图模型中为这些操作创建命令。

相关问题