随笔-3  评论-5  文章-0 

WPF自定义Window样式(1)

目录:

WPF自定义Window样式(1)

WPF自定义Window样式(2)

 

1. 引言

    WPF是制作界面的一大利器。最近在做一个项目,用的就是WPF。既然使用了WPF了,那么理所当然的,需要自定义窗体样式。所使用的代码是在网上查到的:原文链接

      首先上原始源码

2. 创建项目

       创建空白项目stonemqy.CustomWindow,添加WPF项目stonemqy.CustomWindow.Main。在stonemqy.CustomWindow.Main中添加文件夹Themes,并在其中添加资源字典Generic.xaml,注意这里的Themes文件夹和Generic.xaml资源字典的名字不可更改。并在项目下依次添加类VisualStates、TransitioningContentControl和CustomWindow。

3. VisualStates

using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Media;

namespace stonemqy.CustomWindow.Main
{
    public static class VisualStates
    {  /// <summary>
        /// This method tries to get the named VisualStateGroup for the 
        /// dependency object. The provided object's ImplementationRoot will be 
        /// looked up in this call.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="groupName">The visual state group's name.</param>
        /// <returns>Returns null or the VisualStateGroup object.</returns>
        public static VisualStateGroup TryGetVisualStateGroup(DependencyObject dependencyObject, string groupName)
        {
            FrameworkElement root = GetImplementationRoot(dependencyObject);
            if (root == null)
            {
                return null;
            }

            return VisualStateManager.GetVisualStateGroups(root)
                .OfType<VisualStateGroup>()
                .Where(group => string.CompareOrdinal(groupName, group.Name) == 0)
                .FirstOrDefault();
        }

        /// <summary>
        /// Gets the implementation root of the Control.
        /// </summary>
        /// <param name="dependencyObject">The DependencyObject.</param>
        /// <remarks>
        /// Implements Silverlight's corresponding internal property on Control.
        /// </remarks>
        /// <returns>Returns the implementation root or null.</returns>
        public static FrameworkElement GetImplementationRoot(DependencyObject dependencyObject)
        {
            Debug.Assert(dependencyObject != null, "DependencyObject should not be null.");
            return (1 == VisualTreeHelper.GetChildrenCount(dependencyObject)) ?
                VisualTreeHelper.GetChild(dependencyObject, 0) as FrameworkElement :
                null;
        }
    }
}

4. TransitioningContentControl

using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;

namespace stonemqy.CustomWindow.Main
{
    /// <summary>
    /// Represents a control with a single piece of content and when that content 
    /// changes performs a transition animation. 
    /// </summary>
    /// <QualityBand>Experimental</QualityBand>
    /// <remarks>The API for this control will change considerably in the future.</remarks>
    [TemplateVisualState(GroupName = PresentationGroup, Name = NormalState)]
    [TemplateVisualState(GroupName = PresentationGroup, Name = DefaultTransitionState)]
    [TemplatePart(Name = PreviousContentPresentationSitePartName, Type = typeof(ContentControl))]
    [TemplatePart(Name = CurrentContentPresentationSitePartName, Type = typeof(ContentControl))]
    public class TransitioningContentControl : ContentControl
    {
        #region Visual state names
        /// <summary>
        /// The name of the group that holds the presentation states.
        /// </summary>
        private const string PresentationGroup = "PresentationStates";

        /// <summary>
        /// The name of the state that represents a normal situation where no
        /// transition is currently being used.
        /// </summary>
        private const string NormalState = "Normal";

        /// <summary>
        /// The name of the state that represents the default transition.
        /// </summary>
        public const string DefaultTransitionState = "DefaultTransition";
        #endregion Visual state names

        #region Template part names
        /// <summary>
        /// The name of the control that will display the previous content.
        /// </summary>
        internal const string PreviousContentPresentationSitePartName = "PreviousContentPresentationSite";

        /// <summary>
        /// The name of the control that will display the current content.
        /// </summary>
        internal const string CurrentContentPresentationSitePartName = "CurrentContentPresentationSite";

        #endregion Template part names

        #region TemplateParts
        /// <summary>
        /// Gets or sets the current content presentation site.
        /// </summary>
        /// <value>The current content presentation site.</value>
        private ContentPresenter CurrentContentPresentationSite { get; set; }

        /// <summary>
        /// Gets or sets the previous content presentation site.
        /// </summary>
        /// <value>The previous content presentation site.</value>
        private ContentPresenter PreviousContentPresentationSite { get; set; }
        #endregion TemplateParts

        #region public bool IsTransitioning

        /// <summary>
        /// Indicates whether the control allows writing IsTransitioning.
        /// </summary>
        private bool _allowIsTransitioningWrite;

