实例讲解wpf数据绑定及值转换的应用
先谈谈MVVM
谈起MVVM并不陌生了,最开始接触MVVM是在做一个web项目,这个web项目是用在移动端,使用了ionic+angularJs,期初使用的时候对MVVM并不是很了解,经过一段时间的使用发现,其实MVVM是对MVC的延展,现在前端技术越来越多,而且前端的工作也越来越多,不仅仅是做个页面的事情了,随着nodejs的兴起,前段好像无所不能了,做起了后端的事情,这里MVVM其实也有这个意思,随着MVC应用的越来越广泛,大家发现了一个问题:C层越来越大,业务逻辑全部在这块。MVVM是为了解决这个问题而出现的。
MVVM(Model-View-view-Model),这种模式上突出一点“数据绑定”:将Model和View进行绑定,Model的数据变化时View上的展示就随之变化,然后有一个View-Model 就是写在前端的数据转换工具,angular其实本质上是将后端的开发模型引入到了前端,在前端完成数据整理的工作。
wpf的MVVM
1.UI对象绑定
将源控件的某个属性绑定到目标控件的某个属性上,绑定的语法:Text=”{Binding ElementName=SourceObjectName, Path=SourceProperty}”
看个例子:
我们将姓名1后textbox的text属性绑定到姓名后的textbox的text属性上,当我在姓名后面输入什么,姓名1后也会显示一样的内容
代码:
 
<TextBlock Grid.Row="1" Grid.Column="1" Text="姓 名" Style="{StaticResource UserInfoTextBlockStyle}"></TextBlock> <TextBox x:Name="main_userInfo_name_tbx" Grid.Row="1" Grid.Column="2" Style="{StaticResource UserInfoTextBoxStyle}"></TextBox> <TextBlock Grid.Row="1" Grid.Column="3" Text="姓 名1" Style="{StaticResource UserInfoTextBlockStyle}" ></TextBlock> <TextBox x:Name="main_userInfo_phoneNO_tbx" Text="{Binding ElementName=main_userInfo_name_tbx,Path=Text }" Grid.Row="1" Grid.Column="4" Style="{StaticResource UserInfoTextBoxStyle}"></TextBox>
当然除了在xaml中实现绑定,我们也可以在cs文件中代码实现绑定:
代码如下:
 
Binding binding = new Binding(); //设置源对象 binding.Source = main_userInfo_name_tbx; //设置源属性 binding.Path = new PropertyPath("Text"); //添加到目标属性 this.main_userInfo_phoneNO_tbx.SetBinding(TextBlock.TextProperty, binding);
2.绑定到数据源
这种很常见,比如常见的combobox下拉框中的数据,可以通过绑定来实现。
对于所有的ItemsControl对象都有一个ItemsSource依赖属性,这是专门为数据绑定而准备的。ItemsSource的类型是IEnumerable,所以对于我们几乎所有的集合类型我们都可以轻易的改变成ItemsSource的源对象。依赖属性内建的垂直通知功能让UI对象间的绑定可以自己负责同步处理,但是对于.NET集合/对象来讲,它不具备这样的能力。为了让目标属性与源集合的更改保持同步,源集合必须实现一个叫INotifyCollectionChanged的接口,但通常我们只需要将集合类继承于ObservableCollection类即可。因为ObservableCollection实现了INotifyPropertyChanged和INotifyCollectionChanged接口。
举个例子看一下,现在有一个需求,需要在dataGrid中动态展示采集到的数据(边采集边展示,数据一条条增加),达到这样的效果:

而且要实时更新状态,这里我们采用绑定的方式实现:
1>.首先要定义展示数据的数据模型(字段定义)
2>.在界面上定义绑定区域(xaml中)
3>.在业务逻辑中初始化数据模型类,然后将数据集合绑定到datagrid上
数据模型代码:
 
