2011-03-09 59 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中所有可能的操作,然後在視圖模型中爲這些操作創建命令。

相關問題