        /// <summary>
        /// Gets a value indicating whether this instance is currently performing
        /// a transition.
        /// </summary>
        public bool IsTransitioning
        {
            get { return (bool)GetValue(IsTransitioningProperty); }
            private set
            {
                _allowIsTransitioningWrite = true;
                SetValue(IsTransitioningProperty, value);
                _allowIsTransitioningWrite = false;
            }
        }

        /// <summary>
        /// Identifies the IsTransitioning dependency property.
        /// </summary>
        public static readonly DependencyProperty IsTransitioningProperty =
            DependencyProperty.Register(
                "IsTransitioning",
                typeof(bool),
                typeof(TransitioningContentControl),
                new PropertyMetadata(OnIsTransitioningPropertyChanged));

        /// <summary>
        /// IsTransitioningProperty property changed handler.
        /// </summary>
        /// <param name="d">TransitioningContentControl that changed its IsTransitioning.</param>
        /// <param name="e">Event arguments.</param>
        private static void OnIsTransitioningPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TransitioningContentControl source = (TransitioningContentControl)d;

            if (!source._allowIsTransitioningWrite)
            {
                source.IsTransitioning = (bool)e.OldValue;
                throw new InvalidOperationException("TransitiotioningContentControl_IsTransitioningReadOnly");
            }
        }
        #endregion public bool IsTransitioning

        /// <summary>
        /// The storyboard that is used to transition old and new content.
        /// </summary>
        private Storyboard _currentTransition;

        /// <summary>
        /// Gets or sets the storyboard that is used to transition old and new content.
        /// </summary>
        private Storyboard CurrentTransition
        {
            get { return _currentTransition; }
            set
            {
                // decouple event
                if (_currentTransition != null)
                {
                    _currentTransition.Completed -= OnTransitionCompleted;
                }

                _currentTransition = value;

                if (_currentTransition != null)
                {
                    _currentTransition.Completed += OnTransitionCompleted;
                }
            }
        }

        #region public string Transition
        /// <summary>
        /// Gets or sets the name of the transition to use. These correspond
        /// directly to the VisualStates inside the PresentationStates group.
        /// </summary>
        public string Transition
        {
            get { return GetValue(TransitionProperty) as string; }
            set { SetValue(TransitionProperty, value); }
        }

        /// <summary>
        /// Identifies the Transition dependency property.
        /// </summary>
        public static readonly DependencyProperty TransitionProperty =
            DependencyProperty.Register(
                "Transition",
                typeof(string),
                typeof(TransitioningContentControl),
                new PropertyMetadata(DefaultTransitionState, OnTransitionPropertyChanged));

        /// <summary>
        /// TransitionProperty property changed handler.
        /// </summary>
        /// <param name="d">TransitioningContentControl that changed its Transition.</param>
        /// <param name="e">Event arguments.</param>
        private static void OnTransitionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TransitioningContentControl source = (TransitioningContentControl)d;
            string oldTransition = e.OldValue as string;
            string newTransition = e.NewValue as string;

            if (source.IsTransitioning)
            {
                source.AbortTransition();
            }

            // find new transition
            Storyboard newStoryboard = source.GetStoryboard(newTransition);

