visual C#(二十六)在UWP應用中顯示和搜索數據

參考書:《 visual C# 從入門到精通》
第四部分 用C#構建UMP應用
第26章 在WP應用中顯示和搜索數據

26.1 實現Model-View-ViewModel模式

MVVM模式中,Model提供應用程序需要的數據,View則指定數據在UI中的顯示方式。ViewModel包含用於連接兩者的邏輯,它獲取用戶輸入並將其轉換成對模型執行業務操作的指令;它還從模型獲取數據,並以視圖要求的方式格式化。由於應用程序可能提供相同數據的多個視圖。ViewModel的一個工作是確保來自相同模型的數據能由不同視圖顯示和處理。UWP應用中,視圖可配置數據綁定以連接ViewModel提供的數據。另外,視圖可調用由ViewModel事項的命令,請求ViewModel更新模型中的數據或執行業務操作。

26.1.1 通過數據綁定顯示數據

我們繼續上一章節的應用開發。但我們稍微變動一下,讓控件在藍色背景上顯示,這樣可以更顯眼一些。我們利用Rectangle控件來創建藍色背景。XAML標記如下:

				<Rectangle Grid.Row="0" Grid.RowSpan="6" Grid.Column="1" Grid.ColumnSpan="7">
                    <Rectangle.Fill>
                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5.0">
                            <GradientStop Color="#FF0E3895"/>
                            <GradientStop Color="#FF141415" Offset="0.929"/>
                        </LinearGradientBrush>
                    </Rectangle.Fill>
                </Rectangle>
  1. 右擊項目新建一個公共類,命名爲Customer.cs,代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace C_25_2_Customers
{
    public class Customer
    {
        private int _customerID;
        public int CustomerID
        {
            get { return this._customerID;}
            set { this._customerID = value; }
        }
        private string _title;
        public string Title
        {
            get { return this._title; }
            set { this._title = value; }
        }
        private string _firstName;
        public string FirstName
        {
            get { return this._firstName; }
            set { this._firstName = value; }
        }
        private string _lastName;
        public string LastName
        {
            get { return this._lastName; }
            set { this._lastName = value; }
        }
        private string _emailAddress;
        public string EmailAddress
        {
            get { return this._emailAddress; }
            set { this._emailAddress = value; }
        }
        private string _phone;
        public string Phone
        {
            get { return this._phone; }
            set { this._phone = value; }
        }
    }
}
  1. 修改所有的TextBox控件中的Text屬性:
				<TextBox Grid.Row="0" Grid.Column="1" x:Name="cid" HorizontalAlignment="Stretch"  TextWrapping="Wrap" Text="{Binding CustomerID}" VerticalAlignment="Center" FontSize="20" IsReadOnly="True"/>
                <TextBox Grid.Row="2" Grid.Column="1" x:Name="cfirstName" HorizontalAlignment="Stretch"  TextWrapping="Wrap" Text="{Binding FirstName}" VerticalAlignment="Center" FontSize="20" />
                <TextBox Grid.Row="3" Grid.Column="1" x:Name="clastName" HorizontalAlignment="Stretch" TextWrapping="Wrap" Text="{Binding LastName}" VerticalAlignment="Center" FontSize="20" />
      ...;
                <TextBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="3" x:Name="cemail" HorizontalAlignment="Stretch"  TextWrapping="Wrap" Text="{Binding EmailAddress}" VerticalAlignment="Center" Width="400" FontSize="20"/>
                <TextBox Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="3" x:Name="cphone" HorizontalAlignment="Stretch"   TextWrapping="Wrap" Text="{Binding Phone}" VerticalAlignment="Center" Width="200" FontSize="20"/>

  1. MainPage.xaml.cs中添加如下代碼:
public MainPage()
        {
            this.InitializeComponent();
            Customer customer = new Customer
            {
                CustomerID = 1,
                Title = "Mr",
                FirstName = "John",
                LastName = "Sharp",
                EmailAddress = "[email protected]",
                Phone = "111-1111"
            };
            this.DataContext = customer;
        }

運行以後效果如下:
在這裏插入圖片描述在這裏插入圖片描述

注意到一點,就是在窄視圖下修改TextBox中的數據回車,回到寬視圖數據又會變回來。說明數據綁定是單向操作,對顯示的數據進行的操作不會寫回數據源。

26.1.2 通過數據綁定修改數據

