聊聊 Wpf 數(shù)據(jù)綁定實(shí)例
前言:
數(shù)據(jù)綁定的基本步驟:
(1)先聲明一個(gè)類(lèi)及其屬性
(2)初始化類(lèi)賦值
(3)在C#代碼中把控件DataContext=對(duì)象;
(4)在界面設(shè)計(jì)里,控件給要綁定的屬性{Binding 綁定類(lèi)的屬性}
原理:監(jiān)聽(tīng)事件機(jī)制,界面改變有TextChanged之類(lèi)的事件,所以改變界面可以同步修改到對(duì)象
想讓普通對(duì)象實(shí)現(xiàn)數(shù)據(jù)綁定,需要實(shí)現(xiàn)INotifyPropertyChanged接口才能監(jiān)聽(tīng)ProperChanged。具體代碼如下顯示:
- class Person:INotifyPropertyChanged
- {
- private int age;
- public int Age
- {
- get
- {
- return age;
- }
- set
- {
- this.age = value;
- if (PropertyChanged != null)
- {
- PropertyChanged(this,
- new PropertyChangedEventArgs("Age"));
- }
- }
- }
- }
BindingMode枚舉值
名稱(chēng) | 說(shuō)明 |
---|---|
OneWay | 當(dāng)源屬性變化時(shí)更新目標(biāo)屬性 |
TwoWay | 當(dāng)源屬性變化時(shí)更新目標(biāo)屬性,當(dāng)目標(biāo)屬性變化時(shí)更新源屬性 |
OneTime | 最初根據(jù)源屬性設(shè)置目標(biāo)屬性,其后的改變會(huì)忽略。 |
OneWayToSource | 與OneWay類(lèi)型相似,但方向相反。 |
Default | 此類(lèi)綁定依賴(lài)于目標(biāo)屬性 |
UpdateSourceTrigger
名稱(chēng) | 說(shuō)明 |
---|---|
Default | 默認(rèn)值,與依賴(lài)屬性有關(guān) |
Explicit | 必須在顯示地調(diào)用BindingExpression.UpdateSource的情況下才更新源。 |
LostFocus | 控件失去焦點(diǎn)的時(shí)候更新源值 |
PropertyChanged | 綁定的目標(biāo)值改變時(shí)更新。 |
實(shí)例運(yùn)行后界面如下:
MainWindow.xaml
- <Window x:Class="WpfApp1.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:WpfApp1"
- mc:Ignorable="d"
- Title="MainWindow" Height="600" Width="800">
- <StackPanel>
- <TextBlock Text="Student ID:" FontWeight="Bold" Margin="5"/>
- <TextBox Name="textBoxId" Margin="5" Text="{Binding Id,Mode=TwoWay}"/>
- <TextBlock Text="Student Name:" FontWeight="Bold" Margin="5"/>
- <TextBox Name="textBoxName" Margin="5" Text="{Binding Name,Mode=TwoWay}"/>
- <TextBlock Text="Student List:" FontWeight="Bold" Margin="5"/>
- <ListBox Name="listBox1" Height="110" Margin="5" >
- <ListBox.ItemTemplate>
- <DataTemplate>
- <StackPanel Orientation="Horizontal">
- <TextBlock Text="{Binding Path=Id}" Width="30"/>
- <TextBlock Text="{Binding Path=Name}" Width="60"/>
- <TextBlock Text="{Binding Path=Age}" Width="30"/>
- </StackPanel>
- </DataTemplate>
- </ListBox.ItemTemplate>
- </ListBox>
- <ListBox Name="listBox2" Height="80" ItemsSource="{Binding Student}" DisplayMemberPath="Id" Margin="5"/>
- <Slider Name="slider1" MinHeight="25" Value="{Binding Id}"/>
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition Height="*"></RowDefinition>
- </Grid.RowDefinitions>
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="*"/>
- <ColumnDefinition Width="*"/>
- </Grid.ColumnDefinitions>
- <Button Grid.Column="0" Content="Action" FontSize="40" Name="btnCtrl1" Height="80" Margin="5" Click="BtnCtrl1_Click"/>
- <Button Grid.Column="1" Content="Action" FontSize="40" Name="btnCtrl2" Height="80" Margin="5" Click="BtnCtrl2_Click"/>
- </Grid>
- </StackPanel>
- </Window>
首先解釋下C#中的Task.Delay()和Thread.Sleep()
- Thread.Sleep()是同步延遲,Task.Delay()是異步延遲。
- Thread.Sleep()會(huì)阻塞線(xiàn)程,Task.Delay()不會(huì)。
- Thread.Sleep()不能取消,Task.Delay()可以。
- Task.Delay()實(shí)質(zhì)創(chuàng)建一個(gè)運(yùn)行給定時(shí)間的任務(wù),Thread.Sleep()使當(dāng)前線(xiàn)程休眠給定時(shí)間。
- 反編譯Task.Delay(),基本上講它就是個(gè)包裹在任務(wù)中的定時(shí)器。
- Task.Delay()和Thread.Sleep()最大的區(qū)別是Task.Delay()旨在異步運(yùn)行,在同步代碼中使用Task.Delay()是沒(méi)有意義的;在異步代碼中使用Thread.Sleep()是一個(gè)非常糟糕的主意。通常使用await關(guān)鍵字調(diào)用Task.Delay()。
- 我的理解:Task.Delay(),async/await和CancellationTokenSource組合起來(lái)使用可以實(shí)現(xiàn)可控制的異步延遲。
MainWindow.xaml.cs
- using System;
- using System.Collections.ObjectModel;
- using System.ComponentModel;
- using System.Threading.Tasks;
- using System.Windows;
- namespace WpfApp1
- {
- /// <summary>
- /// MainWindow.xaml 的交互邏輯
- /// </summary>
- public partial class MainWindow : Window
- {
- public ObservableCollection<Student> stuList;
- public MainWindow()
- {
- InitializeComponent();
- this.DataContext = new Student() { Name="111", Id =1 };
- Task.Run(async() => //開(kāi)啟異步線(xiàn)程task
- {
- await Task.Delay(3000); //延時(shí)3秒
- Dispatcher.Invoke((Action)delegate //線(xiàn)程中主界面顯示需要用委托,不然這次賦值,在界面不更新
- {
- this.DataContext = new Student() { Name = "222", Id = 2 };
- });
- });
- this.DataContext = new Student() { Name = "333" , Id = 3 };
- }
- private void BtnCtrl1_Click(object sender, RoutedEventArgs e)
- {
- Student stu = new Student() { Id = 4, Name = "Jon", Age = 29 }; //實(shí)例化一個(gè)Student類(lèi) 并給類(lèi)成員賦值
- this.DataContext = stu;//將實(shí)例化得對(duì)象傳給DataContext
- }
- private void BtnCtrl2_Click(object sender, RoutedEventArgs e)
- {
- ObservableCollection<Student> stuList = new ObservableCollection<Student>() //具有通知屬性的list
- {
- new Student() { Id=5, Name="Tim", Age=29 },
- new Student() { Id=6, Name="Tom", Age=28 },
- };
- this.listBox1.ItemsSource = stuList;
- this.listBox2.ItemsSource = stuList;
- this.listBox2.DisplayMemberPath = "Name";
- this.DataContext = stuList;
- }
- }
- public class Student : INotifyPropertyChanged //創(chuàng)建一個(gè)繼承自INotifyPropertyChanged的類(lèi)Student
- {
- private string name;
- public string Name
- {
- get { return name; }
- set
- {
- name = value;
- if (this.PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs("Name")); //給Name綁定屬性變更通知事件
- }
- }
- }
- private int id;
- public int Id
- {
- get { return id; }
- set
- {
- id = value;
- if (this.PropertyChanged != null)
- {
- this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Id"));//給Id綁定屬性變更通知事件
- }
- }
- }
- private int age;
- public int Age
- {
- get { return age; }
- set
- {
- age = value;
- if (this.PropertyChanged != null)
- {
- this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Age"));//給Age綁定屬性變更通知事件
- }
- }
- }
- public int ID { get; internal set; }
- public event PropertyChangedEventHandler PropertyChanged;
- }
- }
本文轉(zhuǎn)載自微信公眾號(hào)「CSharp編程大全」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系CSharp編程大全公眾號(hào)。