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

        变更通知是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


  • 0
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值