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;

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