public class FtpGrideData : INotifyPropertyChanged { private Visibility isvisible; public Visibility IsVisible { get { return isvisible; } set { this.isvisible = value; OnPropertyChanged("IsVisible"); } } private string host; public string Host { get { return host; } set { this.host = value; OnPropertyChanged("Host"); } } private string address; public string Address { get { return address; } set { this.address = value; OnPropertyChanged("Address"); } } private string transType; public string TransType { get { return transType; } set { this.transType = value; OnPropertyChanged("TransType"); } } private string fileNum; public string FileNum { get { return fileNum; } set { this.fileNum = value; OnPropertyChanged("FileNum"); } } private string fileSize; private string testTime; private string averageSpeed; public string FileSize { get { return fileSize; } set { this.fileSize = value; OnPropertyChanged("FileSize"); } } public string TestTime { get { return testTime; } set { this.testTime = value; OnPropertyChanged("TestTime"); } } public string AverageSpeed { get { return averageSpeed; } set { this.averageSpeed = value; OnPropertyChanged("AverageSpeed"); } } private string statusDesc; public string StatusDesc { get { return statusDesc; } set { this.statusDesc = value; OnPropertyChanged("StatusDesc"); } } private string errorMessage; public string ErrorMessage { get { return errorMessage; } set { this.errorMessage = value; OnPropertyChanged("ErrorMessage"); } } public event PropertyChangedEventHandler PropertyChanged; void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }
前台页面代码:
 
<DataGrid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Name="ftpinfoDataGrid" RowHeaderWidth="0" ItemsSource="{Binding}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserSortColumns="False" SelectionMode="Single" SelectionUnit="FullRow" RowHeight="40" CanUserResizeRows="False" CanUserReorderColumns="False" CanUserResizeColumns="False" GridLinesVisibility="None" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" VerticalScrollBarVisibility="Auto" Background="White" > <DataGrid.ColumnHeaderStyle> <Style TargetType="DataGridColumnHeader"> <Setter Property="HorizontalContentAlignment" Value="Center" /> <Setter Property="Background" Value="#CCE1F1"/> <Setter Property="Foreground" Value="Black"/> <Setter Property="FontSize" Value="16" /> <Setter Property="BorderThickness" Value="0,1,0,1"/> <Setter Property="Height" Value="40" /> </Style> </DataGrid.ColumnHeaderStyle> <DataGrid.CellStyle> <Style TargetType="DataGridCell" > <Setter Property="FontSize" Value="14"/> <Setter Property="Foreground" Value="Black"/> <Setter Property="VerticalAlignment" Value="Center" /> <!--<Setter Property="Margin" Value="0,10,0,10" />--> <!--<Setter Property="Height" Value="40" />--> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="Background" Value="#CCE1F1"/> <Setter Property="Foreground" Value="Black"/> <Setter Property="BorderThickness" Value="0"/> </Trigger> </Style.Triggers> </Style> </DataGrid.CellStyle> <DataGrid.RowStyle> <Style TargetType="DataGridRow"> <Setter Property="Background" Value="#FFF" /> <Setter Property="BorderThickness" Value="0"/> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Stretch" /> <!--<Setter Property="Margin" Value="0,10,0,10" />--> <Setter Property="Height" Value="38" /> <!--设置每行的颜色为蓝色--> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Background" Value="#F2F2F2"/> <Setter Property="Foreground" Value="Black"/> </Trigger> <Trigger Property="IsSelected" Value="True"> <Setter Property="Background" Value="#CCE1F1"/> <Setter Property="Foreground" Value="Black"/> </Trigger> </Style.Triggers> </Style> </DataGrid.RowStyle> <DataGrid.Columns > <!--<DataGridTextColumn Width="100" Header=" " IsReadOnly="True"></DataGridTextColumn>--> <!-- <DataGridTemplateColumn Header="" Width="60"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Image Visibility="{Binding IsVisible}" Source="Images/statue.png" Width="20" Height="20"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> --> <DataGridTextColumn Width="140" Header="地址" Binding="{Binding Path=Address}" IsReadOnly="true" ElementStyle="{StaticResource CenterAlignmentStyle}" ></DataGridTextColumn> <DataGridTextColumn Width="125" Header="传输类型" Binding="{Binding Path=TransType}" IsReadOnly="true" ElementStyle="{StaticResource CenterAlignmentStyle}" ></DataGridTextColumn> <DataGridTextColumn Width="125" Header="传输文件数" Binding="{Binding Path=FileNum}" IsReadOnly="true" ElementStyle="{StaticResource CenterAlignmentStyle}" ></DataGridTextColumn> <DataGridTextColumn Width="120" Header="文件大小" Binding="{Binding Path=FileSize}" IsReadOnly="true" ElementStyle="{StaticResource CenterAlignmentStyle}" ></DataGridTextColumn> <DataGridTextColumn Width="120" Header="总耗时" Binding="{Binding Path=TestTime}" IsReadOnly="true" ElementStyle="{StaticResource CenterAlignmentStyle}" ></DataGridTextColumn> <DataGridTextColumn Width="120" Header="平均速率" Binding="{Binding Path=AverageSpeed}" IsReadOnly="true" ElementStyle="{StaticResource CenterAlignmentStyle}" ></DataGridTextColumn> <DataGridTemplateColumn Width="120" Header="状态" IsReadOnly="True" > <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Path=StatusDesc}" ToolTip="{Binding Path=ErrorMessage}" HorizontalAlignment="Center" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
数据模型初始化,数据绑定:
 
