簡體   English   中英

在WPF應用程序中應用MVVM模式

[英]Applying MVVM pattern in a WPF application

我正在制作一個簡單的WPF應用程序,其中包含在畫布上繪制的形狀。 視圖由地圖組成,該地圖地圖上的不同靜態位置上具有幾個復雜的幾個正方形序列。

MapView是一個包含視圖框和畫布的UserControl。 正方形由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都有一個mousedown事件,每個視圖都代表一個模型,我對如何在我的應用程序中以優雅的方式實現它感到困惑(關於MVVM模式)。 我應該在XAML中預定義SquareViews,然后生成模型,還是事先生成模型,並根據在運行時對模型所做的更改動態創建視圖。

  • 如何區分SquareViews? 基於(查看)模型參考? 位置坐標? 我想避免給每個單獨的廣場分別給出一個名字......

  • 將視圖的DataContext設置為相應的viewmodel(無需使用框架)的其他方法,而不是將其添加到視圖的代碼隱藏中。

  • 有沒有更好的方法來定位我的地圖上的方塊? (我知道畫布在縮放,不同分辨率,dpi等方面不是很靈活,但據說視圖框應該改進這一點,盡管我還沒有完全測試過)

PS如果我的描述/問題是含糊不清的,請告訴我。

如果我理解你的問題......

我認為您可以采用的方法是使用DataTemplates,ItemsControl和ContentPresentor。

實際上,您要做的是告訴WPF“顯示”您的視圖模型。 因為您的視圖模型只是普通類,所以WPF不知道如何“渲染”它們。 這就是DataTemplates的用武之地。這種方法的好處是DataTemplate內容的DataContext將自動設置為視圖模型。 DataTemplates在Window或UserControl資源中定義:

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

當WPF遇到SquareViewModel時,上面的代碼將呈現SquareView用戶控件(並將SquareView上的DataContext設置為SquareViewModel)。

要將視圖模型放置在視圖中,您可以使用ContentPresenter(對於單個ViewModel):

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

在您的情況下,您將希望顯示一組SquareViewModel項目,因此您將需要使用ItemsControl:

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

但是這不會給你想要的結果,因為默認情況下它會像ListBox一樣。 您需要將模板應用於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;
    }
}

查看

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

並在Window1構造函數中:

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

看看Ryan Cromwell撰寫的這篇博客 基本上,您希望在畫布上顯示正方形的“列表”。 他解釋了如何做到我想你的要求。

你必須想出某種網格結構(WPF Datagrid會為你做)。 網格的優點是可以像行一樣使用它可以被視為x坐標和列作為y坐標。在開始實現之前,想象一下你想要在UI上顯示什么。 WPF只是一種將您的想象力變為現實的技術。 如果您的應用程序是UI驅動的,那么首先收集可能來自UI的所有操作,為視圖模型中的那些操作創建命令。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM