zoukankan      html  css  js  c++  java
  • wpf日历控件制作过程分析(全)[转]

     希望通过分析能更好的理解wpf控件的开发

    wpf日历控件制作过程分析(1)---定义header

      一.日历的header布局

      包含两部分,两个按钮和一个Title

    wpf日历控件制作过程分析(1)---定义header

      首先定义按钮的样式(随自己定),可以先定义几个状态为普通状态,鼠标经过状态,按下状态和禁用4个状态显示不同的样式.其中按钮上还有一个小三角.所以还要定义一个三角的Geometry

      代码开始

      1.画出Geometry(涉及知识点为Geometry的画法及迷你语法,如M Z等)

    <PathGeometry x:Key="geometry" Figures="M0,0 4.5,4 9,0 5.5,0 4.5,1 3.5,0z"/>

      2.定义4个不同状态下的笔刷(可自由发挥)

      Code

      <LinearGradientBrush x:Key="MonthCalendarButtonFillNormal" StartPoint="0,0" EndPoint="1,1">
        <LinearGradientBrush.GradientStops>
          <GradientStop Color="#FFE1EAFE" Offset="0"/>
          <GradientStop Color="#FFC3D3FD" Offset="0.3"/>
          <GradientStop Color="#FFC3D3FD" Offset="0.6"/>
          <GradientStop Color="#FFBBCDF9" Offset="1"/>
        </LinearGradientBrush.GradientStops>
      </LinearGradientBrush>
      <LinearGradientBrush x:Key="MonthCalendarButtonFillHover" StartPoint="0, 0" EndPoint="1, 1">
        <LinearGradientBrush.GradientStops>
          <GradientStop Color="#FFD6E7FF" Offset="0"/>
          <GradientStop Color="#FFD6E7FF" Offset="0.6"/>
          <GradientStop Color="#FFB9DAFB" Offset="1"/>
        </LinearGradientBrush.GradientStops>
      </LinearGradientBrush>
      <LinearGradientBrush x:Key="MonthCalendarButtonFillPressed" StartPoint="0, 0" EndPoint="1, 1">
        <LinearGradientBrush.GradientStops>
          <GradientStop Color="#FF93A8D9" Offset="0"/>
          <GradientStop Color="#FFA5BDFB" Offset="0.3"/>
          <GradientStop Color="#FFA5BDFB" Offset="0.7"/>
          <GradientStop Color="#FFD2DEEB" Offset="1.0"/>
        </LinearGradientBrush.GradientStops>
      </LinearGradientBrush>
      <LinearGradientBrush x:Key="MonthCalendarButtonFillDisabled" StartPoint="0, 0" EndPoint="1, 1">
        <LinearGradientBrush.GradientStops>
          <GradientStop Color="#FFF7F7F7" Offset="0"/>
          <GradientStop Color="#FFF0F0F0" Offset="0.3"/>
          <GradientStop Color="#FFECECEC" Offset="0.6"/>
          <GradientStop Color="#FFE3E3E3" Offset="1.0"/>
        </LinearGradientBrush.GradientStops>
      </LinearGradientBrush>

      3.定义按钮样式,按钮上再使用上面的笔刷

      Code

      <Style x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type DateControls:MonthCalendar},ResourceId=PreviousButtonStyleKey}" TargetType="{x:Type ButtonBase}">
        <Setter Property="Width" Value="16" />
        <Setter Property="Height" Value="16" />
        <Setter Property="Background" Value="{StaticResource MonthCalendarButtonFillNormal}" />
        <Setter Property="Foreground" Value="#FF4D6185"/>
        <Setter Property="Focusable" Value="false"/>
        <Setter Property="VerticalAlignment" Value="Top"/>
      </Style>
      <Style x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type DateControls:MonthCalendar},ResourceId=NextButtonStyleKey}" TargetType="{x:Type ButtonBase}">
        <Setter Property="Width" Value="16" />
        <Setter Property="Height" Value="16" />
        <Setter Property="Background" Value="{StaticResource MonthCalendarButtonFillNormal}" />
        <Setter Property="Foreground" Value="#FF4D6185"/>
        <Setter Property="Focusable" Value="false"/>
        <Setter Property="VerticalAlignment" Value="Top"/>
      </Style>

      注意上面黑字,这里使用了数据绑定的类型转换器,只要给这个控件指定数据源就可以了,其作用是把日期转换上面第二张截图的格式

      5.整合header

      Code

                    <!--header beginer-->
                    <Grid x:Name="Title">
                      <DateControls:MonthCalendarTitle x:Name="TitleHost" DataContext="{TemplateBinding VisibleMonth}" Style="{TemplateBinding TitleStyle}"/>
                      <RepeatButton x:Name="PART_PreviousButton" Command="DateControls:MonthCalendar.PreviousCommand"
                         Margin="7 5 0 0" HorizontalAlignment="Left" >
                        <Viewbox>
                          <Path Data="{StaticResource geometry}" Fill="Black">
                            <Path.LayoutTransform>
                              <RotateTransform Angle="90"/>
                            </Path.LayoutTransform>
                          </Path>
                        </Viewbox>
                      </RepeatButton>
                      <RepeatButton x:Name="PART_NextButton" Command="DateControls:MonthCalendar.NextCommand"
                         Margin="0 5 7 0" HorizontalAlignment="Right">
                        <Viewbox>
                          <Path Data="{StaticResource geometry}" Fill="Black">
                            <Path.LayoutTransform>
                              <RotateTransform Angle="-90"/>
                            </Path.LayoutTransform>
                          </Path>
                        </Viewbox>
                      </RepeatButton>
                    </Grid>
                    <!--heander end-->

      注意点:

      1.使用DataContext作为数据源

      2.用RepeatButton当作按钮(可重复触发事件)

      3.使用LayoutTransform翻转Geometry图形

      4.自定义样式TitleStyle,默认为空

      5.未见RepeatButton使用定义的ButtonBase样式?(可与第四点比较)

      下次继续

    定义header

      在header中,我们看到了定义一个自定义样式TitleStyle

      1.自定义样式

      看后台代码定义

      Code

        /**//// <summary>
        /// The DependencyProperty for the TitleStyle property.
        /// Flags:       none
        /// Default Value:   null
        /// </summary>
        public static readonly DependencyProperty TitleStyleProperty =
            DependencyProperty.Register(
                "TitleStyle",
                typeof(Style),
                typeof(MonthCalendar),
                new FrameworkPropertyMetadata(
                    (Style)null));
        /**//// <summary>
        /// TitleStyle property
        /// </summary>
        public Style TitleStyle
        {
          get { return (Style)GetValue(TitleStyleProperty); }
          set { SetValue(TitleStyleProperty, value); }
        }

      应该说,是比较简单的,默认样式为null,如果指定了样式的话,则会覆盖默认的样式

      2.不重叠选择样式

      为日历的前进和后退按钮定义两个样式

      Code

        /**//// <summary>
        /// The DependencyProperty for the PreviousButtonStyle property.
        /// Flags:       none
        /// Default Value:   null
        /// </summary>
        public static readonly DependencyProperty PreviousButtonStyleProperty =
            DependencyProperty.Register(
                "PreviousButtonStyle",
                typeof(Style),
                typeof(MonthCalendar),
                new FrameworkPropertyMetadata(
                    (Style)null, new PropertyChangedCallback(OnPreviousButtonStyleChanged)));
        /**//// <summary>
        /// PreviousButtonStyle property
        /// </summary>
        public Style PreviousButtonStyle
        {
          get { return (Style)GetValue(PreviousButtonStyleProperty); }
          set { SetValue(PreviousButtonStyleProperty, value); }
        }
        private static void OnPreviousButtonStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          ((MonthCalendar)d).RefreshPreviousButtonStyle();
        }
        /**//// <summary>
        /// The DependencyProperty for the NextButtonStyle property.
        /// Flags:       none
        /// Default Value:   null
        /// </summary>
        public static readonly DependencyProperty NextButtonStyleProperty =
            DependencyProperty.Register(
                "NextButtonStyle",
                typeof(Style),
                typeof(MonthCalendar),
                new FrameworkPropertyMetadata(
                    (Style)null, new PropertyChangedCallback(OnNextButtonStyleChanged)));
        /**//// <summary>
        /// NextButtonStyle property
        /// </summary>
        public Style NextButtonStyle
        {
          get { return (Style)GetValue(NextButtonStyleProperty); }
          set { SetValue(NextButtonStyleProperty, value); }
        }
        private static void OnNextButtonStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          ((MonthCalendar)d).RefreshNextButtonStyle();
        }

      再来这个RefreshNextButtonStyle方法

      Code

        private void RefreshNextButtonStyle()
        {
          ButtonBase nextButton = GetTemplateChild(c_NextButtonName) as ButtonBase;
          if (nextButton != null)
          {
            if (NextButtonStyle == null)
            {
              if (_defaultNextButtonStyle == null)
              {
                _defaultNextButtonStyle = FindResource(new ComponentResourceKey(typeof(MonthCalendar), "NextButtonStyleKey")) as Style;
              }
              nextButton.Style = _defaultNextButtonStyle;
            }
            else
            {
              nextButton.Style = NextButtonStyle;
            }
          }
        }

      注意点:

      1.GetTemplateChild可以获取到xaml中声明了key值的元素,c_NextButtonName变量就是xaml定义的key,此key应该公开给控件的使用者,可调整样式

      2.用TemplatePart公开模块样式,如两个按钮的key值

      [TemplatePart(Name = "PART_PreviousButton", Type = typeof(ButtonBase))]

      [TemplatePart(Name = "PART_NextButton", Type = typeof(ButtonBase))]

      3._defaultNextButtonStyle还是从xaml去找,其目的是为了自定义样式不会与默认样式发生冲突.可以title样式比较

      4.构建可视化模板需要在OnApplyTemplate方法中使用,如上面的RefreshNextButtonStyle方法必须在OnApplyTemplate方法中调用

    <!--DayHeaders-->
                      <Grid x:Name="DayHeaders" Grid.Column="1">
                        <Grid.ColumnDefinitions>
                          <ColumnDefinition/>
                          <ColumnDefinition/>
                          <ColumnDefinition/>
                          <ColumnDefinition/>
                          <ColumnDefinition/>
                          <ColumnDefinition/>
                          <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <DateControls:MonthCalendarDayHeader Grid.Column="0" Style="{TemplateBinding DayHeaderStyle}"
                      DataContext="{Binding Path=FirstDayOfWeek,Mode=OneWay,Converter={StaticResource MonthCalendarDayHeaderConverter},ConverterParameter=0,RelativeSource={RelativeSource AncestorType={x:Type DateControls:MonthCalendar}}}"/>
                        <DateControls:MonthCalendarDayHeader Grid.Column="1" Style="{TemplateBinding DayHeaderStyle}"
                      DataContext="{Binding Path=FirstDayOfWeek,Mode=OneWay,Converter={StaticResource MonthCalendarDayHeaderConverter},ConverterParameter=1, RelativeSource={RelativeSource AncestorType={x:Type DateControls:MonthCalendar}}}"/>
                        <DateControls:MonthCalendarDayHeader Grid.Column="2" Style="{TemplateBinding DayHeaderStyle}"
                      DataContext="{Binding Path=FirstDayOfWeek,Mode=OneWay,Converter={StaticResource MonthCalendarDayHeaderConverter},ConverterParameter=2, RelativeSource={RelativeSource AncestorType={x:Type DateControls:MonthCalendar}}}"/>
                        <DateControls:MonthCalendarDayHeader Grid.Column="3" Style="{TemplateBinding DayHeaderStyle}"
                      DataContext="{Binding Path=FirstDayOfWeek,Mode=OneWay,Converter={StaticResource MonthCalendarDayHeaderConverter},ConverterParameter=3, RelativeSource={RelativeSource AncestorType={x:Type DateControls:MonthCalendar}}}"/>
                        <DateControls:MonthCalendarDayHeader Grid.Column="4" Style="{TemplateBinding DayHeaderStyle}"
                      DataContext="{Binding Path=FirstDayOfWeek,Mode=OneWay,Converter={StaticResource MonthCalendarDayHeaderConverter},ConverterParameter=4, RelativeSource={RelativeSource AncestorType={x:Type DateControls:MonthCalendar}}}"/>
                        <DateControls:MonthCalendarDayHeader Grid.Column="5" Style="{TemplateBinding DayHeaderStyle}"
                      DataContext="{Binding Path=FirstDayOfWeek,Mode=OneWay,Converter={StaticResource MonthCalendarDayHeaderConverter},ConverterParameter=5, RelativeSource={RelativeSource AncestorType={x:Type DateControls:MonthCalendar}}}"/>
                        <DateControls:MonthCalendarDayHeader Grid.Column="6" Style="{TemplateBinding DayHeaderStyle}"
                      DataContext="{Binding Path=FirstDayOfWeek,Mode=OneWay,Converter={StaticResource MonthCalendarDayHeaderConverter},ConverterParameter=6, RelativeSource={RelativeSource AncestorType={x:Type DateControls:MonthCalendar}}}"/>
                      </Grid>
                      <!--DayHeaders-->

      FirstDayOfWeek属性类型为DayOfWeek 枚举,通过数据绑定的ConverterParameter属性传递参数,然后通过类型转换器转换数据

      然后再画一条分隔线

    <Rectangle x:Name="DayHeadersSplitLine" Grid.Column="1" Fill="Black" Height="1" VerticalAlignment="Bottom" Margin="2,0,2,0"/>

      到目前为止,默认的显示效果如下

    wpf日历控件制作过程分析(3)---定义DayHeaders

  • 相关阅读:
    css学习记录(css元素类型)
    一个面向对象的js问题 大家帮忙看看
    css选择器记录
    css学习记录
    如何进行高效JavaScript单元测试
    js拖动库介绍
    PHP 方法记录
    jquery学习笔记(一)
    windows8 后台传递下载
    .NET Framework 4.5 RC 更新
  • 原文地址:https://www.cnblogs.com/slteam/p/1398063.html
Copyright © 2011-2022 走看看