RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

MVVM是什么?

汽車電子技術(shù) ? 來源:工控羊 ? 作者: zyuanlbj ? 2023-02-07 14:32 ? 次閱讀

前言

最近在學(xué)習(xí)WPF,買了一本劉鐵錳老師的《深入淺出WPF》書籍,受益頗深。劉老師是微軟社區(qū)精英,他的C#視頻課程也是很受歡迎,感興趣的小伙伴可以去b站觀看。

這里,以一個在線訂餐系統(tǒng)為例,和大家一起分享MVVM的魅力。

MVVM

首先,我們來看看MVVM到底是什么?

MVVM是Model-View-ViewModel的簡寫,它是一種極度優(yōu)秀的設(shè)計模式,也是MVC的增強版。

圖片

View:用戶界面,也叫視圖

由控件構(gòu)成的、與用戶進(jìn)行交互的界面,用于把數(shù)據(jù)展示給用戶并響應(yīng)用戶的輸入。

ViewModel:MVVM的核心

ViewModel通過雙向數(shù)據(jù)綁定將View和Model連接了起來,而View和Model之間的同步工作都是完全自動的,無需人為操作。

Model:數(shù)據(jù)模型

現(xiàn)實世界中事物和邏輯的抽象。

在WPF中,數(shù)據(jù)占據(jù)主導(dǎo)地位,數(shù)據(jù)與界面之間的橋梁是數(shù)據(jù)關(guān)聯(lián),通過這個橋梁,數(shù)據(jù)可以流向界面,也可以從界面流回數(shù)據(jù)源。

ViewModel的存在,使得界面交互業(yè)務(wù)邏輯處理導(dǎo)致的屬性變更會通知到View前端,讓View前端實時更新;View的變動,也會自動反應(yīng)到ViewModel上。

MVVM的出現(xiàn)促進(jìn)了前端開發(fā)與后端的分離,極大提高了前端的開發(fā)效率;幾乎完全解耦了視圖和業(yè)務(wù)邏輯的關(guān)系。

案例剖析

基于以上理解,我們來剖析下面這個在線訂餐系統(tǒng)。

圖片

將主界面劃分為三個區(qū)域:第一個區(qū)域是餐館的信息(名字、地址以及電話),中間區(qū)域是菜單列表,每個菜品都有名字、種類、點評、評分以及價格,還有選中框;第三個區(qū)域有菜品的選中總數(shù)和訂餐按鈕。

這里,我們忽視菜品數(shù)據(jù)的來源是來自數(shù)據(jù)庫還是其他什么存儲方式,也忽視點擊訂餐按鈕后訂餐數(shù)據(jù)的處理,主要是想將更多精力集中在MVVM實現(xiàn)上。

我們來找找有多少個數(shù)據(jù)屬性和命令屬性。

顯而易見能看出有一個 餐館Model ,它有名字、地址和電話三個屬性,因此,有一個餐館類數(shù)據(jù)屬性。

右下角有個Order按鈕,明顯是一個命令屬性。

當(dāng)我們選中某個菜品時,這是一個命令屬性;同時共計框那里會有數(shù)值變化,所以,也會有一個菜品選中總數(shù)數(shù)據(jù)屬性。

中間區(qū)域菜單列表中,有很多不同的菜品,所以會有一個 菜品Model ,它有名字、種類、點評、評分以及價格屬性。

以上,我們都能輕易分析出來,但是還有一個選中框,理解起來有一點點難度。

當(dāng)我們打開軟件時,所有的菜品以列表形式展示出來,它的屬性是固定不變的,只有后面的選中框是用戶點擊的,它的值是動態(tài)變化的。

因此,我們把不變的菜品和變化的選中框當(dāng)做是一個ViewModel,它有兩個數(shù)據(jù)屬性,菜品類和是否被選中。

我們的主界面,也會有一個與之對應(yīng)的ViewModel 它有三個數(shù)據(jù)屬性,餐館類、選中菜品總數(shù)和Dish列表;有兩個命令屬性,訂餐和菜品是否選中命令。

到這里,基于在線訂餐系統(tǒng)的MVVM各個模型,都已經(jīng)清楚明了了。接下來,我們編程實現(xiàn)它。

案例實現(xiàn)

要實現(xiàn)MVVM,我們需借助Prism。

