背水一戰 Windows 10 (24) - MVVM: 通過 Binding 或 x:Bind 結合 Command 實現,通過非 ButtonBase 觸發命令

来源:http://www.cnblogs.com/webabcd/archive/2016/07/18/5679962.html
-Advertisement-
Play Games

背水一戰 Windows 10 之 MVVM(Model-View-ViewModel): 通過 Binding 或 x:Bind 結合 Command 實現,通過非 ButtonBase 觸發命令 ...


[源碼下載]


背水一戰 Windows 10 (24) - MVVM: 通過 Binding 或 x:Bind 結合 Command 實現,通過非 ButtonBase 觸發命令



作者:webabcd


介紹
背水一戰 Windows 10 之 MVVM(Model-View-ViewModel)

  • 通過 Binding 或 x:Bind 結合 Command 實現,通過非 ButtonBase 觸發命令



示例
1、Model
MVVM/Model/Product.cs

/*
 * Model 層的實體類,如果需要通知則需要實現 INotifyPropertyChanged 介面
 */

using System.ComponentModel;

namespace Windows10.MVVM.Model
{
    public class Product : INotifyPropertyChanged
    {
        public Product()
        {
            ProductId = 0;
            Name = "";
            Category = "";
        }

        private int _productId;
        public int ProductId
        {
            get { return _productId; }
            set
            {
                _productId = value;
                RaisePropertyChanged(nameof(ProductId));
            }
        }

        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                RaisePropertyChanged(nameof(Name));
            }
        }

        private string _category;
        public string Category
        {
            get { return _category; }
            set
            {
                _category = value;
                RaisePropertyChanged(nameof(Category));
            }
        }
        

        public event PropertyChangedEventHandler PropertyChanged;
        protected void RaisePropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}

MVVM/Model/ProductDatabase.cs

/*
 * Model 層的數據持久化操作(本地或遠程)
 * 
 * 本例只是一個演示
 */

using System;
using System.Collections.Generic;
using System.Linq;

namespace Windows10.MVVM.Model
{
    public class ProductDatabase
    {
        private List<Product> _products = null;

        public List<Product> GetProducts()
        {
            if (_products == null)
            {
                Random random = new Random();

                _products = new List<Product>();

                for (int i = 0; i < 100; i++)
                {
                    _products.Add
                    (
                        new Product
                        {
                            ProductId = i,
                            Name = "Name" + i.ToString().PadLeft(4, '0'),
                            Category = "Category" + (char)random.Next(65, 91)
                        }
                    );
                }
            }

            return _products;
        }

        public List<Product> GetProducts(string name, string category)
        {
            return GetProducts().Where(p => p.Name.Contains(name) && p.Category.Contains(category)).ToList();
        }

        public void Update(Product product)
        {
            var oldProduct = _products.Single(p => p.ProductId == product.ProductId);
            oldProduct = product;
        }

        public Product Add(string name, string category)
        {
            Product product = new Product();
            product.ProductId = _products.Max(p => p.ProductId) + 1;
            product.Name = name;
            product.Category = category;

            _products.Insert(0, product);

            return product;
        }

        public void Delete(Product product)
        {
            _products.Remove(product);
        }
    }
}


2、ViewModel
MVVM/ViewModel1/MyCommand.cs

/*
 * 為了方便使用,把 ICommand 再封裝一層
 */

using System;
using System.Windows.Input;

namespace Windows10.MVVM.ViewModel1
{
    public class MyCommand : ICommand
    {
        // 由 public void Execute(object parameter) 調用的委托
        public Action<object> MyExecute { get; set; }

        // 由 public bool CanExecute(object parameter) 調用的委托
        public Func<object, bool> MyCanExecute { get; set; }

        public MyCommand(Action<object> execute, Func<object, bool> canExecute)
        {
            this.MyExecute = execute;
            this.MyCanExecute = canExecute;
        }

        // 需要發佈此事件的話,則調用 RaiseCanExecuteChanged 方法即可
        public event EventHandler CanExecuteChanged;
        public void RaiseCanExecuteChanged()
        {
            if (CanExecuteChanged != null)
            {
                CanExecuteChanged(this, EventArgs.Empty);
            }
        }

        // 用於決定當前綁定的 Command 能否被執行
        // parameter 是由 ButtonBase 的 CommandParameter 傳遞過來的
        // 如果返回 false 則對應的 ButtonBase 將變為不可用
        public bool CanExecute(object parameter)
        {
            return this.MyCanExecute == null ? true : this.MyCanExecute(parameter);
        }

        // 用於執行對應的命令,只有在 CanExecute() 返回 true 時才可以被執行
        // parameter 是由 ButtonBase 的 CommandParameter 傳遞過來的對象
        public void Execute(object parameter)
        {
            this.MyExecute(parameter);
        }
    }
}

MVVM/ViewModel1/ProductViewModel.cs

