WPF模板数据绑定及事件模板绑定

来源:互联网 发布:桃子圈微博全数据图 编辑:程序博客网 时间:2024/06/06 00:24

        变更通知是WPF的一个精髓,它使得MVVM成为WPF的标准架构!在数据绑定中,除了正常的数据模版绑定,还会涉及到模板内控件的事件绑定,以及对parent内容的绑定!接下来的示例将会展示大部分常用的绑定场景。

      示例实现的是一个便签软件,主要功能有新增、删除、修改、切换日期、读取便签列表、设置是否完成。

      下面先说下几种绑定方式:

       继承于ICommand和INotifyPropertyChanged的事件委托和通知变更类这里就不写了,网上很多的!或者你可以直接使用mvvmlight的框架。

       在App.xaml中加入资源NoteViewModel,方便在blend中绑定

<Application x:Class="ManageNote.App"             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"             xmlns:local="clr-namespace:ManageNote.ViewModel"             Startup="ApplicationStartup" >    <Application.Resources>        <local:NoteViewModel x:Key="NoteViewModel"></local:NoteViewModel>    </Application.Resources></Application>
打开blend,如果不习惯用blend,可以参考后面的xaml代码自己编写!

1、模板数据绑定,这是最基础的绑定,通过blend可以实现

1.1 绑定window的datacontext


1.2绑定listbox的itemsource


1.3、右键Listbox > 编辑其他模版 > 编辑生成的项 > 创建新项,拖入一个checkbox和textblock,并绑定相对应的字段。如果需要字段转换,最常用的是bool和visible等,可以自己写convert转换器,具体写法自行百度。



1.4 通过“行为”来控制,文本框是否可编辑!原本是只读模式,在双击后可以进行编辑,只展示一个示例,其他的在代码中找!


2、模版父控件的绑定

下面需要绑定checkbox的点击事件来设置该项任务是否完成。在blend中可以看到,在模板的数据绑定中只能显示notemodel中的字段,这是因为item的datacontext类型为NoteModel。我们想绑定NoteViewModel中的CompleteCommand事件,就需要自行指定绑定的数据源。这需要通过代码实现:

<CheckBox x:Name="checkBox" d:LayoutOverrides="Width, Height" HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="{Binding IsCompleted}" Command="{Binding DataContext.CompleteCommand, RelativeSource={RelativeSource AncestorType=Window}}"  CommandParameter="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}" >

这里的Binding使用到了Path和RelativeSource。

msdn的RelativeSource:http://msdn.microsoft.com/zh-cn/library/system.windows.data.binding.source(v=vs.90).aspx

RelativeSource成员:http://msdn.microsoft.com/zh-SG/library/system.windows.data.relativesource_members(v=vs.85)

RelativeSource的AncestorType:http://msdn.microsoft.com/zh-SG/library/system.windows.data.relativesource.ancestortype(v=vs.85)

这几篇文章读完就能掌握常用的几种绑定方式了。

3、模板绑定某一元素的属性(通过RelativeSource查找)

 <ContextMenu x:Key="ContextMenuKey">            <MenuItem Header="删除" Command="{Binding DataContext.DelPlan, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding Path=DataContext, RelativeSource={RelativeSource  Mode=FindAncestor, AncestorLevel=1,AncestorType=ItemsPresenter}}" />        </ContextMenu>
AncestorLevel来确定向上查找的级别,AncestorType确定要查找的元素!这点很类似于JQuery的Selector。

以上就是几种常用的绑定方式。

下面贴上部分源码:

NoteWindow.xaml

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" xmlns:ManageNote_ViewModel="clr-namespace:ManageNote.ViewModel" x:Class="ManageNote.NoteWindow"        Title="便签" RenderOptions.BitmapScalingMode="NearestNeighbor"  mc:Ignorable="d"  ShowInTaskbar="False" WindowStyle="None" AllowsTransparency="True" ResizeMode="NoResize" Background="{x:Null}" VerticalContentAlignment="Stretch" Width="250" Height="200" DataContext="{DynamicResource NoteViewModel}" >    <Window.Resources>        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>        <ContextMenu x:Key="ContextMenuKey">            <MenuItem Header="删除" Command="{Binding DataContext.DelPlan, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding Path=DataContext, RelativeSource={RelativeSource  Mode=FindAncestor, AncestorLevel=1,AncestorType=ItemsPresenter}}" />        </ContextMenu>        <Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">            <Setter Property="Template">                <Setter.Value>                    <ControlTemplate TargetType="{x:Type Button}">                        <Grid>                            <Path Data="M16,16 L32,8.0002261 32,24.000226 z" Fill="#FF888864" Stretch="Fill" Stroke="Black" StrokeThickness="0"/>                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Content=""/>                        </Grid>                        <ControlTemplate.Triggers>                            <Trigger Property="IsFocused" Value="True"/>                            <Trigger Property="IsDefaulted" Value="True"/>                            <Trigger Property="IsMouseOver" Value="True"/>                            <Trigger Property="IsPressed" Value="True"/>                            <Trigger Property="IsEnabled" Value="False"/>                        </ControlTemplate.Triggers>                    </ControlTemplate>                </Setter.Value>            </Setter>        </Style>        <DataTemplate x:Key="DataTemplate1">            <Grid d:DesignWidth="238" Margin="0,2" Background="{x:Null}">                <Grid.ColumnDefinitions>                    <ColumnDefinition Width="25"/>                    <ColumnDefinition Width="*"/>                </Grid.ColumnDefinitions>                <CheckBox x:Name="checkBox" d:LayoutOverrides="Width, Height" HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="{Binding IsCompleted}" Command="{Binding DataContext.CompleteCommand, RelativeSource={RelativeSource AncestorType=Window}}"  CommandParameter="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}" >                </CheckBox>                <TextBox x:Name="textBox" Grid.Column="1" Height="Auto" TextWrapping="Wrap" Text="{Binding Content}" IsReadOnly="True" Background="{x:Null}" BorderBrush="{x:Null}" SelectionBrush="#FF0D69FF" BorderThickness="1" Style="{DynamicResource TextBoxStyle1}">                    <i:Interaction.Triggers>                        <i:EventTrigger EventName="MouseDoubleClick">                            <ei:ChangePropertyAction TargetObject="{Binding ElementName=textBox}" PropertyName="IsReadOnly" Value="False"/>                        </i:EventTrigger>                        <i:EventTrigger EventName="LostFocus">                            <ei:ChangePropertyAction TargetObject="{Binding ElementName=textBox}" PropertyName="IsReadOnly" Value="True"/>                            <i:InvokeCommandAction Command="{Binding DataContext.UpdateTaskCommand,RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding Path=Content,RelativeSource={ RelativeSource Mode=TemplatedParent}}"/>                        </i:EventTrigger>                    </i:Interaction.Triggers>                </TextBox>            </Grid>        </DataTemplate>        <Style x:Key="ListBoxItemStyle1" TargetType="{x:Type ListBoxItem}">            <Setter Property="Background" Value="Transparent"/>            <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>            <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>            <Setter Property="Padding" Value="2,0,0,0"/>            <Setter Property="ContextMenu"  Value="{StaticResource ContextMenuKey}" />            <Setter Property="Template">                <Setter.Value>                    <ControlTemplate TargetType="{x:Type ListBoxItem}">                        <Border x:Name="Bd" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true" Background="{x:Null}">                            <VisualStateManager.VisualStateGroups>                                <VisualStateGroup x:Name="CommonStates">                                    <VisualState x:Name="Normal"/>                                    <VisualState x:Name="MouseOver"/>                                    <VisualState x:Name="Disabled"/>                                </VisualStateGroup>                            </VisualStateManager.VisualStateGroups>                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>                        </Border>                    </ControlTemplate>                </Setter.Value>            </Setter>        </Style>        <LinearGradientBrush x:Key="TextBoxBorder" EndPoint="0,20" MappingMode="Absolute" StartPoint="0,0">            <GradientStop Color="#ABADB3" Offset="0.05"/>            <GradientStop Color="#E2E3EA" Offset="0.07"/>            <GradientStop Color="#E3E9EF" Offset="1"/>        </LinearGradientBrush>        <Style x:Key="TextBoxStyle1" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>            <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>            <Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>            <Setter Property="BorderThickness" Value="1"/>            <Setter Property="Padding" Value="1"/>            <Setter Property="AllowDrop" Value="true"/>            <Setter Property="FocusVisualStyle" Value="{x:Null}"/>            <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>            <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>            <Setter Property="Template">                <Setter.Value>                    <ControlTemplate TargetType="{x:Type TextBox}">                        <Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" SnapsToDevicePixels="true">                            <VisualStateManager.VisualStateGroups>                                <VisualStateGroup x:Name="CommonStates">                                    <VisualState x:Name="Normal"/>                                    <VisualState x:Name="Disabled"/>                                    <VisualState x:Name="ReadOnly"/>                                    <VisualState x:Name="MouseOver"/>                                </VisualStateGroup>                            </VisualStateManager.VisualStateGroups>                            <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" BorderThickness="1"/>                        </Microsoft_Windows_Themes:ListBoxChrome>                        <ControlTemplate.Triggers>                            <Trigger Property="IsEnabled" Value="false">                                <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>                            </Trigger>                        </ControlTemplate.Triggers>                    </ControlTemplate>                </Setter.Value>            </Setter>        </Style>    </Window.Resources>    <Grid  Margin="3">        <Border CornerRadius="5" Background="Black" BorderThickness="1" BorderBrush="#FFCDCDCD" >            <Border.Effect>                <DropShadowEffect BlurRadius="9" Color="#FF4B4747" Opacity="0.845" Direction="285" ShadowDepth="1"/>            </Border.Effect>        </Border>        <Grid>            <Grid.Background>                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">                    <GradientStop Color="#FFFDFDCB" Offset="0"/>                    <GradientStop Color="#FFFCF9A1" Offset="1"/>                </LinearGradientBrush>            </Grid.Background>            <Grid.RowDefinitions>                <RowDefinition Height="30" />                <RowDefinition />            </Grid.RowDefinitions>            <Border BorderBrush="Black" BorderThickness="0" Margin="0" Background="#FFF8F7B6"/>            <Image x:Name="image"            Height="20" Source="5_content_new.png" Stretch="Fill" Width="20" HorizontalAlignment="Right" Margin="0,0,30,0" VerticalAlignment="Center" >                <i:Interaction.Triggers>                    <i:EventTrigger EventName="MouseLeftButtonDown" SourceObject="{Binding ElementName=image}">                        <ei:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="AddAgenda" />                    </i:EventTrigger>                </i:Interaction.Triggers>            </Image>            <TextBlock  HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="labDate" Foreground="#FF646363" FontWeight="Bold" FontSize="13.333" Text="{Binding Title}" />            <Button  x:Name="btnPre" Content="Button" HorizontalAlignment="Left" Margin="5,0,0,0" Style="{DynamicResource ButtonStyle1}" Width="16" Height="16" VerticalAlignment="Center" Command="{Binding ChangeDateCommand, Mode=OneWay}" CommandParameter="-1"/>            <Button  x:Name="btnNext"  Content="Button" Margin="0,0,5,0" Style="{DynamicResource ButtonStyle1}" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Right" Width="16" Height="16" VerticalAlignment="Center" Background="{x:Null}" Command="{Binding ChangeDateCommand, Mode=OneWay}" CommandParameter="1">                <Button.RenderTransform>                    <TransformGroup>                        <ScaleTransform/>                        <SkewTransform/>                        <RotateTransform Angle="180"/>                        <TranslateTransform/>                    </TransformGroup>                </Button.RenderTransform>            </Button>            <ListBox Margin="5" Grid.Row="1" Background="{x:Null}" BorderThickness="0" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemContainerStyle="{DynamicResource ListBoxItemStyle1}" ScrollViewer.VerticalScrollBarVisibility="Hidden" ItemTemplate="{DynamicResource DataTemplate1}" ItemsSource="{Binding Tasks}" HorizontalContentAlignment="Stretch">            </ListBox>        </Grid>    </Grid></Window>

