miketwais

work up

实例讲解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>
View Code

当然除了在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);
View Code

 

2.绑定到数据源

这种很常见,比如常见的combobox下拉框中的数据,可以通过绑定来实现。

对于所有的ItemsControl对象都有一个ItemsSource依赖属性,这是专门为数据绑定而准备的。ItemsSource的类型是IEnumerable,所以对于我们几乎所有的集合类型我们都可以轻易的改变成ItemsSource的源对象。依赖属性内建的垂直通知功能让UI对象间的绑定可以自己负责同步处理,但是对于.NET集合/对象来讲,它不具备这样的能力。为了让目标属性与源集合的更改保持同步,源集合必须实现一个叫INotifyCollectionChanged的接口,但通常我们只需要将集合类继承于ObservableCollection类即可。因为ObservableCollection实现了INotifyPropertyChangedINotifyCollectionChanged接口。

举个例子看一下,现在有一个需求,需要在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));
            }
        }
    }
View Code

前台页面代码:

            <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>
View Code

数据模型初始化,数据绑定:

_ftpDataList = new ObservableCollection<FtpGrideData>();
this.ftpinfoDataGrid.DataContext = this._ftpDataList;
View Code

 

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));
            }
        }
    }
View Code

值转换方法:

    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();
        }
    }
View Code

前台展示及数据模板定义代码:

 <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>
View Code

初始化数据模型对象,数据绑定代码:

ObservableCollection<WebTestData> WebTestDatas = new WebTestData();
this.flowNodes.ItemsSource = WebTestDatas;
View Code

OK,关于数据绑定的应用就先介绍到这里,我也是个学习中的开发者,欢迎各位大牛提意见!

posted @ 2017-05-04 16:16  MasonZhang  阅读(1458)  评论(0)    收藏  举报