我們現在要實現雙向的數據綁定,應該怎麼作呢。先不看書上怎麼說,自己想想的話首先想到的是通過控件的相關的事件處理方法。但這樣要一個一個的寫代碼會有點麻煩。實際上由更簡單的方法。本質上也是事件響應,但方便很多。

  1. 對所有的TextBox控件的XAML標記作修改:<TextBox Grid.Row="1" Grid.Column="1" x:Name="id" HorizontalAlignment="Stretch" TextWrapping="Wrap" Text="{Binding CustomerID,Mode=TwoWay}" VerticalAlignment="Center" FontSize="20" IsReadOnly="True"/>
  2. 修改Customer.cs中的代碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;

namespace C_25_2_Customers
{
    public class Customer:INotifyPropertyChanged
    {
        private int _customerID;
        public int CustomerID
        {
            get { return this._customerID;}
            set { this._customerID = value; this.OnPropertyChanged(nameof(CustomerID)); }
        }
        private string _title;
        public string Title
        {
            get { return this._title; }
            set { this._title = value;this.OnPropertyChanged(nameof(Title)); }
        }
        private string _firstName;
        public string FirstName
        {
            get { return this._firstName; }
            set { this._firstName = value;this.OnPropertyChanged(nameof(FirstName)); }
        }
        private string _lastName;
        public string LastName
        {
            get { return this._lastName; }
            set { this._lastName = value;this.OnPropertyChanged(nameof(LastName)); }
        }
        private string _emailAddress;
        public string EmailAddress
        {
            get { return this._emailAddress; }
            set { this._emailAddress = value; this.OnPropertyChanged(nameof(EmailAddress)); }
        }
        private string _phone;

        
        public string Phone
        {
            get { return this._phone; }
            set { this._phone = value;this.OnPropertyChanged(nameof(Phone)); }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(String propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

    }
}

這樣數據綁定就是雙向的了。

26.1.3 爲ComboBox控件使用數據綁定

ComboBox控件比較特殊。

  1. 首先在ComboBox控件的XAML標記中設定屬性SelectedValue:<ComboBox Grid.Row="1" ... SelectedValue="{Binding Title,Mode=TwoWay}">
  2. MainPage.xaml.cs中添加如下代碼:
 public MainPage()
        {
            this.InitializeComponent();

            List<string> titles = new List<string> { "Mr", "Mrs", "Ms", "Miss" };
            this.title.ItemsSource = titles;
            this.ctitle.ItemsSource = titles;
            ...;
        }

這樣就可以了。

26.1.4 創建ViewModel

ViewModel在視圖和模型之間建立了連接,實現了應用程序的業務邏輯。業務邏輯應獨立於視圖和模型。ViewModel通過一組命令向視圖公開業務邏輯。UI可根據用戶在應用中的導航方式來觸發命令。

我們接着前面的來。

  1. 右擊項目新建一個公共類,命名爲ViewModel.cs,代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace C_25_2_Customers
{
    public class ViewModel
    {
        private List<Customer> customers;
        private int currentCustomer;
        public ViewModel()
        {
            this.currentCustomer = 0;
            this.customers = new List<Customer>
            {
                new Customer
                {
                    CustomerID = 1,
                    Title = "Mr",
                    FirstName = "John",
                    LastName = "Sharp",
                    EmailAddress = "[email protected]",
                    Phone = "111-1111"
                },
                new Customer
                {
                    CustomerID = 2,
                    Title = "Mrs",
                    FirstName = "Diana",
                    LastName = "Sharp",
                    EmailAddress = "[email protected]",
                    Phone = "111-1112"
                },
                new Customer
                {
                    CustomerID = 3,
                    Title = "Ms",
                    FirstName = "Francesca",
                    LastName = "Sharp",
                    EmailAddress = "[email protected]",
                    Phone = "111-1113"
                }
            };
        }
        public Customer Current
        {
            get { return this.customers.Count > 0 ? this.customers[currentCustomer] : null; }
        }
    }
}
  1. 稍微修改MainPage.xaml.cs中的代碼:
public MainPage()
        {
            this.InitializeComponent();

            List<string> titles = new List<string> { "Mr", "Mrs", "Ms", "Miss" };
            this.title.ItemsSource = titles;
            this.ctitle.ItemsSource = titles;

            ViewModel viewModel = new ViewModel();
            this.DataContext = viewModel;
        }
  1. 修改所有TextBox空間的XAML標記:<TextBox Grid.Row="0" Grid.Column="1" x:Name="cid" Text="{Binding Current.CustomerID,Mode=TwoWay}" .../>

運行效果沒有變化。

26.1.5 向ViewModel添加命令

ViewModel所公開的命令必須實現ICommand接口,控件的操作才能和命令綁定。該接口定義了以下方法和事件:

  • CanExecute
  • Execute
  • CanExecuteChanged

過程稍微有些繁瑣,這裏直接把代碼放上來了。

  1. 新建一個公共類,命名爲Command.cs,代碼如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Windows.UI.Xaml;
namespace C_25_2_Customers
{
    public class Command:ICommand
    {
        private Action methodToExecute = null;
        private Func<bool> methodToDetectCanExecute = null;
        private DispatcherTimer canExecuteChangedEventTimer = null;
        public Command(Action methodToExecute, Func<bool> methodToDetectCanExecute)
        {
            this.methodToExecute = methodToExecute;
            this.methodToDetectCanExecute = methodToDetectCanExecute;

            this.canExecuteChangedEventTimer = new DispatcherTimer();
            this.canExecuteChangedEventTimer.Tick += canExecuteChangedEventTimer_Tick;
            this.canExecuteChangedEventTimer.Interval = new TimeSpan(0, 0, 1);
            this.canExecuteChangedEventTimer.Start();
        }

        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            if (this.methodToDetectCanExecute == null)
            {
                return true;
            }
            else
            {
                return this.methodToDetectCanExecute();
            }
        }

        public void Execute(object parameter)
        {
            this.methodToExecute();
        }
        void canExecuteChangedEventTimer_Tick(object sender,object e)
        {
            if (this.CanExecuteChanged != null)
            {
                this.CanExecuteChanged(this,EventArgs.Empty);
            }
        }
    }
}
  1. 修改ViewModel.cs中的代碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;

namespace C_25_2_Customers
{
    public class ViewModel:INotifyPropertyChanged
    {
        private List<Customer> customers;
        private int currentCustomer;
        public Command NextCustomer { get; set; }
        public Command PreviousCustomer { get; set; }

        public ViewModel()
        {
            this.currentCustomer = 0;
            this.IsAtEnd = false;
            this.IsAtStart = true;
            this.NextCustomer = new Command(this.Next, () => { return this.customers.Count > 0 && !this.IsAtEnd; }) ;
            this.PreviousCustomer = new Command(this.Previous, () => { return customers.Count > 0 && !this.IsAtStart; });
            this.customers = new List<Customer>
            {
                new Customer
                {
                    CustomerID = 1,
                    Title = "Mr",
                    FirstName = "John",
                    LastName = "Sharp",
                    EmailAddress = "[email protected]",
                    Phone = "111-1111"
                },
                new Customer
                {
                    CustomerID = 2,
                    Title = "Mrs",
                    FirstName = "Diana",
                    LastName = "Sharp",
                    EmailAddress = "[email protected]",
                    Phone = "111-1112"
                },
                new Customer
                {
                    CustomerID = 3,
                    Title = "Ms",
                    FirstName = "Francesca",
                    LastName = "Sharp",
                    EmailAddress = "[email protected]",
                    Phone = "111-1113"
                }
            };
        }
        private bool _isAtStart;
        public bool IsAtStart
        {
            get { return this._isAtStart; }
            set { this._isAtStart = value;this.onPropertyChanged("IsAtStart"); }
        }
        private bool _isAtEnd;
        public bool IsAtEnd
        {
            get { return this._isAtEnd; }
            set { this._isAtEnd = value;this.onPropertyChanged("IsAtEnd"); }
        }
        public Customer Current
        {
            get { return this.customers.Count > 0 ? this.customers[currentCustomer] : null; }
        }
        public void Next()
        {
            if (this.customers.Count - 1 > this.currentCustomer)
            {
                this.currentCustomer++;
                this.onPropertyChanged(nameof(Current));
                this.IsAtStart = false;
                this.IsAtEnd = (this.customers.Count - 1 == this.currentCustomer);
            }
        }
        public void Previous()
        {
            if (this.currentCustomer > 0)
            {
                this.currentCustomer--;
                this.onPropertyChanged(nameof(Current));
                this.IsAtEnd = false;
                this.IsAtStart = (this.currentCustomer == 0);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void onPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
  1. 在XAML標記中的底部的</Page>前添加如下標記:
   ...;
	<Page.TopAppBar>
        <CommandBar>
            <AppBarButton x:Name="previousCustomer" Icon="Previous" Label="Previous" Command="{Binding Path=PreviousCustomer}"/>
            <AppBarButton x:Name="NextCustomer" Icon="Next" Label="Next" Command="{Binding Path=NextCustomer}"/>
        </CommandBar>
    </Page.TopAppBar>
</Page>

運行結果如下:
在這裏插入圖片描述

26.2 用Cortana 搜索數據

pass;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章