/*
 * ViewModel 層
 *
 * 註:為了方便使用,此例對 ICommand 做了一層封裝。如果需要瞭解比較原始的 MVVM 實現請參見 http://www.cnblogs.com/webabcd/archive/2013/08/29/3288304.html
 */

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Windows10.MVVM.Model;

namespace Windows10.MVVM.ViewModel1
{
    public class ProductViewModel : INotifyPropertyChanged
    {
        // 用於提供 Products 數據
        private ObservableCollection<Product> _products;
        public ObservableCollection<Product> Products
        {
            get { return _products; }
            set
            {
                _products = value;
                RaisePropertyChanged(nameof(Products));
            }
        }

        // 用於“添加”和“查詢”的 Product 對象
        private Product _product;
        public Product Product
        {
            get { return _product; }
            set
            {
                _product = value;
                RaisePropertyChanged(nameof(Product));
            }
        }

        // 資料庫對象
        private ProductDatabase _context = null;

        public ProductViewModel()
        {
            _context = new ProductDatabase();

            Product = new Product();
            Products = new ObservableCollection<Product>(_context.GetProducts());
        }


        private MyCommand _getProductsCommand;
        public MyCommand GetProductsCommand
        {
            get
            {
                return _getProductsCommand ?? (_getProductsCommand = new MyCommand
                  ((object obj) =>
                  {
                      // 從 Model 層獲取數據
                      Products = new ObservableCollection<Product>(_context.GetProducts(Product.Name, Product.Category));
                  },
                  null));
            }
        }

        private MyCommand _addProductCommand;
        public MyCommand AddProductCommand
        {
            get
            {
                return _addProductCommand ?? (_addProductCommand = new MyCommand
                  ((object obj) =>
                  {
                      // 在 Model 層添加一條數據
                      Product newProduct = _context.Add(Product.Name, Product.Category);

                      // 更新 ViewModel 層數據
                      Products.Insert(0, newProduct);
                  },
                  null));
            }
        }

        private MyCommand _updateProductCommand;
        public MyCommand UpdateProductCommand
        {
            get
            {
                return _updateProductCommand ?? (_updateProductCommand = new MyCommand
                  ((object obj) =>
                  {
                      // 通過 CommandParameter 傳遞過來的數據
                      Product product = obj as Product;

                      // 更新 ViewModel 層數據
                      product.Name = product.Name + "U";
                      product.Category = product.Category + "U";

                      // 更新 Model 層數據
                      _context.Update(product);
                  },
                  // 對應 ICommand 的 CanExecute(),如果返回 false 則對應的 ButtonBase 將變為不可用
                  (object obj) => obj != null));
            }
        }

        private MyCommand _deleteProductCommand;
        public MyCommand DeleteProductCommand
        {
            get
            {
                return _deleteProductCommand ?? (_deleteProductCommand = new MyCommand
                  ((object obj) =>
                  {
                      // 通過 CommandParameter 傳遞過來的數據
                      Product product = obj as Product;

                      // 更新 Model 層數據
                      _context.Delete(product);

                      // 更新 ViewModel 層數據
                      Products.Remove(product);
                  },
                  // 對應 ICommand 的 CanExecute(),如果返回 false 則對應的 ButtonBase 將變為不可用
                  (object obj) => obj != null));
            }
        }


        public event PropertyChangedEventHandler PropertyChanged;
        protected void RaisePropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}


3、View
MVVM/View/Demo1_2.xaml

<Page
    x:Class="Windows10.MVVM.View.Demo1_2"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Windows10.MVVM.View"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    
    xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" 
    xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
    
    xmlns:vm="using:Windows10.MVVM.ViewModel1">

    <Grid Background="Transparent">
        <StackPanel Margin="10 0 10 10">

            <!--
                View 層
            -->

            <!--
                本例通過 Binding 結合 Command 實現 MVVM(用 x:Bind 結合 Command 實現 MVVM 也是一樣的),通過非 ButtonBase 觸發命令
            -->

            <StackPanel.DataContext>
                <vm:ProductViewModel />
            </StackPanel.DataContext>