Prism是一個框架,用于在WPF和Xamarin Forms中構(gòu)建松散耦合,它提供了一組設(shè)計模式的實現(xiàn),這些設(shè)計模式有助于編寫結(jié)構(gòu)良好且可維護(hù)的XAML應(yīng)用程序,包括MVVM、依賴注入、命令、EventAggregator等。

這里用到的是Prism的NotificationObject基類和DelegateCommand,旨在幫助我們借助ViewModel實現(xiàn)View與Model的數(shù)據(jù)自動更新。

打開VS2019,新建一個解決方案,再新建幾個文件夾,分別是Data、Services、Views、Models和ViewModels。這樣,我們的項目整體架構(gòu)就搭建好了。

圖片

右擊引用,通過管理NuGet程序包,在彈出的窗口瀏覽中輸入“Prism.MVVM”,在線安裝Prism。

Data文件夾中,存放的是Data.xml,里面是菜品信息。


<Dishes>
  <Dish>
    <Name>水煮肉片Name>
    <Category>徽菜Category>
    <Comment>招牌菜Comment>
    <Score>9.7Score>
    <Price>45元Price>
  Dish>
  <Dish>
    <Name>椒鹽龍蝦Name>
    <Category>川菜Category>
    <Comment>招牌菜Comment>
    <Score>9.2Score>
    <Price>43元Price>
  Dish>
  <Dish>
    <Name>京醬豬蹄Name>
    <Category>湘菜Category>
    <Comment>招牌菜Comment>
    <Score>9.8Score>
    <Price>51元Price>
  Dish>
  <Dish>
    <Name>爆炒魷魚Name>
    <Category>徽菜Category>
    <Comment>招牌菜Comment>
    <Score>9.3Score>
    <Price>54元Price>
  Dish>
  <Dish>
    <Name>可樂雞翅Name>
    <Category>湘菜Category>
    <Comment>招牌菜Comment>
    <Score>9.4Score>
    <Price>44元Price>
  Dish>
  <Dish>
    <Name>涼拌龍須Name>
    <Category>湘菜Category>
    <Comment>涼拌Comment>
    <Score>8.6Score>
    <Price>18元Price>
  Dish>
  <Dish>
    <Name>麻辣花生Name>
    <Category>湘菜Category>
    <Comment>涼拌Comment>
    <Score>8.7Score>
    <Price>19元Price>
  Dish>
  <Dish>
    <Name>韭菜炒肉Name>
    <Category>湘菜Category>
    <Comment>炒菜Comment>
    <Score>9.4Score>
    <Price>25元Price>
  Dish>
  <Dish>
    <Name>青椒肉絲Name>
    <Category>湘菜Category>
    <Comment>炒菜Comment>
    <Score>9.1Score>
    <Price>26元Price>
  Dish>
  <Dish>
    <Name>紅燒茄子Name>
    <Category>湘菜Category>
    <Comment>招牌菜Comment>
    <Score>9.4Score>
    <Price>24元Price>
  Dish>
  <Dish>
    <Name>紅燒排骨Name>
    <Category>湘菜Category>
    <Comment>招牌菜Comment>
    <Score>9.4Score>
    <Price>42元Price>
  Dish>
  <Dish>
    <Name>番茄蛋湯Name>
    <Category>湘菜Category>
    <Comment>招牌菜Comment>
    <Score>9.4Score>
    <Price>21元Price>
  Dish>
  <Dish>
    <Name>山藥炒肉Name>
    <Category>湘菜Category>
    <Comment>招牌菜Comment>
    <Score>9.4Score>
    <Price>27元Price>
  Dish>
  <Dish>
    <Name>極品肥牛Name>
    <Category>湘菜Category>
    <Comment>招牌菜Comment>
    <Score>9.4Score>
    <Price>58元Price>
  Dish>
  <Dish>
    <Name>香拌牛肉Name>
    <Category>湘菜Category>
    <Comment>招牌菜Comment>
    <Score>9.4Score>
    <Price>48元Price>
  Dish>
  <Dish>
    <Name>手撕包菜Name>
    <Category>湘菜Category>
    <Comment>招牌菜Comment>
    <Score>9.4Score>
    <Price>16元Price>
  Dish>
  <Dish>
    <Name>香辣花甲Name>
    <Category>湘菜Category>
    <Comment>招牌菜Comment>
    <Score>9.4Score>
    <Price>36元Price>
  Dish>
  <Dish>
    <Name>酸菜魚Name>
    <Category>湘菜Category>
    <Comment>招牌菜Comment>
    <Score>9.4Score>
    <Price>56元Price>
  Dish>
