利刃 MVVMLight 4:绑定和绑定的各种使用场景
一、绑定:
主要包含元素绑定和非元素绑定两种。
1、元素绑定,是绑定的最简单形式,源对象是WPF的元素,并且源对象的属性是依赖项属性。
根据我们之前的知识 ,依赖项属性具有内置的更改通知支持。所以当我们的源对象中改变依赖项属性的值时,会立即更新目标对象中的绑定属性。
以上篇的例子来重写,我们不用额外定义全局公开的属性来支持数据的显示。
如下:
1 <StackPanel Orientation="Vertical" HorizontalAlignment="Left" > 2 <TextBox x:Name="WelcomeText" Width="200" Margin="10,10,0,0"></TextBox> 3 <TextBlock Text="{Binding ElementName=WelcomeText,Path=Text,StringFormat='Hello \{0\}'}" Margin="10,10,0,0"></TextBlock> 4 </StackPanel>
TextBlock 绑定了名称为WelcomeText的元素,并且将Path指向Text属性,所以他的值会跟着 WelcomeText的变化而变化。
2、非元素类型绑定:
2.1 Source属性:绑定具体的数据对象:如系统信息跟我们定义的资源数据。
定义Window下的全局资源
1 <Window.Resources> 2 <SolidColorBrush x:Key="BorderBrush">Red</SolidColorBrush> 3 </Window.Resources>
应用到视图中
1 <StackPanel Margin="10,50,0,0" Orientation="Vertical" > 2 <TextBlock Text="{Binding Source={x:Static SystemFonts.IconFontFamily},Path=Source}" ></TextBlock> 3 <TextBlock Text="{Binding Source={StaticResource BorderBrush}}" Foreground="{Binding Source={StaticResource BorderBrush}}" ></TextBlock> 4 </StackPanel>
结果:
2.2 RelativeSource 属性:设置该属性 可以根据当前目标对象的相对关系指向源目标。比如获取当前对象的父亲对象、兄弟对象或者自身的其他属性等一些数据。
1 <StackPanel Margin="10,50,0,0" Orientation="Vertical" ToolTip="top" > 2 3 <StackPanel Orientation="Horizontal" > 4 <TextBlock Width="150" Text="获取自身宽度:" ></TextBlock> 5 <TextBlock Width="200" Text="{Binding Path=Width,RelativeSource={RelativeSource Mode=Self}}" ></TextBlock> 6 </StackPanel> 7 8 9 <StackPanel Orientation="Horizontal" ToolTip="parent" > 10 <TextBlock Width="150" Text="查找上一层ToolTip:" ></TextBlock> 11 <TextBlock Text="{Binding Path=ToolTip,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type StackPanel}}}"></TextBlock> 12 </StackPanel> 13 14 15 <StackPanel Orientation="Horizontal"> 16 <TextBlock Width="150" Text="查找上二层ToolTip:" ></TextBlock> 17 <TextBlock Text="{Binding Path=ToolTip,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type StackPanel},AncestorLevel=2}}"></TextBlock> 18 </StackPanel> 19 20 </StackPanel>
代码很容易理解,这边在创建RelativeSource的时候,mode模式有四种类型:
Mode成员名称 | 说明 | |
---|---|---|
FindAncestor |
引用数据绑定元素的父链中的上级。 这可用于绑定到特定类型的上级或其子类。 若要指定 AncestorType 和/或 AncestorLevel,这就是应使用的模式。 |
|
PreviousData |
允许在当前显示的数据项列表中绑定上一个数据项(不是包含数据项的控件)。 |
|
Self |
引用正在其上设置绑定的元素,并允许你将该元素的一个属性绑定到同一元素的其他属性上。 |
|
TemplatedParent |
引用应用了模板的元素,其中此模板中存在数据绑定元素。 这类似于设置 TemplateBindingExtension,且仅在 Binding 位于模板内部时适用。 |
注意:AncestorType 指得是查找的对象类型,AncestorLevel 代表搜索的层级的位置,如果是3,则忽略前两个发现的元素。
结果:
2.3 DataContext 属性:如果想将一个对象绑定到一个由多个元素组成的视图块或者复合元素中,用DataContext 会更好开发和维护。如下
1 <StackPanel Orientation="Vertical" DataContext="UInfo" > 2 3 <StackPanel Orientation="Horizontal" > 4 <TextBlock Text="名称:" Width="100" ></TextBlock> 5 <TextBox Text="{Binding Name}" Width="100" ></TextBox> 6 </StackPanel> 7 8 <StackPanel Orientation="Horizontal"> 9 <TextBlock Text="性别:" Width="100" ></TextBlock> 10 <TextBox Text="{Binding Sex}" Width="100" ></TextBox> 11 </StackPanel> 12 13 </StackPanel>
二、绑定的各种使用场景:
1、下拉框:
View代码:
1 <StackPanel Margin="10,20,0,50"> 2 <TextBlock Text="下拉框" FontWeight="Bold" FontSize="12" Margin="0,5,0,5" ></TextBlock> 3 <DockPanel x:Name="Combbox" > 4 <StackPanel DockPanel.Dock="Left" Width="240"> 5 <ComboBox Width="200" HorizontalAlignment="Left" ItemsSource="{Binding CombboxList}" SelectedItem="{Binding CombboxItem}" DisplayMemberPath="Text" SelectedValuePath="Key" ></ComboBox> 6 </StackPanel> 7 8 <StackPanel DockPanel.Dock="Right" Width="240" Orientation="Horizontal" DataContext="{Binding CombboxItem}" > 9 <TextBlock Text="{Binding Key,StringFormat='结果:\{0\}'}" Margin="0,0,15,0" ></TextBlock> 10 <TextBlock Text="{Binding Text}"></TextBlock> 11 </StackPanel> 12 13 </DockPanel> 14 </StackPanel>
Model代码:
1 public class ComplexInfoModel:ObservableObject 2 { 3 private String key; 4 /// <summary> 5 /// Key值 6 /// </summary> 7 public String Key 8 { 9 get { return key; } 10 set { key = value; RaisePropertyChanged(()=>Key); } 11 } 12 13 private String text; 14 /// <summary> 15 /// Text值 16 /// </summary> 17 public String Text 18 { 19 get { return text; } 20 set { text = value; RaisePropertyChanged(()=>Text); } 21 } 22 }
ViewModel代码:
1 #region 下拉框相关 2 private ComplexInfoModel combboxItem; 3 /// <summary> 4 /// 下拉框选中信息 5 /// </summary> 6 public ComplexInfoModel CombboxItem 7 { 8 get { return combboxItem; } 9 set { combboxItem = value; RaisePropertyChanged(() => CombboxItem); } 10 } 11 12 13 private List<ComplexInfoModel> combboxList; 14 /// <summary> 15 /// 下拉框列表 16 /// </summary> 17 public List<ComplexInfoModel> CombboxList 18 { 19 get { return combboxList; } 20 set { combboxList = value; RaisePropertyChanged(()=>CombboxList); } 21 } 22 #endregion
说明:CombboxItem是一个全局的属性,作用在当前页面的数据上下文中,结果显示的内容指向下拉框中的选中值,达到共用一个数据的目的。
结果:
2、单选框
1 <StackPanel Margin="10,0,0,50"> 2 <TextBlock Text="单选框" FontWeight="Bold" FontSize="12" Margin="0,5,0,5" ></TextBlock> 3 <DockPanel x:Name="RadioButton" > 4 <StackPanel DockPanel.Dock="Left" Width="240"> 5 <RadioButton Content="{Binding SingleRadio}" IsChecked="{Binding IsSingleRadioCheck}" HorizontalAlignment="Right" Width="240" > 6 </RadioButton> 7 </StackPanel> 8 <StackPanel DockPanel.Dock="Right" Width="240" Orientation="Horizontal"> 9 <TextBlock Text="{Binding IsSingleRadioCheck,StringFormat='结果:\{0\}'}" ></TextBlock> 10 </StackPanel> 11 </DockPanel> 12 </StackPanel>
说明:注意这边使用到了两个属性: SingleRadio,IsSingleRadioCheck,一个用于显示单选框内容,一个用于表示是否选中
结果:
3、组合单选框
1 <StackPanel Margin="10,0,0,50"> 2 <TextBlock Text="组合单选框" FontWeight="Bold" FontSize="12" Margin="0,5,0,5"></TextBlock> 3 <DockPanel x:Name="GroupRadioButton" > 4 <StackPanel DockPanel.Dock="Left" Width="240"> 5 <ItemsControl ItemsSource="{Binding RadioButtons}"> 6 <ItemsControl.ItemTemplate> 7 <DataTemplate> 8 <RadioButton Content="{Binding Content}" IsChecked="{Binding IsCheck}" GroupName="RadioButtons" 9 Command="{Binding DataContext.RadioCheckCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ItemsControl}}"> 10 </RadioButton> 11 </DataTemplate> 12 </ItemsControl.ItemTemplate> 13 </ItemsControl> 14 </StackPanel> 15 16 <StackPanel DockPanel.Dock="Right" Width="240" Orientation="Horizontal"> 17 <TextBlock Text="{Binding RadioButton.Content,StringFormat='结果:\{0\}'}" ></TextBlock> 18 </StackPanel> 19 </DockPanel> 20 </StackPanel>
这边使用了ItemsControl,可以根据模板来定义内容,我们在模板中放置我们需要用到的内容。这边需要注意的是:GroupName用一样的,来代表这是一个单选控件组合。
结果:
4、复选框,复选框与单选框的使用情况类似:
1 <StackPanel Margin="10,0,0,50"> 2 <TextBlock Text="复合框" FontWeight="Bold" FontSize="12" Margin="0,5,0,5" ></TextBlock> 3 <DockPanel x:Name="GroupCheckButton" > 4 <StackPanel DockPanel.Dock="Left" Width="240"> 5 <ItemsControl ItemsSource="{Binding CheckButtons}" x:Name="cbt" > 6 <ItemsControl.ItemTemplate> 7 <DataTemplate> 8 <CheckBox Content="{Binding Content}" IsChecked="{Binding IsCheck}" 9 Command="{Binding DataContext.CheckCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ItemsControl}}"/> 10 </DataTemplate> 11 </ItemsControl.ItemTemplate> 12 </ItemsControl> 13 </StackPanel> 14 15 <StackPanel DockPanel.Dock="Right" Width="240" Orientation="Horizontal"> 16 <TextBlock Text="{Binding CheckInfo,StringFormat='结果:\{0\}'}" ></TextBlock> 17 </StackPanel> 18 </DockPanel> 19 </StackPanel>
结果:
5、树形控件
View代码:
1 <StackPanel Margin="10,0,0,50"> 2 <TextBlock Text="树" FontWeight="Bold" FontSize="12" Margin="0,5,0,5" ></TextBlock> 3 <DockPanel x:Name="TreeButton" > 4 <StackPanel DockPanel.Dock="Left" Width="240"> 5 <TreeView ItemsSource="{Binding TreeInfo}" x:Name="tree" BorderThickness="0"> 6 <TreeView.ItemTemplate> 7 <HierarchicalDataTemplate ItemsSource="{Binding Children}"> 8 <TextBlock Text="{Binding NodeName}"/> 9 </HierarchicalDataTemplate> 10 </TreeView.ItemTemplate> 11 </TreeView> 12 </StackPanel> 13 14 <StackPanel DockPanel.Dock="Right" Width="240" Orientation="Horizontal" DataContext="{Binding SelectedItem,ElementName=tree}"> 15 <TextBlock Text="结果:"/> 16 <TextBlock Text="{Binding NodeID,StringFormat='NodeID:\{0\}'}" Margin="0,0,20,0" /> 17 <TextBlock Text="{Binding NodeName,StringFormat='NodeName:\{0\}'}"/> 18 </StackPanel> 19 </DockPanel> 20 </StackPanel>
Model代码
1 public class TreeNodeModel : ObservableObject 2 { 3 public string NodeID { get; set; } 4 public string NodeName { get; set; } 5 public List<TreeNodeModel> Children { get; set; } 6 }
ViewModel代码
1 #region 树控件 2 3 private List<TreeNodeModel> treeInfo; 4 /// <summary> 5 /// 树控件数据信息 6 /// </summary> 7 public List<TreeNodeModel> TreeInfo 8 { 9 get { return treeInfo; } 10 set { treeInfo = value; RaisePropertyChanged(()=>TreeInfo); } 11 } 12 13 14 #endregion
结果:
6、ListBox
1 <StackPanel Margin="10,0,0,50" Orientation="Vertical" > 2 <TextBlock Text="ListBox模板" FontWeight="Bold" FontSize="12" Margin="0,5,0,5" ></TextBlock> 3 <DockPanel > 4 <StackPanel HorizontalAlignment="Left" DockPanel.Dock="Left" > 5 <ListBox x:Name="lb" ItemsSource="{Binding ListBoxData}" Width="500" BorderThickness="0" > 6 <ListBox.ItemsPanel> 7 <ItemsPanelTemplate> 8 <WrapPanel Width="{Binding ActualWidth,RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"/> 9 </ItemsPanelTemplate> 10 </ListBox.ItemsPanel> 11 12 <ListBox.ItemTemplate> 13 <DataTemplate> 14 <StackPanel> 15 <Image Source="{Binding Img}" Width="96" Height="96"/> 16 <TextBlock HorizontalAlignment="Center" Text="{Binding Info}"/> 17 </StackPanel> 18 </DataTemplate> 19 </ListBox.ItemTemplate> 20 </ListBox> 21 </StackPanel> 22 23 <StackPanel DockPanel.Dock="Right" DataContext="{Binding SelectedItem,ElementName=lb}" Margin="15" Orientation="Vertical" > 24 <TextBlock Text="{Binding Info,StringFormat='选中:\{0\}'}" ></TextBlock> 25 </StackPanel> 26 </DockPanel> 27 </StackPanel>
ViewModel代码:
1 #region ListBox 模板 2 3 private IEnumerable listBoxData; 4 /// <summary> 5 /// LisBox数据模板 6 /// </summary> 7 public IEnumerable ListBoxData 8 { 9 get { return listBoxData; } 10 set { listBoxData = value;RaisePropertyChanged(()=>ListBoxData); } 11 } 12 13 #endregion
初始数据:
1 private void InitListBoxList() 2 { 3 ListBoxData = new ObservableCollection<dynamic>(){ 4 new { Img="/MVVMLightDemo;component/Images/1.jpg",Info="樱桃" }, 5 new { Img="/MVVMLightDemo;component/Images/2.jpg",Info="葡萄" }, 6 new { Img="/MVVMLightDemo;component/Images/3.jpg",Info="苹果" }, 7 new { Img="/MVVMLightDemo;component/Images/4.jpg",Info="猕猴桃" }, 8 new { Img="/MVVMLightDemo;component/Images/5.jpg",Info="柠檬" }, 9 }; 10 }
结果:
7、用户控件的集合绑定:
1 <UserControl x:Class="MVVMLightDemo.Content.FruitInfoView" 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="300" d:DesignWidth="300"> 8 <Grid> 9 <Grid.Resources> 10 <Style TargetType="{x:Type StackPanel}"> 11 <Style.Triggers> 12 <Trigger Property="IsMouseOver" Value="True"> 13 <Setter Property="RenderTransform"> 14 <Setter.Value> 15 <RotateTransform Angle="10"></RotateTransform> 16 </Setter.Value> 17 </Setter> 18 <Setter Property="Background" Value="#3B9CFB" /> 19 </Trigger> 20 </Style.Triggers> 21 </Style> 22 </Grid.Resources> 23 24 25 <StackPanel Orientation="Vertical" Margin="10"> 26 <Image Source="{Binding Img}" Width="96" Height="96" /> 27 <TextBlock HorizontalAlignment="Center" Text="{Binding Info}"/> 28 </StackPanel> 29 30 </Grid> 31 </UserControl>
在目标视图页面注册并使用:
1 xmlns:Content="clr-namespace:MVVMLightDemo.Content"
1 <StackPanel Margin="10,0,0,50" Orientation="Vertical" > 2 <TextBlock Text="用户控件模板列表" FontWeight="Bold" FontSize="12" Margin="0,5,0,5" ></TextBlock> 3 <StackPanel HorizontalAlignment="Left" Width="500" > 4 <ItemsControl ItemsSource="{Binding FiList}" HorizontalAlignment="Left" > 5 <ItemsControl.ItemTemplate> 6 <DataTemplate> 7 <Content:FruitInfoView /> 8 </DataTemplate> 9 </ItemsControl.ItemTemplate> 10 11 <!-- 面板显示模板 --> 12 <ItemsControl.ItemsPanel> 13 <ItemsPanelTemplate> 14 <WrapPanel Orientation="Horizontal"> 15 </WrapPanel> 16 </ItemsPanelTemplate> 17 </ItemsControl.ItemsPanel> 18 19 </ItemsControl> 20 21 </StackPanel> 22 </StackPanel>
结果:
后记:这篇更确切的说是绑定的相关知识,只是应用了MVVM模式来实现。
工作太忙了,写的太慢,其实后面几篇都已经成稿了,一直放在Note里面等待认真检查,品质太差怕误导其他开发人员。