            // unable to find the transition.
            if (newStoryboard == null)
            {
                // could be during initialization of xaml that presentationgroups was not yet defined
                if (VisualStates.TryGetVisualStateGroup(source, PresentationGroup) == null)
                {
                    // will delay check
                    source.CurrentTransition = null;
                }
                else
                {
                    // revert to old value
                    source.SetValue(TransitionProperty, oldTransition);

                    throw new ArgumentException(
                       "TransitioningContentControl_TransitionNotFound");
                }
            }
            else
            {
                source.CurrentTransition = newStoryboard;
            }
        }
        #endregion public string Transition

        #region public bool RestartTransitionOnContentChange
        /// <summary>
        /// Gets or sets a value indicating whether the current transition
        /// will be aborted when setting new content during a transition.
        /// </summary>
        public bool RestartTransitionOnContentChange
        {
            get { return (bool)GetValue(RestartTransitionOnContentChangeProperty); }
            set { SetValue(RestartTransitionOnContentChangeProperty, value); }
        }

        /// <summary>
        /// Identifies the RestartTransitionOnContentChange dependency property.
        /// </summary>
        public static readonly DependencyProperty RestartTransitionOnContentChangeProperty =
            DependencyProperty.Register(
                "RestartTransitionOnContentChange",
                typeof(bool),
                typeof(TransitioningContentControl),
                new PropertyMetadata(false, OnRestartTransitionOnContentChangePropertyChanged));

        /// <summary>
        /// RestartTransitionOnContentChangeProperty property changed handler.
        /// </summary>
        /// <param name="d">TransitioningContentControl that changed its RestartTransitionOnContentChange.</param>
        /// <param name="e">Event arguments.</param>
        private static void OnRestartTransitionOnContentChangePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((TransitioningContentControl)d).OnRestartTransitionOnContentChangeChanged((bool)e.OldValue, (bool)e.NewValue);
        }

        /// <summary>
        /// Called when the RestartTransitionOnContentChangeProperty changes.
        /// </summary>
        /// <param name="oldValue">The old value of RestartTransitionOnContentChange.</param>
        /// <param name="newValue">The new value of RestartTransitionOnContentChange.</param>
        protected virtual void OnRestartTransitionOnContentChangeChanged(bool oldValue, bool newValue)
        {
        }
        #endregion public bool RestartTransitionOnContentChange

        #region Events
        /// <summary>
        /// Occurs when the current transition has completed.
        /// </summary>
        public event RoutedEventHandler TransitionCompleted;
        #endregion Events

        /// <summary>
        /// Initializes a new instance of the <see cref="TransitioningContentControl"/> class.
        /// </summary>
        public TransitioningContentControl()
        {
            DefaultStyleKey = typeof(TransitioningContentControl);
        }

        /// <summary>
        /// Builds the visual tree for the TransitioningContentControl control 
        /// when a new template is applied.
        /// </summary>
        public override void OnApplyTemplate()
        {
            if (IsTransitioning)
            {
                AbortTransition();
            }

            base.OnApplyTemplate();

            PreviousContentPresentationSite = GetTemplateChild(PreviousContentPresentationSitePartName) as ContentPresenter;
            CurrentContentPresentationSite = GetTemplateChild(CurrentContentPresentationSitePartName) as ContentPresenter;

            if (CurrentContentPresentationSite != null)
            {
                CurrentContentPresentationSite.Content = Content;
            }

            // hookup currenttransition
            Storyboard transition = GetStoryboard(Transition);
            CurrentTransition = transition;
            if (transition == null)
            {
                string invalidTransition = Transition;
                // revert to default
                Transition = DefaultTransitionState;

                throw new ArgumentException(
                    "TransitioningContentControl_TransitionNotFound");
            }

            VisualStateManager.GoToState(this, NormalState, false);
            VisualStateManager.GoToState(this, Transition, true);
        }

        /// <summary>
        /// Called when the value of the <see cref="P:System.Windows.Controls.ContentControl.Content"/> property changes.
        /// </summary>
        /// <param name="oldContent">The old value of the <see cref="P:System.Windows.Controls.ContentControl.Content"/> property.</param>
        /// <param name="newContent">The new value of the <see cref="P:System.Windows.Controls.ContentControl.Content"/> property.</param>
        protected override void OnContentChanged(object oldContent, object newContent)
        {
            base.OnContentChanged(oldContent, newContent);

            StartTransition(oldContent, newContent);
        }

        /// <summary>
        /// Starts the transition.
        /// </summary>
        /// <param name="oldContent">The old content.</param>
        /// <param name="newContent">The new content.</param>
        [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "newContent", Justification = "Should be used in the future.")]
        private void StartTransition(object oldContent, object newContent)
        {
            // both presenters must be available, otherwise a transition is useless.
            if (CurrentContentPresentationSite != null && PreviousContentPresentationSite != null)
            {
                CurrentContentPresentationSite.Content = newContent;

                PreviousContentPresentationSite.Content = oldContent;

                // and start a new transition
                if (!IsTransitioning || RestartTransitionOnContentChange)
                {
                    IsTransitioning = true;
                    VisualStateManager.GoToState(this, NormalState, false);
                    VisualStateManager.GoToState(this, Transition, true);
                }
            }
        }

        /// <summary>
        /// Handles the Completed event of the transition storyboard.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void OnTransitionCompleted(object sender, EventArgs e)
        {
            AbortTransition();

            RoutedEventHandler handler = TransitionCompleted;
            if (handler != null)
            {
                handler(this, new RoutedEventArgs());
            }
        }

        /// <summary>
        /// Aborts the transition and releases the previous content.
        /// </summary>
        public void AbortTransition()
        {
            // go to normal state and release our hold on the old content.
            VisualStateManager.GoToState(this, NormalState, false);
            IsTransitioning = false;
            if (PreviousContentPresentationSite != null)
            {
                PreviousContentPresentationSite.Content = null;
            }
        }

        /// <summary>
        /// Attempts to find a storyboard that matches the newTransition name.
        /// </summary>
        /// <param name="newTransition">The new transition.</param>
        /// <returns>A storyboard or null, if no storyboard was found.</returns>
        private Storyboard GetStoryboard(string newTransition)
        {
            VisualStateGroup presentationGroup = VisualStates.TryGetVisualStateGroup(this, PresentationGroup);
            Storyboard newStoryboard = null;
            if (presentationGroup != null)
            {
                newStoryboard = presentationGroup.States
                    .OfType<VisualState>()
                    .Where(state => state.Name == newTransition)
                    .Select(state => state.Storyboard)
                    .FirstOrDefault();
            }
            return newStoryboard;
        }


    }
}

 

 5. CustomWindow

     此处原来有关于CustomWindow的一些注释,但是经验证,注释有误,故贴代码时将注释删除了。