Dishes>

Models文件夾中,存放的是Dish類和Restaurant類。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace zy.CrazyElephant.Client.Models
{
    public class Dish
    {
        public string Name { get; set; }
        public string Category { get; set; }
        public string Comment { get; set; }
        public double Score { get; set; }
        public string Price { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace zy.CrazyElephant.Client.Models
{
   public class Restaurant
    {
        public string Name { get; set; }
        public string Address { get; set; }
        public string PhoneNumber { get; set; }
    }
}

ViewModels中,存放的是兩個ViewModel。

using Microsoft.Practices.Prism.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using zy.CrazyElephant.Client.Models;

namespace zy.CrazyElephant.Client.ViewModels
{
   public class DishMenuItemViewModel:NotificationObject
    {
        public Dish Dish{ get; set; }

        private bool isSelected;

        public bool IsSelected
        {
            get { return isSelected; }
            set
            {
                isSelected = value;
                this.RaisePropertyChanged("IsSelected");
            }
        }

    }
}
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using zy.CrazyElephant.Client.Models;
using zy.CrazyElephant.Client.Services;

namespace zy.CrazyElephant.Client.ViewModels
{
    public class MainWindowViewModel:NotificationObject
    {
        public MainWindowViewModel()
        {
            this.LoadRestaurant();
            this.LoadMenu();

            this.PlaceOrderCommand = new DelegateCommand(PlaceOrderCommandExecute);
            this.SelectMenuItemCommand = new DelegateCommand(SelectMenuItemExecute);
        }

        public DelegateCommand PlaceOrderCommand { get; set; }
        public DelegateCommand SelectMenuItemCommand { get; set; }

        private int count;

        public int Count
        {
            get { return count; }
            set
            {
                count = value;
                this.RaisePropertyChanged("Count");
            }
        }

        private Restaurant restaurant;

        public Restaurant Restaurant
        {
            get { return restaurant; }
            set
            {
                restaurant = value;
                this.RaisePropertyChanged("Restaurant");
            }
        }

        private List dishMenu;

        public List DishMenu
        {
            get { return dishMenu; }
            set
            {
                dishMenu = value;
                this.RaisePropertyChanged("DishMenu");
            }
        }

        private void LoadRestaurant()
        {
            this.Restaurant = new Restaurant();
            this.Restaurant.Name = "聚賢莊";
            this.Restaurant.Address = "xx省xx市xx區(qū)xx街道xx樓xx層xx號";
            this.Restaurant.PhoneNumber = "18888888888 or 6666-6666666";
        }

        private void LoadMenu()
        {
            XmlDataService ds = new XmlDataService();
            var dishes = ds.GetAllDishes();
            this.DishMenu = new List();
            foreach (var dish in dishes)
            {
                DishMenuItemViewModel item = new DishMenuItemViewModel();
                item.Dish = dish;
                this.DishMenu.Add(item);
            }
        }

        private void PlaceOrderCommandExecute()
        {
            var selectedDishes = this.DishMenu.Where(i => i.IsSelected == true).Select(i => i.Dish.Name).ToList();
            IOrderService os = new MockOrderService();
            os.PlaceOrder(selectedDishes);
            MessageBox.Show("訂餐成功!");
        }

        private void SelectMenuItemExecute()
        {
            this.Count = this.DishMenu.Count(i => i.IsSelected == true);
        }
    }
}

Services中,IDataService和IOrderService,是兩個基接口,前一個用于獲取菜品數(shù)據(jù);后一個用于訂餐處理。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using zy.CrazyElephant.Client.Models;

namespace zy.CrazyElephant.Client.Services
{
    public interface IDataService
    {
        List GetAllDishes();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace zy.CrazyElephant.Client.Services
{
    public interface IOrderService
    {
        void PlaceOrder(List dishes);
    }
}

XmlDataService類,繼承自IDataService,用于讀取xml文件,獲取菜品數(shù)據(jù)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using zy.CrazyElephant.Client.Models;

namespace zy.CrazyElephant.Client.Services
{
    public class XmlDataService : IDataService
    {
        public List GetAllDishes()
        {
            List dishList = new List();
            string xmlFileName = System.IO.Path.Combine(Environment.CurrentDirectory, @"Data\\Data.xml");
            XDocument doc = XDocument.Load(xmlFileName);
            var dishes = doc.Descendants("Dish");
            foreach (var d in dishes)
            {
                Dish dish = new Dish();
                dish.Name = d.Element("Name").Value;
                dish.Category = d.Element("Category").Value;
                dish.Comment = d.Element("Comment").Value;
                dish.Score = Convert.ToDouble(d.Element("Score").Value);
                dish.Price = d.Element("Price").Value;
                dishList.Add(dish);
            }
            return dishList;
        }
    }
}

MockOrderService類,繼承自IOrderService,用于處理訂餐邏輯,這里是把選中的菜品名字以txt文件保存到硬盤中。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace zy.CrazyElephant.Client.Services
{
    public class MockOrderService : IOrderService
    {
        public void PlaceOrder(List dishes)
        {
            System.IO.File.WriteAllLines(Environment.CurrentDirectory + "\\\\order.txt", dishes.ToArray());
        }
    }
}

只有一個界面,即MainWindow.xaml,代碼如下。

<Window x:Class="zy.CrazyElephant.Client.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:zy.CrazyElephant.Client"
        mc:Ignorable="d"
        Title="{Binding Restaurant.Name,StringFormat=\\{0\\}-在線訂餐}" Height="600" Width="1000" WindowStartupLocation="CenterScreen">
    <Border BorderBrush="Orange" BorderThickness="3" CornerRadius="6" Background="AliceBlue">
        <Grid x:Name="Root" Margin="4">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="auto"/>
            Grid.RowDefinitions>
            <Border BorderBrush="Orange" BorderThickness="1" CornerRadius="6" Padding="4">
                <StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <StackPanel.Effect>
                            <DropShadowEffect Color="LightGray"/>
                        StackPanel.Effect>
                        <TextBlock Text="歡迎光臨-" FontSize="60" FontFamily="LiShu"/>
                        <TextBlock Text="{Binding Restaurant.Name}" FontSize="60" FontFamily="LiShu"/>
                    StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="小店地址:" FontSize="24" FontFamily="LiShu"/>
                        <TextBlock Text="{Binding Restaurant.Address}" FontSize="24" FontFamily="LiShu"/>
                    StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="訂餐電話:" FontSize="24" FontFamily="LiShu"/>
                        <TextBlock Text="{Binding Restaurant.PhoneNumber}" FontSize="24" FontFamily="LiShu"/>
                    StackPanel>
                StackPanel>
            Border>
            <DataGrid AutoGenerateColumns="False" GridLinesVisibility="None" CanUserAddRows="False" CanUserDeleteRows="False" Margin="0.4" Grid.Row="1" FontSize="16" ItemsSource="{Binding DishMenu}">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="菜品" Binding="{Binding Dish.Name}" Width="120"/>
                    <DataGridTextColumn Header="種類" Binding="{Binding Dish.Category}" Width="120"/>
                    <DataGridTextColumn Header="點評" Binding="{Binding Dish.Comment}" Width="120"/>
                    <DataGridTextColumn Header="推薦分?jǐn)?shù)" Binding="{Binding Dish.Score}" Width="120"/>
                    <DataGridTextColumn Header="價格" Binding="{Binding Dish.Price}" Width="120"/>
                    <DataGridTemplateColumn Header="選中" SortMemberPath="IsSelected" Width="120">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox IsChecked="{Binding Path=IsSelected,UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" HorizontalAlignment="Center" Command="{Binding Path=DataContext.SelectMenuItemCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=DataGrid}}"/>
                            DataTemplate>
                        DataGridTemplateColumn.CellTemplate>
                    DataGridTemplateColumn>
                DataGrid.Columns>
            DataGrid>
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="2">
                <TextBlock Text="共計" VerticalAlignment="Center"/>
                <TextBox IsReadOnly="True" TextAlignment="Center" Width="120" Text="{Binding Count}" Margin="4,0"/>
                <Button Content="Order" Height="24" Width="120" Command="{Binding PlaceOrderCommand}"/>
            StackPanel>
        Grid>
    Border>
Window>

MainWindow.xaml.cs中,代碼很簡單,只需要添加一行即可。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using zy.CrazyElephant.Client.ViewModels;

namespace zy.CrazyElephant.Client
{
    /// <summary>
    /// MainWindow.xaml 的交互邏輯
    /// summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new MainWindowViewModel();
        }
    }
}

無論界面如何變化,只要符合這種邏輯形式的軟件通過前端界面Binding的方式,我們的業(yè)務(wù)邏輯代碼就不會變動,通用性很強。實現(xiàn)了前端界面與后端邏輯分離,開閉原則應(yīng)用的很到位。

寫在最后

基本上,絕大多數(shù)軟件所做的工作無非就是從數(shù)據(jù)存儲中讀出數(shù)據(jù),展現(xiàn)到用戶界面上,然后從用戶界面接收輸入,寫入到數(shù)據(jù)存儲里面去。所以,對于數(shù)據(jù)存儲(Model)和界面(View)這兩層,大家基本沒什么異議。但是,如何把Model展現(xiàn)到View上,以及如何把數(shù)據(jù)從View寫入到Model里,不同的人有不同的意見。

MVC派的看法是,界面上的每個變化都是一個事件,我只需要針對每個事件寫一堆代碼,來把用戶的輸入轉(zhuǎn)換成Model里的對象就行了,這堆代碼可以叫Controller。

而MVVM派的看法是,我給View里面的各種控件也定義一個對應(yīng)的數(shù)據(jù)對象,這樣,只要修改這個數(shù)據(jù)對象,View里面顯示的內(nèi)容就自動跟著刷新;而在View里做了任何操作,這個數(shù)據(jù)對象也跟著自動更新,這樣多美。

所以,ViewModel就是與View對應(yīng)的Model。因為,數(shù)據(jù)庫結(jié)構(gòu)往往是不能直接跟界面控件一一對應(yīng)上的,因此,需要再定義一個數(shù)據(jù)對象專門對應(yīng)View上的控件。而ViewModel的職責(zé)就是把Model對象封裝成可以顯示和接受輸入的界面數(shù)據(jù)對象。

至于ViewModel的數(shù)據(jù)隨著View自動刷新,并且同步到Model里去,這部分代碼可以寫成公用的框架,不用程序員自己操心了。

簡單的說,ViewModel就是View與Model的連接器,View與Model通過ViewModel實現(xiàn)數(shù)據(jù)雙向綁定。

END

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Model
    +關(guān)注

    關(guān)注

    0

    文章

    339

    瀏覽量

    25061
  • 設(shè)計模式
    +關(guān)注

    關(guān)注

    0

    文章

    53

    瀏覽量

    8626
  • MVC
    MVC
    +關(guān)注

    關(guān)注

    0

    文章

    73

    瀏覽量

    13852
收藏 人收藏

    評論

    相關(guān)推薦

    #硬聲創(chuàng)作季 Java項目實戰(zhàn)(金融項目)-MVVM

    JAVA編程語言
    Mr_haohao
    發(fā)布于 :2022年09月07日 10:55:17

    Vue2.0+3.0-Day3-03.簡介 - mvvm

    vue
    電子學(xué)習(xí)
    發(fā)布于 :2023年01月08日 21:10:12

    89.089 尚硅谷 尚融寶 MVVM

    項目開發(fā)
    充八萬
    發(fā)布于 :2023年07月18日 18:21:32

    AWTK-MVVM在STM32H743上是怎樣去移植的

    AWTK-MVVM 在 STM32H743 上的移植筆記本項目除了實現(xiàn)基本功能的移植外,還提供了如下功能:集成實時操作系統(tǒng) (RTOS)(騰訊的 TinyOS)集成 FATFS 文件系統(tǒng),訪問 SD
    發(fā)表于 08-24 06:45

    AWTK-MVVM是什么?其功能有哪些

    AWTK-MVVM是一套為AWTK用C語言開發(fā),并支持各種腳本語言的MVVM框架,實現(xiàn)了數(shù)據(jù)綁定、命令綁定和窗口導(dǎo)航等基本功能,使用AWTK-MVVM開發(fā)應(yīng)用程序,無需學(xué)習(xí)AWTK本身的API,只需
    發(fā)表于 12-15 06:07

    iOS中怎樣用代碼實現(xiàn)mvvm的記錄

    卷首 最近新工作中用到的RAC+MVVM的開發(fā)模式,由于之前都是用MVC,從自己的菜雞水平感覺這兩種設(shè)計模式在思想上還是有些微區(qū)別的,然后自己也是看了挺多關(guān)于這兩個模式異同與使用利弊的文章,但是說
    發(fā)表于 09-25 11:19 ?0次下載
    iOS中怎樣用代碼實現(xiàn)<b class='flag-5'>mvvm</b>的記錄

    前端渲染引擎的優(yōu)勢分析

    React、Vue、Angular等均屬于MVVM模式,在一些只需完成數(shù)據(jù)和模板簡單渲染的場合,顯得笨重且學(xué)習(xí)成本較高,而解決該問題非常優(yōu)秀框架之一是doT.js,本文將對它進(jìn)行詳解。 背景 前端
    發(fā)表于 09-30 13:14 ?0次下載
    前端渲染引擎的優(yōu)勢分析

    如何使用協(xié)議的實現(xiàn) MVVM 架構(gòu)

    類型,而轉(zhuǎn)為使用繼承來實現(xiàn)。 通過 Natasha 在 do{iOS} 2015上對 MVVM 的介紹,您可以學(xué)習(xí)到如何使用協(xié)議來實現(xiàn)這個功能,而不再采用繼承的方式!Natasha The Robot
    發(fā)表于 10-11 15:13 ?0次下載
    如何使用協(xié)議的實現(xiàn) <b class='flag-5'>MVVM</b> 架構(gòu)

    MVC、MVP與MVVM的異同介紹

    View和ViewModel內(nèi)部通過一個Binder進(jìn)行事件交互,該Binder通過雙向綁定將View與ViewModel中與對于數(shù)據(jù)操作的部分鏈接,當(dāng)對應(yīng)數(shù)據(jù)由更新時同樣會自動地反饋到View層上。
    的頭像 發(fā)表于 06-22 15:34 ?4706次閱讀

    基于MVVM模式的氣動數(shù)據(jù)可視化分析系統(tǒng)

    基于MVVM模式的氣動數(shù)據(jù)可視化分析系統(tǒng)
    發(fā)表于 06-23 16:05 ?27次下載

    AWTK-MVVM C語言MVVM框架

    ./oschina_soft/gitee-awtk-mvvm.zip
    發(fā)表于 06-21 11:33 ?2次下載
    AWTK-<b class='flag-5'>MVVM</b> C語言<b class='flag-5'>MVVM</b>框架

    工業(yè)上位機(jī)開發(fā)實戰(zhàn)WPF+MVVM框架

    上一篇博客介紹了上位機(jī)實現(xiàn)MVVM 框架的步驟 MVVMtoolkit 學(xué)習(xí)_叮當(dāng)說的博客-CSDN博客 下面我們繼續(xù)來講解下實現(xiàn)上位機(jī)中會遇到的一些小問題:之前的程序中我們已經(jīng)知道了 ,當(dāng)數(shù)據(jù)改變
    發(fā)表于 05-09 11:30 ?0次下載
    工業(yè)上位機(jī)開發(fā)實戰(zhàn)WPF+<b class='flag-5'>MVVM</b>框架

    MVVM+RAC的基本概念和使用方式

    在iOS開發(fā)中,采用合適的架構(gòu)模式能夠提高代碼的可維護(hù)性和可測試性。
    的頭像 發(fā)表于 06-06 14:55 ?1230次閱讀

    使用MVVM框架實現(xiàn)一個簡單加法器

    使用MVVM框架來實現(xiàn)一個簡單加法器。最終效果如下,點擊按鈕可以對上面兩個文本框中的數(shù)字進(jìn)行相加得出結(jié)果顯示在第三個文本框中。重點在于看mvvm框架下程序該怎么寫。使用CommunityToolkit.Mvvm框架,通過nuge
    的頭像 發(fā)表于 10-24 14:23 ?814次閱讀
    使用<b class='flag-5'>MVVM</b>框架實現(xiàn)一個簡單加法器

    AWTK 開源智能串口屏方案

    AWTK開源智能串口屏方案發(fā)布,旨在解決傳統(tǒng)串口屏諸多痛點,為用戶提供更開放、更易用、更強大的開源串口屏方案?;贏WTK和AWTK-MVVM實現(xiàn)的串口屏方案。界面修改數(shù)據(jù),自動通知MCU。MCU
    的頭像 發(fā)表于 12-02 08:24 ?944次閱讀
    AWTK 開源智能串口屏方案
    RM新时代网站-首页