_ftpDataList = new ObservableCollection<FtpGrideData>(); this.ftpinfoDataGrid.DataContext = this._ftpDataList;
3.数据模板&&值转换器Value Converter
数据模板:在日常开发中总会遇到基本控件的样子满足不了客户展示需求,这样就需要定制数据模板(定制展示方式)
值转换器:有些情况下,我们绑定的值,并不是最终界面上要展示的结果。比如数据中有一个状态位,但是在界面上我需要用某张图片或者某种样式展示,这时候就需要使用“值转换器Value Converter”来对值进行相应的转换。
举个例子:
有这样的一个需求:在页面中需要按顺序打开多个网页,头部展示该网页的LOGO,当前正在打开的网页的LOGO设置成正常,其他网页LOGO设置为半透明(这里要使用值转换器)

另外,某些网站不存在LOGO图片,我们给他默认的LOGO图片并且要在旁边显示它得网址(这里需要使用数据模板)

制作思路:
1>.定义展示结果的数据模型和值转换方法
2>.在界面上定义显示区域,定义数据模板(针对没有LOGO的情况),引用值转换方法
3>.在业务逻辑里面完成数据模型的初始化,数据绑定操作
看看代码吧,数据模型代码:
 
public class WebTestData : INotifyPropertyChanged { public WebTestData() { this.name = ""; } private string url; public String Url { get { return url; } set { this.url = value; OnPropertyChanged("Url"); } } private int isActive; public int IsActive { get { return isActive; } set { this.isActive = value; OnPropertyChanged("IsActive"); } } private string name; public string Name { get { return name; } set { this.name = value; OnPropertyChanged("Name"); } } private bool isShowName; public bool IsShowName { get { return isShowName; } set { this.isShowName = value; OnPropertyChanged("IsShowName"); } } private string webSiteTooltip; public string WebSiteTooltip { get { return webSiteTooltip; } set { this.webSiteTooltip = value; OnPropertyChanged("WebSiteTooltip"); } } public event PropertyChangedEventHandler PropertyChanged; void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }
值转换方法:
 
public class ImageConverter : IValueConverter { //在载入数据的时候将数据转换为图片类型 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { try { Uri uri = new Uri((string)value, UriKind.RelativeOrAbsolute); BitmapImage img = new BitmapImage(uri); return img; } catch { return new BitmapImage(); } } //在页面上操作的时候,将图片类型转换为数据,这里只有再TwoWay的时候才有用 public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { BitmapImage img = value as BitmapImage; return img.UriSource.AbsoluteUri; } } public class BorderStyleConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { try { int isactive = (int)value; Style style = new Style(); FrameworkElement fe = new FrameworkElement(); style = (Style)fe.TryFindResource("opacity1"); if (isactive == 1) { style = (Style)fe.TryFindResource("opacity1"); } else { style = (Style)fe.TryFindResource("opacity2"); } return style; } catch { throw new NotImplementedException(); } } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }
前台展示及数据模板定义代码:
 
