从这一篇往前看,其实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 WpfApplication1017 {18 /// <summary>19 /// MainWindow.xaml 的交互逻辑20 /// </summary>21 public partial class MainWindow : Window22 {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 ListViewDemo19 {20 /// <summary>21 /// MainWindow.xaml 的交互逻辑22 /// </summary>23 public partial class MainWindow : Window24 {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 : INotifyPropertyChanged47 {48 public string name;49 50 public string Name51 {52 get53 {54 return name;55 }56 set57 {58 name = value;59 NotifyPropertyChange("Name");60 }61 }62 63 public int age;64 65 public int Age66 {67 get68 {69 return age;70 }71 set72 {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 WpfApplication1216 {17 /// <summary>18 /// MainWindow.xaml 的交互逻辑19 /// </summary>20 public partial class MainWindow : Window21 {22 public MainWindow()23 {24 InitializeComponent();25 }26 }27 28 public class CustomTextBlock : TextBlock29 {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 Time39 {40 get41 {42 //获取当前属性值 43 return (DateTime)GetValue(TimeProperty);44 }45 set46 {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>
最后感谢一直关注此系列的朋友,希望你们有一丝收获。