using System; 
using System.Windows; 
using System.Windows.Input; 

namespace stonemqy.CustomWindow.Main
{
    public class CustomWindow : Window
    {
        public CustomWindow()
        {
            DefaultStyleKey = typeof(CustomWindow);
            CommandBindings.Add(new CommandBinding(SystemCommands.CloseWindowCommand, CloseWindow));
            CommandBindings.Add(new CommandBinding(SystemCommands.MaximizeWindowCommand, MaximizeWindow, CanResizeWindow));
            CommandBindings.Add(new CommandBinding(SystemCommands.MinimizeWindowCommand, MinimizeWindow, CanMinimizeWindow));
            CommandBindings.Add(new CommandBinding(SystemCommands.RestoreWindowCommand, RestoreWindow, CanResizeWindow));
            CommandBindings.Add(new CommandBinding(SystemCommands.ShowSystemMenuCommand, ShowSystemMenu));
        }

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonDown(e);
            if (e.ButtonState == MouseButtonState.Pressed)
                DragMove();
        }

        protected override void OnContentRendered(EventArgs e)
        {
            base.OnContentRendered(e);
            if (SizeToContent == SizeToContent.WidthAndHeight)
                InvalidateMeasure();
        }

        #region Window Commands

        private void CanResizeWindow(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = ResizeMode == ResizeMode.CanResize || ResizeMode == ResizeMode.CanResizeWithGrip;
        }

        private void CanMinimizeWindow(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = ResizeMode != ResizeMode.NoResize;
        }

        private void CloseWindow(object sender, ExecutedRoutedEventArgs e)
        {
            this.Close();
            //SystemCommands.CloseWindow(this);
        }

        private void MaximizeWindow(object sender, ExecutedRoutedEventArgs e)
        {
            SystemCommands.MaximizeWindow(this);
        }

        private void MinimizeWindow(object sender, ExecutedRoutedEventArgs e)
        {
            SystemCommands.MinimizeWindow(this);
        }

        private void RestoreWindow(object sender, ExecutedRoutedEventArgs e)
        {
            SystemCommands.RestoreWindow(this);
        }


        private void ShowSystemMenu(object sender, ExecutedRoutedEventArgs e)
        {
            var element = e.OriginalSource as FrameworkElement;
            if (element == null)
                return;

            var point = WindowState == WindowState.Maximized ? new Point(0, element.ActualHeight)
                : new Point(Left + BorderThickness.Left, element.ActualHeight + Top + BorderThickness.Top);
            point = element.TransformToAncestor(this).Transform(point);
            SystemCommands.ShowSystemMenu(this, point);
        }

        #endregion
    }
}

