從這一篇往前看,其實wpf中還有很多東西沒有講到,不過我的原則還是將比較常用的知識點過一遍,如果大家熟悉了這些知識,基本功
也就打的差不多了,后續可以等待老鄧的wpf細說系列,這里我先頂老鄧一下。
一:用戶控件(UserControl)
對於用戶控件的認識,我想大家還是很熟悉的,因為這玩意我們在webform或者在mvc中用的可多了,我們看看wpf中怎么使用,首先
我們要知道"用戶控件“繼承自UserControl,而UserControl繼承自ContentControl,也就是上上一篇說的”內容控件”。
第一步:在vs中的添加項中找到一個“用戶控件WPF”,點擊添加即可。
第二步:我們發現其實UserControl和Window是一個層次上的,都有xaml和cs文件,然后我們在xaml中拖幾個控件。
1 <UserControl x:Class="WpfApplication8.AddProduct" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 mc:Ignorable="d" 7 d:DesignHeight="200" d:DesignWidth="300"> 8 <Grid Height="171" Width="262"> 9 <TextBlock Height="20" HorizontalAlignment="Left" Margin="28,57,0,0" Name="textBlock1" Text="名稱:" VerticalAlignment="Top" Width="42" /> 10 <TextBlock Height="20" HorizontalAlignment="Left" Margin="28,92,0,0" Name="textBlock2" Text="價格:" VerticalAlignment="Top" Width="42" /> 11 <TextBox Height="23" HorizontalAlignment="Left" Margin="76,54,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" /> 12 <TextBox Height="23" HorizontalAlignment="Left" Margin="76,92,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" /> 13 </Grid> 14 </UserControl>
第三步:我們在MainWindow中引用,跟webform中使用套路一模一樣,最后也就ok了。
1 <Window x:Class="WpfApplication8.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:local="clr-namespace:WpfApplication8" 5 Title="MainWindow" Height="350" Width="525"> 6 <Grid> 7 <local:AddProduct x:Name="test"/> 8 </Grid> 9 </Window>
二:資源文件
先前文章我也說過,資源就類似於webform中的css,但是實際應用中,css都是一個個單獨的文件來實現內容與樣式的分離,當然
wpf中也主張這么做。
第一步:vs中新建項 -> 資源字典->點擊確定
第二步:這里我就將默認生成的Dictionary1.xaml放在解決方案的Style文件夾下,然后我們寫上一段簡單的style。
1 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 2 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 3 <Style x:Key="backColor" TargetType="{x:Type Button}"> 4 <Setter Property="Background" Value="Red"/> 5 </Style> 6 </ResourceDictionary>
第三步:在Resources上引用,指定資源文件路徑,跟webform中的css文件引用一樣一樣的。
1 <Window x:Class="WpfApplication9.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 Title="MainWindow" Height="350" Width="525"> 5 <Window.Resources> 6 <!-- 引用外部資源文件 --> 7 <ResourceDictionary> 8 <ResourceDictionary.MergedDictionaries> 9 <ResourceDictionary Source="/Style/Dictionary1.xaml"/> 10 </ResourceDictionary.MergedDictionaries> 11 </ResourceDictionary> 12 </Window.Resources> 13 <Grid> 14 <Button Content="Button" Style="{StaticResource ResourceKey=backColor}" Height="23" HorizontalAlignment="Left" Margin="104,58,0,0" Name="button1" VerticalAlignment="Top" Width="75" /> 15 </Grid> 16 </Window>
三:了解wpf中Window的生命周期
了解生命周期,可以讓我們更好的控制生命周期內各個階段發生的行為,具體怎么靈活運用,得要看大家靈活發揮了。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Windows; 6 using System.Windows.Controls; 7 using System.Windows.Data; 8 using System.Windows.Documents; 9 using System.Windows.Input; 10 using System.Windows.Media; 11 using System.Windows.Media.Imaging; 12 using System.Windows.Navigation; 13 using System.Windows.Shapes; 14 using System.Diagnostics; 15 16 namespace WpfApplication10 17 { 18 /// <summary> 19 /// MainWindow.xaml 的交互邏輯 20 /// </summary> 21 public partial class MainWindow : Window 22 { 23 public MainWindow() 24 { 25 InitializeComponent(); 26 27 //初始化 28 this.Initialized += (sender, e) => 29 { 30 Debug.WriteLine("窗體初始化完成 Initialized"); 31 }; 32 33 //激活 34 this.Activated += (sender, e) => 35 { 36 Debug.WriteLine("窗體被激活 Activated"); 37 }; 38 39 //加載 40 this.Loaded += (sender, e) => 41 { 42 Debug.WriteLine("窗體加載完成 Loaded"); 43 }; 44 45 //呈現內容 46 this.ContentRendered += (sender, e) => 47 { 48 Debug.WriteLine("呈現內容 ContentRendered"); 49 }; 50 51 //失活 52 this.Deactivated += (sender, e) => 53 { 54 Debug.WriteLine("窗體被失活 Deactivated"); 55 }; 56 57 //窗體獲取輸入焦點 58 this.GotFocus += (sender, e) => 59 { 60 Debug.WriteLine("窗體獲取輸入焦點 GotFocus"); 61 }; 62 63 //窗體失去輸入焦點 64 this.LostFocus += (sender, e) => 65 { 66 Debug.WriteLine("窗體失去輸入焦點 LostFocus"); 67 }; 68 69 //鍵盤獲取輸入焦點 70 this.GotKeyboardFocus += (sender, e) => 71 { 72 Debug.WriteLine("鍵盤獲取輸入焦點 GotKeyboardFocus"); 73 }; 74 75 //鍵盤失去輸入焦點 76 this.LostKeyboardFocus += (sender, e) => 77 { 78 Debug.WriteLine("鍵盤失去輸入焦點 LostKeyboardFocus"); 79 }; 80 81 //正在關閉 82 this.Closing += (sender, e) => 83 { 84 Debug.WriteLine("窗體正在關閉 Closeing"); 85 }; 86 87 //關閉 88 this.Closed += (sender, e) => 89 { 90 Debug.WriteLine("窗體正在關閉 Closed"); 91 }; 92 93 } 94 } 95 }
從窗體的開啟到關閉,我們可以在“輸出窗口”中看到如下的事件發生順序流。
四:屬性更改通知(INotifyPropertyChanged)
我們在開發webform中,如果刪除GridView里面的一行,我們的作法肯定就是在數據庫中刪除掉選定的記錄然后重新綁定GridView控件
來實現我們的需求,注意,這里有“重新綁定”一詞,但是在wpf中有一個突破,前一篇文章我也提到過wpf中的ObservableCollection<T>,
MSDN中說,在添加項,移除項時此集合通知控件,我們知道對一個集合的操作是CURD,但是恰恰沒有Update的時候提供集合通知,也就
是說當我Update的時候,雖然"集合內容“已被修改,但是"控件“卻沒有實現同步更新,怎么辦呢?INotifyPropertyChanged提供了解決方案。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Windows; 6 using System.Windows.Controls; 7 using System.Windows.Data; 8 using System.Windows.Documents; 9 using System.Windows.Input; 10 using System.Windows.Media; 11 using System.Windows.Media.Imaging; 12 using System.Windows.Navigation; 13 using System.Windows.Shapes; 14 using System.Collections.ObjectModel; 15 using System.Windows.Controls.Primitives; 16 using System.ComponentModel; 17 18 namespace ListViewDemo 19 { 20 /// <summary> 21 /// MainWindow.xaml 的交互邏輯 22 /// </summary> 23 public partial class MainWindow : Window 24 { 25 private ObservableCollection<Person> personList = new ObservableCollection<Person>(); 26 27 public MainWindow() 28 { 29 InitializeComponent(); 30 31 personList.Add(new Person() { Name = "一線碼農", Age = 24 }); 32 33 personList.Add(new Person() { Name = "XXX", Age = 21 }); 34 35 listview1.ItemsSource = personList; 36 } 37 38 private void Button_Click(object sender, RoutedEventArgs e) 39 { 40 var first = personList.FirstOrDefault(); 41 42 first.Name = textBox1.Text; 43 } 44 } 45 46 public class Person : INotifyPropertyChanged 47 { 48 public string name; 49 50 public string Name 51 { 52 get 53 { 54 return name; 55 } 56 set 57 { 58 name = value; 59 NotifyPropertyChange("Name"); 60 } 61 } 62 63 public int age; 64 65 public int Age 66 { 67 get 68 { 69 return age; 70 } 71 set 72 { 73 age = value; 74 NotifyPropertyChange("Age"); 75 } 76 } 77 78 public event PropertyChangedEventHandler PropertyChanged; 79 80 private void NotifyPropertyChange(string propertyName) 81 { 82 if (PropertyChanged != null) 83 PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 84 } 85 } 86 }
1 <Window x:Class="ListViewDemo.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 Title="MainWindow" Height="350" Width="525"> 5 <Grid> 6 <ListView x:Name="listview1"> 7 <ListView.View> 8 <GridView> 9 <GridViewColumn Header="姓名" DisplayMemberBinding="{Binding Path=Name}"/> 10 <GridViewColumn Header="年齡" DisplayMemberBinding="{Binding Path=Age}"/> 11 </GridView> 12 </ListView.View> 13 </ListView> 14 <Button Content="更改名字" Click="Button_Click" Margin="315,174,35,103" /> 15 <TextBox Height="23" HorizontalAlignment="Left" Margin="162,180,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" /> 16 </Grid> 17 </Window>
我們只要輸入名字,然后點擊”button按鈕”,最后ListView同步更新了,是不是很神奇的說。
五:依賴屬性
依賴屬性是wpf中獨有的一種屬性,前面文章中或許我們發現WPF的類定義中滿是這些玩意,比如我們看一個TextBlock。
這些Property為后綴的都是叫做依賴屬性,不過依賴屬性這些東西深究起來內容還是比較多的,不過我還是講究應用方面,有時候我們
可能有這樣的需求,就是希望能在TextBlock上顯示當前時間,這時我們就可以擴展TextBlock,在其中增加一個TimeProperty的依賴
屬性來顯示當前時間。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Windows; 6 using System.Windows.Controls; 7 using System.Windows.Data; 8 using System.Windows.Documents; 9 using System.Windows.Input; 10 using System.Windows.Media; 11 using System.Windows.Media.Imaging; 12 using System.Windows.Navigation; 13 using System.Windows.Shapes; 14 15 namespace WpfApplication12 16 { 17 /// <summary> 18 /// MainWindow.xaml 的交互邏輯 19 /// </summary> 20 public partial class MainWindow : Window 21 { 22 public MainWindow() 23 { 24 InitializeComponent(); 25 } 26 } 27 28 public class CustomTextBlock : TextBlock 29 { 30 //自定義一個依賴項屬性 31 public static DependencyProperty TimeProperty = DependencyProperty.Register("Timer", typeof(DateTime), 32 typeof(CustomTextBlock), 33 new PropertyMetadata(DateTime.Now, OnTimerPropertyChanged), 34 ValidateTimeValue); 35 /// <summary> 36 /// 對依賴屬性進行設置值 37 /// </summary> 38 public DateTime Time 39 { 40 get 41 { 42 //獲取當前屬性值 43 return (DateTime)GetValue(TimeProperty); 44 } 45 set 46 { 47 //給當前的屬性賦值 48 SetValue(TimeProperty, value); 49 } 50 } 51 52 53 static void OnTimerPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) 54 { 55 56 } 57 58 static bool ValidateTimeValue(object obj) 59 { 60 DateTime dt = (DateTime)obj; 61 62 if (dt.Year > 1990 && dt.Year < 2200) 63 return true; 64 return false; 65 } 66 67 } 68 }
1 <Window x:Class="WpfApplication12.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:local="clr-namespace:WpfApplication12" 5 Title="MainWindow" Height="350" Width="525"> 6 <Grid> 7 <local:CustomTextBlock Text="{Binding RelativeSource={RelativeSource Self}, Path=Timer}"/> 8 </Grid> 9 </Window>
最后感謝一直關注此系列的朋友,希望你們有一絲收獲。