            <ListView Name="listView" ItemsSource="{Binding Products}" Width="300" Height="300" HorizontalAlignment="Left" VerticalAlignment="Top">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding Name}" HorizontalAlignment="Left" />
                            <TextBlock Text="{Binding Category}" HorizontalAlignment="Left" Margin="10 0 0 0" />
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

            <StackPanel Orientation="Horizontal" Margin="0 10 0 0" DataContext="{Binding Product}">
                <TextBlock Text="Name:" VerticalAlignment="Center" />
                <TextBox Name="txtName" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100" />
                <TextBlock Text="Category:" VerticalAlignment="Center" Margin="20 0 0 0" />
                <TextBox Name="txtCategory" Text="{Binding Category, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100" />
            </StackPanel>

            <!--
                需要引用 Microsoft.Xaml.Interactions.dll 和 Microsoft.Xaml.Interactivity.dll
            
                Microsoft.Xaml.Interactions.Core:EventTriggerBehavior
                    EventName - 關聯的事件名稱
            
                Microsoft.Xaml.Interactions.Core:InvokeCommandAction
                    Command - 指定關聯的 ICommand
                    CommandParameter - 傳遞給 ICommand 的參數
            -->
            <StackPanel Orientation="Horizontal" Margin="0 10 0 0">
                <TextBlock Text="查詢">
                     <Interactivity:Interaction.Behaviors>
                         <Core:EventTriggerBehavior EventName="Tapped">
                             <Core:InvokeCommandAction Command="{Binding GetProductsCommand}" />
                         </Core:EventTriggerBehavior>
                     </Interactivity:Interaction.Behaviors>
                </TextBlock>

                <TextBlock Text="添加" Margin="10 0 0 0">
                     <Interactivity:Interaction.Behaviors>
                         <Core:EventTriggerBehavior EventName="Tapped">
                             <Core:InvokeCommandAction Command="{Binding AddProductCommand}" />
                         </Core:EventTriggerBehavior>
                     </Interactivity:Interaction.Behaviors>
                </TextBlock>

                <TextBlock Text="更新" Margin="10 0 0 0">
                     <Interactivity:Interaction.Behaviors>
                         <Core:EventTriggerBehavior EventName="Tapped">
                             <Core:InvokeCommandAction Command="{Binding UpdateProductCommand}" CommandParameter="{Binding SelectedItem, ElementName=listView}"/>
                         </Core:EventTriggerBehavior>
                     </Interactivity:Interaction.Behaviors>
                </TextBlock>

                <TextBlock Text="刪除" Margin="10 0 0 0">
                     <Interactivity:Interaction.Behaviors>
                         <Core:EventTriggerBehavior EventName="Tapped">
                             <Core:InvokeCommandAction Command="{Binding DeleteProductCommand}" CommandParameter="{Binding SelectedItem, ElementName=listView}"/>
                         </Core:EventTriggerBehavior>
                     </Interactivity:Interaction.Behaviors>
                </TextBlock>
            </StackPanel>

        </StackPanel>
    </Grid>
</Page>



OK
[源碼下載]


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 昨天《怎樣操作WebAPI介面(顯示數據)》http://www.cnblogs.com/insus/p/5670401.html既有使用jQuery,也有使作HttpClient來從資料庫獲取數據,並顯示在ASP.NET MVC的視圖中。今天Insus.NET想把例子全完成,就是把其餘的添加,更新 ...
  • 最近跟著師父學習軟體,因為軟體比較複雜,所以設計到判斷某個窗體是否打開了,如果打開了,進行某種操作,如果沒有打開,又進行另一種操作。 雖然不難,但是記一下總是好的。 ...
  • 什麼是Moq Moq是一個框架,一個可以模擬對象的框架,比如在不實現介面的情況下獲得介面的對象,這個介面的所有行為都可以用代碼控制 快速開始 被模擬的可以是介面和類,類不能是密封類,只有類中的虛函數能被模擬 先寫一個介面,下麵例子大部分用這個介面,但不全用這個介面 當不用 時候 Throws Moc ...
  • 摘要: Web.config的讀取 對於Web.config的讀取大家都很屬性了。平時我們用得比較多的就是appSettings節點下配置。如: 我們對應的代碼是: 是的,很簡單、很方便、很清晰。可以總感覺缺少那麼一點“面向對象”的感覺。少還無所謂,如果幾十個上百個呢?我們是不是可以考慮分類定義,如... ...
  • 現象:panel1和panel2或更多panel,疊放在一起,panel和panel2是同一層次的。panel1和panel2切換時只能顯示一個panel,如何切換呢? ...
  • 昨天看了一天的ajax,今天又看了兩個小時,終於弄出來個門道,其實ajax不是難,不是枯燥,而是自己不會用,這是根本所在 下麵分享學習經驗,以下是我程式代碼的下載地址:http://vdisk.weibo.com/s/BQ2aD 或者這個地址 http://download.csdn.net/det ...
  • 面向對象是一種開發思想,最應該記住的一句話是萬物皆對象。為了讓程式更好的被理解和編寫,把現實生活中描述事物的方式和思路融合進入,就成了面向對象的思想。把生活中的事物融合進程式中那麼就需要描述,描述分為特征和行為兩方面,而不同類別的對象特征和行為具有巨大的差異,為了更好的制定描述每一類事物的方式,那麼 ...
  • 在網上看到別人的代碼,寫下來留著看,歡迎各位指教,有沒有工廠模式的學習資料啊,留下給小弟學習學習. 首先寫個Model類,實現業務實體,我的比較簡單,只有三個欄位 View Code 1 public class LoginModel 2 { 3 #region 4 5 private int _A ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...