 <UserControl.Resources>
        <local:ImageConverter x:Key="ImageConverter"/>
        <local:BorderStyleConverter x:Key="BorderStyleConverter"/>
        <Style x:Key="websiteListStyle"  TargetType="{x:Type ListBox}">
            <Setter Property="ItemsPanel">
                <Setter.Value>
                    <ItemsPanelTemplate>
                        <WrapPanel Margin="0,0,0,0" 
                                   Orientation="Horizontal" 
                                   IsItemsHost="True" 
                                   Width="{Binding (FrameworkElement.ActualWidth),RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"
                                   SnapsToDevicePixels="True"
                                   />
                    </ItemsPanelTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="ItemTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <Border  Style="{Binding IsActive,Converter={StaticResource BorderStyleConverter}}" x:Name="border"  Margin="5,0,0,0" CornerRadius="5" Height="40" Width="100"  BorderThickness="1" VerticalAlignment="Center" Background="#fff">
                            <Grid Margin="2">
                                <Image Width="100" Height="40" Source="{Binding Url, Converter={StaticResource ImageConverter}}"
                                       Margin="5" Cursor="Hand" Stretch="Fill" ToolTip="{Binding WebSiteTooltip}" 
                                       HorizontalAlignment="Center" VerticalAlignment="Center"  />
                                <Grid Name="CustWebTestGrid" Visibility="Collapsed" Width="100"
                                      Background="White" ToolTip="{Binding WebSiteTooltip}" 
                                      VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="32" />
                                        <ColumnDefinition Width="*" />
                                    </Grid.ColumnDefinitions>
                                    <Image Width="32" Stretch="Uniform" Grid.Column="0"
                                           Source="/Images/DefaultWebTestIcon.png" 
                                           Cursor="Hand"   />
                                    <TextBox Name="WebSiteName" Grid.Column="1" Text="{Binding Name}" Margin="0,0,4,0"
                                            Height="40" HorizontalAlignment="Center" 
                                             VerticalAlignment="Center"  HorizontalContentAlignment="Center"  VerticalContentAlignment="Center"                                           
                                           IsReadOnly="True" BorderThickness="0"
                                           FontFamily="Microsoft YaHei UI Light" FontSize="12" 
                                           Foreground="Black"  />
                                </Grid>
                                <!--<Image ToolTip="{Binding IsActive}" Width="100" Height="40" Source="{Binding Url,Converter = {StaticResource ImageConverter}}" Margin="5" Cursor="Hand" Stretch="Fill" HorizontalAlignment="Center" VerticalAlignment="Center"  />-->
                            </Grid>
                        </Border>
                        <DataTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="BorderBrush" Value="#5e5e5e" TargetName="border" />
                            </Trigger>
                            <DataTrigger Binding="{Binding IsShowName}" Value="True">
                                <Setter Property="Visibility" Value="Visible" TargetName="CustWebTestGrid" />
                            </DataTrigger>
                        </DataTemplate.Triggers>
                    </DataTemplate>
                </Setter.Value>
            </Setter >            
        </Style>
    </UserControl.Resources>
<!--下面是使用ListBox来展示LOGO-->
<StackPanel Width="600" Height="64" Canvas.Left="150" Canvas.Top="4">
                <!--<Image Height="50" Width="100" Source="../Images/main_start.png" Margin="150,0"/>-->
                
                    <ListBox Background="Transparent" Height="50" Width="600" Margin="0"
                             BorderBrush="Transparent"
                             ItemsSource="{Binding WebTestDatas}"                              
                             Name="flowNodes" Style="{StaticResource websiteListStyle}">                        
                    </ListBox>
            </StackPanel>
初始化数据模型对象,数据绑定代码:
 
ObservableCollection<WebTestData> WebTestDatas = new WebTestData(); this.flowNodes.ItemsSource = WebTestDatas;
OK,关于数据绑定的应用就先介绍到这里,我也是个学习中的开发者,欢迎各位大牛提意见!


 
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号