NoteViewModel.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using ManageNote.Model;using System.Data;using MySql.Data.MySqlClient;using System.Collections.ObjectModel;using System.Windows;using System.Windows.Input;namespace ManageNote.ViewModel{    public class NoteViewModel : NotificationObject    {        DateTime currentDate;        private DelegateCommand<NoteModel> completeCommand;        /// <summary>        /// 设置完成状态事件        /// </summary>        public DelegateCommand<NoteModel> CompleteCommand        {            get            {                if (this.completeCommand == null)                {                    this.completeCommand = new DelegateCommand<NoteModel>(this.SetComplete);                }                return this.completeCommand;            }        }        private DelegateCommand<NoteModel> delPlan;        /// <summary>        /// 删除计划事件        /// </summary>        public DelegateCommand<NoteModel> DelPlan        {            get            {                if (this.delPlan == null)                {                    this.delPlan = new DelegateCommand<NoteModel>(this.Delete);                }                return this.delPlan;            }        }        private DelegateCommand<object> changeDateCommand;        /// <summary>        /// 修改日期事件        /// </summary>        public DelegateCommand<object> ChangeDateCommand        {            get            {                if (this.changeDateCommand == null)                {                    this.changeDateCommand = new DelegateCommand<object>(this.ChangeDate);                }                return this.changeDateCommand;            }        }        private DelegateCommand<NoteModel> updateTaskCommand;        /// <summary>        /// 修改事件        /// </summary>        public DelegateCommand<NoteModel> UpdateTaskCommand        {            get            {                if (this.updateTaskCommand == null)                {                    this.updateTaskCommand = new DelegateCommand<NoteModel>(this.UpdateAgenda);                }                return this.updateTaskCommand;            }        }        public NoteViewModel()        {            this.BindDate(DateTime.Now.Date);        }        private string title;        /// <summary>        /// 标题        /// </summary>        public string Title        {            get            {                return this.title;            }            set            {                if (this.title != value)                {                    this.title = value;                    this.RaisePropertyChanged("Title");                }            }        }        private ObservableCollection<NoteModel> tasks = null;        /// <summary>        /// 任务计划集合        /// </summary>        public ObservableCollection<NoteModel> Tasks        {            get            {                return this.tasks;            }            set            {                if (this.tasks != value)                {                    this.tasks = value;                    this.RaisePropertyChanged("Tasks");                }            }        }        /// <summary>        /// 设置完成状态        /// </summary>        /// <param name="iComplete"></param>        /// <returns></returns>        private void SetComplete(NoteModel iModel)        {            StringBuilder strSql = new StringBuilder();            strSql.Append("UPDATE m_agenda SET IsComplete=");            strSql.Append(iModel.IsCompleted ? "1" : "0");            strSql.Append(" WHERE Id=");            strSql.Append(iModel.Id);            EJiang.Common.DirectDbHelperMysql.ExecuteSql(strSql.ToString());        }        private void ChangeDate(object days)        {            this.BindDate(this.currentDate.AddDays(Convert.ToInt32(days)));        }        /// <summary>        /// 用于外部调用,刷新信息        /// </summary>        public void RefrushInfo()        {            this.Tasks = this.GetNoteByDate(SystemConfig.userId, this.currentDate);        }        /// <summary>        /// 绑定信息        /// </summary>        /// <param name="date"></param>        private void BindDate(DateTime date)        {            this.currentDate = date;            this.Title = this.currentDate.ToString("yyyy年MM月dd");            this.Tasks = this.GetNoteByDate(SystemConfig.userId, this.currentDate);        }        /// <summary>        /// 删除        /// </summary>        /// <param name="id"></param>        private void Delete(NoteModel model)        {            if (MessageBox.Show("确定要删除该条任务?", "删除确认", MessageBoxButton.YesNo) == MessageBoxResult.Yes)            {                string strSql = "DELETE FROM m_agenda WHERE Id=" + model.Id;                if (EJiang.Common.DirectDbHelperMysql.ExecuteSql(strSql) > 0)                {                    this.Tasks.Remove(model);                }            }        }        /// <summary>        /// 获取日程        /// </summary>        /// <param name="userId"></param>        /// <param name="date"></param>        /// <returns></returns>        public ObservableCollection<NoteModel> GetNoteByDate(int userId, DateTime date)        {            StringBuilder strSql = new StringBuilder();            strSql.Append("SELECT ");            strSql.Append("Id, ");            strSql.Append("AgendaContent, ");            strSql.Append("StartDate, ");            strSql.Append("IsComplete ");            strSql.Append("FROM m_agenda ");            strSql.Append("WHERE StartDate = @startDate ");            strSql.Append("AND UserId = @userId ");            MySqlParameter[] para =             {                 new MySqlParameter("@userId", userId),                new MySqlParameter("@startDate", date)            };            ObservableCollection<NoteModel> models = new ObservableCollection<NoteModel>();            DataTable dt = EJiang.Common.DirectDbHelperMysql.Query(strSql.ToString(), para).Tables[0];            foreach (DataRow dr in dt.Rows)            {                models.Add(new NoteModel                {                    Id = Convert.ToInt32(dr["Id"]),                    Content = dr["AgendaContent"].ToString(),                    IsCompleted = dr["IsComplete"].ToString() == "1" ? true : false,                    StartDate = Convert.ToDateTime(dr["StartDate"])                });            }            return models;        }        /// <summary>        /// 新增日程        /// </summary>        /// <param name="noteModel"></param>        public void AddAgenda()        {            StringBuilder strSql = new StringBuilder();            strSql.Append("INSERT INTO m_agenda  ");            strSql.Append("(UserId,");            strSql.Append("AgendaContent,  ");            strSql.Append("StartDate,  ");            strSql.Append("LimitDate) ");            strSql.Append("VALUES ");            strSql.Append("(@UserId,  ");            strSql.Append("@AgendaContent,  ");            strSql.Append("@StartDate,  ");            strSql.Append("@LimitDate)");            MySqlParameter[] para =             {                 new MySqlParameter("@UserId", SystemConfig.userId),                new MySqlParameter("@AgendaContent", "请输入您的任务!"),                new MySqlParameter("@StartDate", this.currentDate),                new MySqlParameter("@LimitDate",  this.currentDate)            };            int id = Convert.ToInt32(EJiang.Common.DirectDbHelperMysql.ExecuteInsert(strSql.ToString(), para));            if (id > 0)            {                this.Tasks.Add(new NoteModel                {                    Id = id,                    Content = "请输入您的任务!",                    IsCompleted = false,                    StartDate = this.currentDate                });            }        }        /// <summary>        /// 更新日程        /// </summary>        /// <param name="noteModel"></param>        private void UpdateAgenda(NoteModel noteModel)        {            StringBuilder strSql = new StringBuilder();            strSql.Append("UPDATE m_agenda   ");            strSql.Append("SET  ");            strSql.Append("AgendaContent = @AgendaContent    ");            strSql.Append("WHERE  ");            strSql.Append("Id = @Id  ");            MySqlParameter[] para =             {                 new MySqlParameter("@Id", noteModel.Id),                new MySqlParameter("@AgendaContent", noteModel.Content)            };            EJiang.Common.DirectDbHelperMysql.ExecuteSql(strSql.ToString(), para);        }    }}

源码地址:http://download.csdn.net/detail/wuwo333/6316627


原创粉丝点击