6. Generic.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:stonemqy.CustomWindow.Main"
                    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">


    <DataTemplate x:Key="RestoreWhite">
        <Grid UseLayoutRounding="True"
              RenderTransform="1,0,0,1,.5,.5">
            <Path Data="M2,0 L8,0 L8,6 M0,3 L6,3 M0,2 L6,2 L6,8 L0,8 Z"
                  Width="8"
                  Height="8"
                  VerticalAlignment="Center"
                  HorizontalAlignment="Center"
                  Stroke="White"
                  StrokeThickness="1" />
        </Grid>
    </DataTemplate>

    <DataTemplate x:Key="CloseWhite">
        <Grid Margin="1,0,0,0">

            <Rectangle Stroke="White"
                       Height="2"
                       RenderTransformOrigin="0.5,0.5"
                       Width="11"
                       UseLayoutRounding="True">
                <Rectangle.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform />
                        <SkewTransform />
                        <RotateTransform Angle="45" />
                        <TranslateTransform />
                    </TransformGroup>
                </Rectangle.RenderTransform>
            </Rectangle>
            <Rectangle Stroke="White"
                       Height="2"
                       RenderTransformOrigin="0.5,0.5"
                       Width="11"
                       UseLayoutRounding="True">
                <Rectangle.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform />
                        <SkewTransform />
                        <RotateTransform Angle="-45" />
                        <TranslateTransform />
                    </TransformGroup>
                </Rectangle.RenderTransform>
            </Rectangle>
        </Grid>
    </DataTemplate>

    <DataTemplate x:Key="MaximizeWhite">
        <Grid>
            <Path Data="M0,1 L9,1 L9,8 L0,8 Z"
                  Width="9"
                  Height="8"
                  Margin="0,2,0,0"
                  VerticalAlignment="Center"
                  HorizontalAlignment="Center"
                  Stroke="White"
                  StrokeThickness="2" />
        </Grid>
    </DataTemplate>

    <DataTemplate x:Key="MinimizeWhite">
        <Grid>
            <Path Data="M0,6 L8,6 Z"
                  Width="8"
                  Height="7"
                  VerticalAlignment="Center"
                  HorizontalAlignment="Center"
                  Stroke="White"
                  StrokeThickness="2" />
        </Grid>
    </DataTemplate>



    <Style x:Key="TitleBarButtonFocusVisual">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Rectangle Margin="2"
                               SnapsToDevicePixels="True"
                               Stroke="Transparent"
                               StrokeDashArray="1 2"
                               StrokeThickness="1" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style x:Key="TitleBarButtonStyle"
           TargetType="{x:Type Button}">
        <Setter Property="Focusable"
                Value="False" />
        <Setter Property="Background"
                Value="Transparent" />
        <Setter Property="BorderBrush"
                Value="Transparent" />
        <Setter Property="BorderThickness"
                Value="1" />
        <Setter Property="HorizontalContentAlignment"
                Value="Center" />
        <Setter Property="VerticalContentAlignment"
                Value="Center" />
        <Setter Property="Padding"
                Value="1" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid x:Name="LayoutRoot">
                        <Rectangle x:Name="ButtonBackground"
                                   Width="28"
                                   Height="28"
                                   Fill="#FFFFFFFF"
                                   Opacity="0" />
                        <Border x:Name="ButtonBorder"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Background="{TemplateBinding Background}"
                                SnapsToDevicePixels="true">
                            <ContentPresenter x:Name="TitleBarButtonContentPresenter"
                                              Focusable="False"
                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              Margin="{TemplateBinding Padding}"
                                              RecognizesAccessKey="True"
                                              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                        </Border>
                    </Grid>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver"
                                 Value="true">
                            <Setter Property="Opacity"
                                    Value="0.2"
                                    TargetName="ButtonBackground" />
                        </Trigger>
                        <Trigger Property="IsPressed"
                                 Value="True">
                            <Setter Property="Opacity"
                                    Value="0.4"
                                    TargetName="ButtonBackground" />
                        </Trigger>
                        <Trigger Property="IsEnabled"
                                 Value="false">
                            <Setter TargetName="TitleBarButtonContentPresenter"
                                    Property="Opacity"
                                    Value=".5" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <!--<Style TargetType="{x:Type local:OmecWindow}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:OmecWindow}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>-->



    <Style TargetType="{x:Type local:CustomWindow}">
        <Setter Property="Foreground"
                Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}" />
        <Setter Property="Background"
                Value="#FFF1F1F1" />
        <Setter Property="BorderBrush"
                Value="#FF0874AA" />
        <Setter Property="BorderThickness"
                Value="1" />
        <Setter Property="IsTabStop"
                Value="False" />
        <Setter Property="ResizeMode"
                Value="CanResizeWithGrip" />
        <Setter Property="UseLayoutRounding"
                Value="True" />
        <Setter Property="TextOptions.TextFormattingMode"
                Value="Display" />
        <Setter Property="WindowStyle"
                Value="SingleBorderWindow" />
        <Setter Property="FontFamily"
                Value="Segoe UI" />
        <Setter Property="WindowChrome.WindowChrome">
            <Setter.Value>
                <WindowChrome CornerRadius="0"
                              GlassFrameThickness="1"
                              UseAeroCaptionButtons="False"
                              NonClientFrameEdges="None" />
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:CustomWindow}">


                    <Border BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            x:Name="WindowBorder">
                        <Grid x:Name="LayoutRoot"
                              Background="{TemplateBinding Background}">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="*" />
                            </Grid.RowDefinitions>

                            <Grid x:Name="PART_WindowTitleGrid"
                                  Grid.Row="0"
                                  Height="26.4"
                                  Background="{TemplateBinding BorderBrush}">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="Auto" />
                                </Grid.ColumnDefinitions>
                                <StackPanel Orientation="Horizontal">
                                    <!--<Image Source="{TemplateBinding Icon}"
                                           Margin="7,0,5,0"
                                           VerticalAlignment="Center"
                                          />-->
                                    <Button VerticalAlignment="Center"
                                            Margin="7,0,5,0"
                                            Content="{TemplateBinding Icon}"
                                            Height="{x:Static SystemParameters.SmallIconHeight}"
                                            Width="{x:Static SystemParameters.SmallIconWidth}"
                                            WindowChrome.IsHitTestVisibleInChrome="True"
                                            IsTabStop="False">
                                        <Button.Template>
                                            <ControlTemplate TargetType="{x:Type Button}">
                                                <Image Source="{TemplateBinding Content}" />
                                            </ControlTemplate>
                                        </Button.Template>
                                        <i:Interaction.Triggers>
                                            <i:EventTrigger EventName="Click">
                                                <i:InvokeCommandAction Command="{x:Static SystemCommands.ShowSystemMenuCommand}" />
                                            </i:EventTrigger>
                                            <i:EventTrigger EventName="MouseDoubleClick">
                                                <i:InvokeCommandAction Command="{x:Static SystemCommands.CloseWindowCommand}" />
                                            </i:EventTrigger>
                                        </i:Interaction.Triggers>
                                    </Button>
                                    <ContentControl IsTabStop="False"
                                                    Foreground="White"
                                                    HorizontalAlignment="Center"
                                                    VerticalAlignment="Center"
                                                    FontSize="{DynamicResource {x:Static SystemFonts.CaptionFontSize}}"
                                                    Content="{TemplateBinding Title}" />
                                </StackPanel>
                                <StackPanel x:Name="WindowCommandButtonsStackPanel"
                                            Grid.Column="1"
                                            HorizontalAlignment="Right"
                                            VerticalAlignment="Top"
                                            Background="Transparent"
                                            Orientation="Horizontal"
                                            WindowChrome.IsHitTestVisibleInChrome="True">
                                    <Button x:Name="Minimize"
                                            ToolTip="Minimize"
                                            WindowChrome.IsHitTestVisibleInChrome="True"
                                            Command="{Binding Source={x:Static SystemCommands.MinimizeWindowCommand}}"
                                            ContentTemplate="{StaticResource MinimizeWhite}"
                                            Style="{StaticResource TitleBarButtonStyle}"
                                            IsTabStop="False" />
                                    <Grid Margin="1,0,1,0">
                                        <Button x:Name="Restore"
                                                ToolTip="Restore"
                                                WindowChrome.IsHitTestVisibleInChrome="True"
                                                Command="{Binding Source={x:Static SystemCommands.RestoreWindowCommand}}"
                                                ContentTemplate="{StaticResource RestoreWhite}"
                                                Style="{StaticResource TitleBarButtonStyle}"
                                                Visibility="Collapsed"
                                                IsTabStop="False" />
                                        <Button x:Name="Maximize"
                                                ToolTip="Maximize"
                                                WindowChrome.IsHitTestVisibleInChrome="True"
                                                Command="{Binding Source={x:Static SystemCommands.MaximizeWindowCommand}}"
                                                ContentTemplate="{StaticResource MaximizeWhite}"
                                                Style="{StaticResource TitleBarButtonStyle}"
                                                IsTabStop="False" />
                                    </Grid>
                                    <Button x:Name="Close"
                                            ToolTip="Close"
                                            WindowChrome.IsHitTestVisibleInChrome="True"
                                            Command="{Binding Source={x:Static SystemCommands.CloseWindowCommand}}"
                                            ContentTemplate="{StaticResource CloseWhite}"
                                            Style="{StaticResource TitleBarButtonStyle}"
                                            IsTabStop="False" />
                                </StackPanel>
                            </Grid>
                            <AdornerDecorator Grid.Row="1" KeyboardNavigation.IsTabStop="False">
                                <!--<ContentPresenter x:Name="MainContentPresenter"
                                                  KeyboardNavigation.TabNavigation="Cycle" />-->
                                <local:TransitioningContentControl Content="{TemplateBinding Content}"
                                                                   x:Name="MainContentPresenter"
                                                                
                                                                   KeyboardNavigation.TabNavigation="Cycle" />
                            </AdornerDecorator>
                            <ResizeGrip x:Name="ResizeGrip"
                                        HorizontalAlignment="Right"
                                        VerticalAlignment="Bottom"
                                        Grid.Row="1"
                                        IsTabStop="False"
                                        Visibility="Hidden"
                                        WindowChrome.ResizeGripDirection="BottomRight" />
                        </Grid>
                    </Border>


                    <ControlTemplate.Triggers>
                        <Trigger Property="IsActive"
                                 Value="False">
                            <Setter Property="BorderBrush"
                                    Value="#FF6F7785" />
                        </Trigger>
                        <Trigger Property="WindowState"
                                 Value="Maximized">
                            <Setter TargetName="Maximize"
                                    Property="Visibility"
                                    Value="Collapsed" />
                            <Setter TargetName="Restore"
                                    Property="Visibility"
                                    Value="Visible" />
                            <Setter TargetName="LayoutRoot"
                                    Property="Margin"
                                    Value="7" />
                        </Trigger>
                        <Trigger Property="WindowState"
                                 Value="Normal">
                            <Setter TargetName="Maximize"
                                    Property="Visibility"
                                    Value="Visible" />
                            <Setter TargetName="Restore"
                                    Property="Visibility"
                                    Value="Collapsed" />
                        </Trigger>
                        <Trigger Property="ResizeMode"
                                 Value="NoResize">
                            <Setter TargetName="Minimize"
                                    Property="Visibility"
                                    Value="Collapsed" />
                            <Setter TargetName="Maximize"
                                    Property="Visibility"
                                    Value="Collapsed" />
                            <Setter TargetName="Restore"
                                    Property="Visibility"
                                    Value="Collapsed" />
                        </Trigger>

                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="ResizeMode"
                                           Value="CanResizeWithGrip" />
                                <Condition Property="WindowState"
                                           Value="Normal" />
                            </MultiTrigger.Conditions>
                            <Setter TargetName="ResizeGrip"
                                    Property="Visibility"
                                    Value="Visible" />
                        </MultiTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>

    </Style>



    <Style TargetType="local:TransitioningContentControl">
        <Setter Property="IsTabStop"
                Value="False" />
        <Setter Property="HorizontalContentAlignment"
                Value="Stretch" />
        <Setter Property="VerticalContentAlignment"
                Value="Stretch" />
        <Setter Property="Transition"
                Value="DefaultTransition" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:TransitioningContentControl">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            CornerRadius="2">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="PresentationStates">
                                <VisualState x:Name="DefaultTransition">
                                    <Storyboard>
                                        <!--<DoubleAnimationUsingKeyFrames 
                                            BeginTime="00:00:00" 
                                            Storyboard.TargetName="CurrentContentPresentationSite"
                                            Storyboard.TargetProperty="(UIElement.Opacity)">
                                            <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
                                            <SplineDoubleKeyFrame KeyTime="00:00:00.300" Value="1"/>
                                        </DoubleAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames
                                            BeginTime="00:00:00" 
                                            Storyboard.TargetName="PreviousContentPresentationSite" 
                                            Storyboard.TargetProperty="(UIElement.Opacity)">
                                            <SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
                                            <SplineDoubleKeyFrame KeyTime="00:00:00.300" Value="0"/>
                                        </DoubleAnimationUsingKeyFrames>-->
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                                                       Storyboard.TargetName="CurrentContentPresentationSite"
                                                                       Storyboard.TargetProperty="(UIElement.Opacity)">
                                            <SplineDoubleKeyFrame KeyTime="00:00:00"
                                                                  Value="0" />
                                            <SplineDoubleKeyFrame KeyTime="00:00:00.400"
                                                                  Value="1" />
                                        </DoubleAnimationUsingKeyFrames>

                                        <DoubleAnimation BeginTime="00:00:00"
                                                         Duration="00:00:00.500"
                                                         Storyboard.TargetName="CurrentContentPresentationSite"
                                                         Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"
                                                         From="50"
                                                         To="0">
                                            <DoubleAnimation.EasingFunction>
                                                <CubicEase EasingMode="EaseOut" />
                                            </DoubleAnimation.EasingFunction>
                                        </DoubleAnimation>

                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                                                       Storyboard.TargetName="PreviousContentPresentationSite"
                                                                       Storyboard.TargetProperty="(UIElement.Opacity)">
                                            <SplineDoubleKeyFrame KeyTime="00:00:00"
                                                                  Value="1" />
                                            <SplineDoubleKeyFrame KeyTime="00:00:00.100"
                                                                  Value="0" />
                                        </DoubleAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Normal">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames BeginTime="00:00:00"
                                                                       Storyboard.TargetName="PreviousContentPresentationSite"
                                                                       Storyboard.TargetProperty="(UIElement.Visibility)">
                                            <DiscreteObjectKeyFrame KeyTime="00:00:00">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Collapsed</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>

                                <VisualState x:Name="UpTransition">
                                    <Storyboard>
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                                                       Storyboard.TargetName="CurrentContentPresentationSite"
                                                                       Storyboard.TargetProperty="(UIElement.Opacity)">
                                            <SplineDoubleKeyFrame KeyTime="00:00:00"
                                                                  Value="0" />
                                            <SplineDoubleKeyFrame KeyTime="00:00:00.300"
                                                                  Value="1" />
                                        </DoubleAnimationUsingKeyFrames>

                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                                                       Storyboard.TargetName="CurrentContentPresentationSite"
                                                                       Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">
                                            <SplineDoubleKeyFrame KeyTime="00:00:00"
                                                                  Value="30" />
                                            <SplineDoubleKeyFrame KeyTime="00:00:00.300"
                                                                  Value="0" />
                                        </DoubleAnimationUsingKeyFrames>

                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                                                       Storyboard.TargetName="PreviousContentPresentationSite"
                                                                       Storyboard.TargetProperty="(UIElement.Opacity)">
                                            <SplineDoubleKeyFrame KeyTime="00:00:00"
                                                                  Value="1" />
                                            <SplineDoubleKeyFrame KeyTime="00:00:00.300"
                                                                  Value="0" />
                                        </DoubleAnimationUsingKeyFrames>

                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                                                       Storyboard.TargetName="PreviousContentPresentationSite"
                                                                       Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">
                                            <SplineDoubleKeyFrame KeyTime="00:00:00"
                                                                  Value="0" />
                                            <SplineDoubleKeyFrame KeyTime="00:00:00.300"
                                                                  Value="-30" />
                                        </DoubleAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>

                                <VisualState x:Name="DownTransition">
                                    <Storyboard>
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                                                       Storyboard.TargetName="CurrentContentPresentationSite"
                                                                       Storyboard.TargetProperty="(UIElement.Opacity)">
                                            <SplineDoubleKeyFrame KeyTime="00:00:00"
                                                                  Value="0" />
                                            <SplineDoubleKeyFrame KeyTime="00:00:00.300"
                                                                  Value="1" />
                                        </DoubleAnimationUsingKeyFrames>

                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                                                       Storyboard.TargetName="CurrentContentPresentationSite"
                                                                       Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">
                                            <SplineDoubleKeyFrame KeyTime="00:00:00"
                                                                  Value="-40" />
                                            <SplineDoubleKeyFrame KeyTime="00:00:00.300"
                                                                  Value="0" />
                                        </DoubleAnimationUsingKeyFrames>

                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                                                       Storyboard.TargetName="PreviousContentPresentationSite"
                                                                       Storyboard.TargetProperty="(UIElement.Opacity)">
                                            <SplineDoubleKeyFrame KeyTime="00:00:00"
                                                                  Value="1" />
                                            <SplineDoubleKeyFrame KeyTime="00:00:00.300"
                                                                  Value="0" />
                                        </DoubleAnimationUsingKeyFrames>

                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                                                       Storyboard.TargetName="PreviousContentPresentationSite"
                                                                       Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">
                                            <SplineDoubleKeyFrame KeyTime="00:00:00"
                                                                  Value="0" />
                                            <SplineDoubleKeyFrame KeyTime="00:00:00.300"
                                                                  Value="40" />
                                        </DoubleAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>

                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>

                        <Grid>
                            <ContentPresenter x:Name="PreviousContentPresentationSite"
                                              Content="{x:Null}"
                                              ContentTemplate="{TemplateBinding ContentTemplate}"
                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
                                <ContentPresenter.RenderTransform>
                                    <TransformGroup>
                                        <ScaleTransform />
                                        <SkewTransform />
                                        <RotateTransform />
                                        <TranslateTransform />
                                    </TransformGroup>
                                </ContentPresenter.RenderTransform>
                            </ContentPresenter>

                            <ContentPresenter x:Name="CurrentContentPresentationSite"
                                              Content="{x:Null}"
                                              ContentTemplate="{TemplateBinding ContentTemplate}"
                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
                                <ContentPresenter.RenderTransform>
                                    <TransformGroup>
                                        <ScaleTransform />
                                        <SkewTransform />
                                        <RotateTransform />
                                        <TranslateTransform />
                                    </TransformGroup>
                                </ContentPresenter.RenderTransform>
                            </ContentPresenter>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

7. MainWindow.xaml

<local:CustomWindow x:Class="stonemqy.CustomWindow.Main.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:stonemqy.CustomWindow.Main"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        
    </Grid>
</local:CustomWindow>

8. MainWindow.cs

namespace stonemqy.CustomWindow.Main
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : CustomWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

9. 运行效果

10. 项目代码

源码

posted on 2018-01-11 15:56 stonemqy 阅读(...) 评论(...) 编辑 收藏