《Programming WPF》翻译 第8章 3.Storyboard

简介: 原文:《Programming WPF》翻译 第8章 3.StoryboardStoryboard是动画的集合。如果你使用了标记,所有的动画必须要被定义在一个Storyboard中。(在代码中创建隔离的动画对象,这是可能的,参见本章后面部分。
原文: 《Programming WPF》翻译 第8章 3.Storyboard

Storyboard是动画的集合。如果你使用了标记,所有的动画必须要被定义在一个Storyboard中。(在代码中创建隔离的动画对象,这是可能的,参见本章后面部分。)一个动画的结构通常是不同于设置了动画的UI的结构上。例如,你可能想要来两个单独的用户界面元素在同一时间被设置动画。因为Storyboard将动画从有动画效果的对象中隔离出来,Storyboard是自由地反射这样的连接,即使这些元素被设置了对象,可能被定义在完全不同的文件部分中。

示例8-15显示了包含了两个椭圆的用户界面的标记。

示例8-15

< Window  Text ="Two Animations"  Width ="420"  Height ="150"
    xmlns
="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x
="http://schemas.microsoft.com/winfx/xaml/2005" >

    
< Window.Storyboards >
        
< ParallelTimeline >
            
< SetterTimeline  TargetName ="myEllipse"  Path ="(Ellipse.Width)" >
                
< DoubleAnimation  From ="10"  To ="300"  Duration ="0:0:5"
                                 RepeatBehavior
="Forever"   />
            
</ SetterTimeline >
            
< SetterTimeline  TargetName ="myOtherEllipse"  Path ="(Ellipse.Width)" >
                
< DoubleAnimation  From ="300"  To ="10"  Duration ="0:0:5"
                                 RepeatBehavior
="Forever"   />
            
</ SetterTimeline >
        
</ ParallelTimeline >
    
</ Window.Storyboards >

    
< StackPanel  Orientation ="Horizontal" >
        
< Ellipse  x:Name ="myEllipse"  Height ="100"  Fill ="Red"   />
        
< TextBlock > This is some text </ TextBlock >
        
< Ellipse  x:Name ="myOtherEllipse"  Height ="100"  Fill ="Blue"   />
    
</ StackPanel >
</ Window >

这些椭圆是互不邻近的,但是它们的宽度都以异步的方式设置了动画。这种异步被反射在

Storyboard 的结构中:这两个动画都是内嵌在同样的ParallelTimeline 元素中,指出了这些动画都在相同的时间运行。一个从10 300 的动画,另一个是从300 10 ,因此StackPanel 中这三项的总宽度保持为恒定的。

Storyboard必须运行以三种位置中的一种。它们可以放置在Style中、ContentTemplate中、或者顶级元素中。顶级元素是WindowPage,或者派生于此的类。

所有的用户界面元素都有一个Storyboard属性,继承于基类型FrameworkElement。你可能想这意味着你可以添加一个Storyboard到任意一个元素。这于当前是不被支持的。Storyboard只会工作于:Style中、ContentTemplate中、或者顶级元素中。

把动画放入样式的Storyboard中的能力,使你通过样式系统应用动画。这可是很有用的——如果你想使用同样的动画在很多地方。通过把动画放入样式,而不是一个WindowPage,你要避免复制和排除次要矛盾的可能性。示例8-16显示了带有Storyboard的一个样式。

示例8-16

< Window  Text ="StyleAnimations"  Width ="220"  Height ="200"
    xmlns
="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x
="http://schemas.microsoft.com/winfx/xaml/2005" >

    
< Window.Resources >
        
< Style  TargetType =" {x:Type Button} " >
            
< Setter  Property ="Height"  Value ="25"   />
            
< Setter  Property ="Background"  Value ="Green"   />

            
< Style.Storyboards >
                
< SetterTimeline
                        
Path ="(Button.Background).(SolidColorBrush.Color)" >
                    
< ColorAnimation  To ="LimeGreen"  Duration ="0:0:0.3"
                        AutoReverse
="True"  RepeatBehavior ="Forever"   />
                
</ SetterTimeline >
                
< ParallelTimeline  RepeatBehavior ="Forever"  Duration ="0:0:2" >
                    
< SetterTimeline  Path ="(Button.Width)" >
                        
< DoubleAnimation  From ="80"  To ="90"  Duration ="0:0:0.1"
                                         AutoReverse
="True"   />
                    
</ SetterTimeline >
                    
< SetterTimeline  Path ="(Button.Height)"
                                    BeginTime
="0:0:0.4" >
                        
< DoubleAnimation  By ="30"  Duration ="0:0:0.5"
                                         AutoReverse
="True" />
                    
</ SetterTimeline >
                
</ ParallelTimeline >
            
</ Style.Storyboards >
        
</ Style >
    
</ Window.Resources >

    
< StackPanel  Orientation ="Vertical" >
        
< Button  HorizontalAlignment ="Center" > Click me! </ Button >
        
< Button  HorizontalAlignment ="Center" > No, click me! </ Button >
    
</ StackPanel >

</ Window >

这些动画并没有做什么显著不寻常的事情。它们只是改变了一对按钮的大小和颜色,正如图

8-8 所示。可是,注意到SetterTimeline 元素并没有详细指出TargetName 。这是因为使用一个样式Storyboard ,这里有一个隐式的目标:该样式应用到的元素(这种情形下是一个Button )。同样,如图8-8 所示,因为这是一个样式,它定义的动画应用到所有的按钮。

8-8


如果你为控件定义了一个模板,它可能包含了——没有直接响应到元素可你又想设置动画的属性——的样式,例如,图
8-9显示了两对按钮。在顶行,这些按钮显示为自定义的可视化——带有圆形的静态外观。底部按钮是相似的,但是一个放射性的填充被添加到按钮中,并含有一个内部的光源。我们可能想为这个光源设置动画,使这个按钮逐渐地跳动。

8-9


这个按钮的类型并没有提供我们用来表示光源颜色的属性,因此为了给这个光源设置动画,这个动画需要为控件模板中详细指定的元素设置目标。在这种情形中,我们可以把动画放入模板的
Storyboard中,而不是样式的Storyboard中。如果你设置了x:Name属性在模板中相应的元素上,你可以接着在动画中用TargetName引用它。示例8-17显示了图8-9的标记。

示例8-17

< Window  xmlns ="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x
="http://schemas.microsoft.com/winfx/xaml/2005"
    Text
="Style VisualTree Animation"  Width ="400"  Height ="150"
    
>

    
< Window.Resources >
        
< Style  TargetType =" {x:Type Button} " >
            
< Setter  Property ="Background"  Value ="CornflowerBlue"   />
            
< Setter  Property ="Height"  Value ="26"   />
            
< Setter  Property ="Template" >
                
< Setter.Value >

                    
< ControlTemplate  TargetType =" {x:Type Button} " >
                        
< Grid  Height =" {TemplateBinding Height} " >
                            
< RowDefinition  Height ="1.8*"   />
                            
< RowDefinition  Height ="*"   />

                            
< Rectangle  Grid.RowSpan ="2"  RadiusX ="13"  RadiusY ="13"
                                       Fill
=" {TemplateBinding Background} "
                                       Stroke
="VerticalGradient Black LightGray"   />


                            
<!--  Glow  -->

                            
< Rectangle  Grid.RowSpan ="2"  RadiusX ="13"  RadiusY ="13"
                                       x:Name
="glow" >
                                
< Rectangle.Fill >
                                    
< RadialGradientBrush  Center ="0.5, 1"
                                             RadiusX
="0.7"  RadiusY ="0.8" >
                                        
< RadialGradientBrush.GradientStops >
                                            
< GradientStop  Offset ="0"
                                                          Color
="White"   />
                                            
< GradientStop  Offset ="1"
                                                          Color
="Transparent"   />
                                        
</ RadialGradientBrush.GradientStops >
                                    
</ RadialGradientBrush >
                                
</ Rectangle.Fill >
                            
</ Rectangle >


                            
< Rectangle  Margin ="3,1.1"  RadiusX ="11"  RadiusY ="12"
                                       Fill
="VerticalGradient #dfff #0fff"   />
                            
< ContentPresenter  Grid.RowSpan ="3"  Margin ="13,2,13,4"
                                              HorizontalAlignment
="Center"
                                              VerticalAlignment
="Center"   />

                        
</ Grid >

                        
< ControlTemplate.Storyboards >
                            
< SetterTimeline  TargetName ="glow"
Path
="(Rectangle.Fill).(LinearGradientBrush.GradientStops)[0].(GradientStop.Color)" >

                                
< ColorAnimation  From ="#1fff"  To ="#cfff"
                                    Duration
="0:0:1"
                                    AutoReverse
="True"  RepeatBehavior ="Forever"
                                    AccelerationRatio
="0.4"
                                    DecelerationRatio
="0.6" />
                            
</ SetterTimeline >
                        
</ ControlTemplate.Storyboards >
                    
</ ControlTemplate >
                
</ Setter.Value >
            
</ Setter >

        
</ Style >
    
</ Window.Resources >

    
< StackPanel  VerticalAlignment ="Center"
                Orientation
="Horizontal" >
        
< Button  Margin ="4,0" > Click me! </ Button >
        
< Button  Background ="DarkRed"  Foreground ="White" > And me! </ Button >
    
</ StackPanel >

</ Window >

大多数模板是静态的,但是光源被设置了动画。注意到

x:Name 属性带有一个glow 值在相关的形状上。这个动画在模板的Storyboard 中,正如你希望的,它将包括一个单独的SetterTimeline ,带有一个被设置为glow TargetName 。这个Path 有点复杂,简单的因为我们为一个特定的带有笔刷的GradientStop 设定动画。记住轻量级对象——如笔刷或者梯度停止,不能被直接设置动画。替代的,我们不得不生成相应的完整的UI 元素。动画设置目标同时使用Path 属性来向下导航到我们希望改动的属性。

这个特定的Path引进了一个我们之前没有看到过的新样式:[0]。这个[index]语法用于指出一个项在集合的一个特定的偏移位置。

正如我们在第五章看到的,样式和模板都可以定义触发器以允许属性被设置为自动依照某一个刺激。例如,你可以触发任何Storyboard中的动画——当一个特定的事件发生时。

示例8-18为一个按钮显示了一个样式,带有一个简单的模板——仅绘制了一个矩形在按钮内容的周围。这个模板的Storyboard包含了两个动画。第一个退变颜色到PeachPuff,然会再返回来,另一个则在矩形轮廓的厚度上振荡。注意到,这两个按钮都有一个设置为{x:Null}BeginTime。这防止了在应用程序开始的时候这些按钮会自动运行动画。

示例8-18

< Style  TargetType =" {x:Type Button} " >
    
< Setter  Property ="Template" >
        
< Setter.Value >
            
< ControlTemplate  TargetType =" {x:Type Button} " >
                
< Grid >
                    
< Rectangle  x:Name ="mainRect"   Fill ="Aqua"  Stroke ="Blue"   />
                    
< ContentPresenter
                        
HorizontalAlignment =
                                   "
{TemplateBinding HorizontalContentAlignment} "
                        VerticalAlignment
=
                                   "
{TemplateBinding VerticalContentAlignment} "   />
                
</ Grid >

                
< ControlTemplate.Storyboards >

                    
<!--  Click animation  -->

                    
< SetterTimeline  x:Name ="clickTimeline"  BeginTime =" {x:Null} "
                                 TargetName
="mainRect"
                                 Path
="(Rectangle.Fill).(SolidColorBrush.Color)" >
                        
< ColorAnimation  To ="PeachPuff"  Duration ="0:0:0.2"
                                        AutoReverse
="True"   />
                    
</ SetterTimeline >


                    
<!--  Mouse over animation  -->

                    
< SetterTimeline  x:Name ="enterTimeline"  BeginTime =" {x:Null} "
                                    TargetName
="mainRect"  Duration ="1"
                                    Path
="(Rectangle.StrokeThickness)"   >
                        
< DoubleAnimation  To ="3"  Duration ="0:0:0.2"
                                         AutoReverse
="True"
                                         RepeatBehavior
="Forever"   />
                    
</ SetterTimeline >

                
</ ControlTemplate.Storyboards >

                
< ControlTemplate.Triggers >
                    
< EventTrigger  RoutedEvent ="ButtonBase.Click" >
                        
< EventTrigger.Actions >
                            
< BeginAction  TargetName ="clickTimeline"   />
                        
</ EventTrigger.Actions >
                    
</ EventTrigger >

                    
< EventTrigger  RoutedEvent ="Mouse.MouseEnter" >
                        
< EventTrigger.Actions >
                            
< BeginAction  TargetName ="enterTimeline"   />
                        
</ EventTrigger.Actions >
                    
</ EventTrigger >

                    
< EventTrigger  RoutedEvent ="Mouse.MouseLeave" >
                        
< EventTrigger.Actions >
                            
< StopAction  TargetName ="enterTimeline"   />
                        
</ EventTrigger.Actions >
                    
</ EventTrigger >
                
</ ControlTemplate.Triggers >

            
</ ControlTemplate >
        
</ Setter.Value >
    
</ Setter >
</ Style >

这个动画被模板中的

triggers 部分中的Eventtrigger 元素全部触发。首先会响应到这些按钮的Click 事件。(这个事件由按钮的基本类定义,这里是ButtonBase.Click 。)无论何时点击这个按钮。这将引起clickTimeline 动画的运行,使按钮退变颜色到PeachPuff 然后再回到被点击时的样子。

另一个动画有两个Eventtrigger元素,一个用于当鼠标进入控件的时候,另一个用于当鼠标离开控件的时候。这是因为线条宽度的动画会永远重复,如果这只有一个触发器,开始动画在鼠标进入控件的时候,这个动画将会开始而不会停止,由于这是一个顶级的timeline。因此我们需要1秒钟的Eventtrigger,响应到MouseLeave事件——使用StopAction来停止这个动画。

这个示例的鼠标事件命名为Mouse.MouseEnterMouse.MouseLeave。这是有一点不寻常的,当事件被命名为定义它们的元素。这些事件是继承于UIElement基类,因此你可以希望它们被命名为UIElement.MouseEnterUIElement.MouseLeave。可是,这些由UIElement提供的事件只是底层的附属事件外面的包装。底层的事件由System.Windows.Input命名空间的Mouse类定义,这是为什么事件名以Mouse.UIElement开始,简单而便利的包装了这些附属事件作为标准.NET事件。

每个Eventtrigger可以有你想要的任何事件,因此你可以一次性开始或废弃一些动画。

这通常是非常便利的使WPF自动开始和停止你的动画——在事件发生时。这就意味着你不需要写任何代码。可是,这并不总是一个适当的事件来用作触发器,因此在程序上开始一个动画,有时是很有用的。

8.3.1 使用代码加载动画

为了从代码上开始一个动画,理解timeline和时钟之间的不同是必要的。正如我们已经看到的,一个timeline层次是在一段延伸的时间内发生的一个或更多事情的描述——但这只是一个描述。timeline层次的存在,带有一个SetterTimeline和一个DoubleAnimation,并不是足够引起动画的发生。表现这个动画的工作由一个或多个时钟完成。

时钟是一个在运行期创建的对象,对timeline中的当前位置保持跟踪,执行timeline定义的无论什么动作。如果你回想到timeline图表,如图8-7,时钟就是知道我们在时间的那个位置的图表上端。

timeline和时钟的关系并不像代码和多线程的关系。可执行代码定义了要表现什么操作,但是一个线程被要求执行代码。同样的,一个timeline描述了在一段特定的时间长度发生了什么,但是一个时钟被要求运行这个timeline

WPF自动创建时钟。在创建一个用户界面的时候,它顺便访问相应的Stroyboard属性和为每个timeline创建时钟。如果一个带有storyboard的样式或模板被使用在多个地方,每个实例都有它自己的一组时钟——支持动画独立地运行。这是无妨的,否则,如果你有一个动画在鼠标进入按钮的时候运行,它会为屏幕上所有的按钮同时运行,这将不会是十分有用的。

通常,顶级timeline的时钟是自动开始的,基于他们的BeginTime。可是,如果你详细指定BeginTime{x:Null},这个时钟将不会开始,因此这个动画不会运行。我们在前面的章节看到,如何使用触发器来加载动画。触发器中的BeginAction只是告诉WPF在触发器发生时,开始相应的timeline的时钟。你也可以编写代码来开始动画。

为了亲自开始一个动画,我们需要得到它的时钟。这些代码需要找到timeline的时钟,看上去有点不同的,取决于你是否处理timeline在一个Style、一个模板、还是一个顶级元素中。

示例8-19

< Window  x:Class ="StartAnimationWithCode.Window1"
    xmlns
="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x
="http://schemas.microsoft.com/winfx/xaml/2005"
    Text
="Code"  Width ="150"  Height ="100" >

    
< Window.Storyboards >
        
< SetterTimeline  BeginTime =" {x:Null} "  TargetName ="myButton"
                x:Name
="clickTimeline"
                Path
="(Button.Background).(SolidColorBrush.Color)" >
            
< ColorAnimation  To ="Red"  Duration ="0:0:0.2"  AutoReverse ="True"   />
        
</ SetterTimeline >
    
</ Window.Storyboards >

    
< StackPanel  HorizontalAlignment ="Left"  VerticalAlignment ="Top" >
        
< Button  x:Name ="myButton"  Background ="Aqua" > Foo </ Button >
    
</ StackPanel >
</ Window >

这个动画将按钮的颜色改变为红色,而且还要返回。由于这个动画的

BeginTime 被设置为{x:Null} ,并且没有任何自动的触发器,我们需要写一些代码来运行它们。我们将这么做——通过添加一个Click 句柄到示例8-19 中的按钮。示例8-20 显示了包含这个Click 句柄的代码。

示例8-20

using  System;
using  System.Windows;
using  System.Windows.Media.Animation;

namespace  StartAnimationWithCode
{
    
public partial class Window1 : Window
    
{
        
public Window1( ) : base( )
        
{
            InitializeComponent( );

            myButton.Click 
+= ButtonClick;
        }


        
private void ButtonClick(object sender, RoutedEventArgs e)
        
{
            Clock clock;
            Timeline clickTimeline 
= FindName("clickTimeline"as Timeline;
            clock 
= this.FindStoryboardClock(clickTimeline);

            clock.ClockController.Begin( );
        }

    }

}

这个句柄获取了动画的

timeline ,接着获取它的Clock 。它使用了时钟的控制器来运行这个动画。图8-10 显示了这个运行中的动画。

8-10


如果这个动画存在于一个样式中,这段代码工作得有点不同。示例
8-21显示了带有动画的一个样式。(这个动画有和前一个示例同样的效果;它只是以一种不同的方式被应用。)

示例8-21

< Window  x:Class ="StartAnimationWithCode.StyleAnimationFromCode"
    xmlns
="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x
="http://schemas.microsoft.com/winfx/xaml/2005"
    Text
="Style"  Width ="150"  Height ="100" >

    
< Window.Resources >
        
< Style  TargetType =" {x:Type Button} " >
            
< Style.Storyboards >
                
< SetterTimeline  BeginTime =" {x:Null} "  x:Name ="clickTimeline"
                                Path
="(Button.Background).(SolidColorBrush.Color)" >
                    
< ColorAnimation  To ="Red"  Duration ="0:0:0.2"
                                    AutoReverse
="True"   />
                
</ SetterTimeline >
            
</ Style.Storyboards >
        
</ Style >
    
</ Window.Resources >

    
< Button  x:Name ="myButton"  Background ="Aqua"
            HorizontalAlignment
="Center"  VerticalAlignment ="Center" >
        Foo
    
</ Button >
</ Window >

这个

Click 句柄必须要修改,因为动画现在定义在样式中。示例8-22 显示了新的句柄。

示例8-22

private   void  ButtonClick( object  sender, RoutedEventArgs e)
{
    Clock clock;
    clock 
= Style.FindStoryboardClock(myButton, "clickTimeline");

    clock.ClockController.Begin( );
}

当然,如果样式定义了一个模板,我们可能希望直接为模板的一部分定义动画。在这种情形中,动画会存在于模板的

Stroyboard 中,而不是样式的Stroyboard 中。示例8-23 显示了包含了一个带Stroyboard 的模板的样式。

示例8-23

< Style  TargetType =" {x:Type Button} " >
    
< Setter  Property ="Template" >
        
< Setter.Value >
            
< ControlTemplate  TargetType =" {x:Type Button} " >
                
< Grid >
                    
< Rectangle  x:Name ="mainRect"   Fill ="Aqua"  Stroke ="Blue"   />
                    
< ContentPresenter  HorizontalAlignment =" {TemplateBinding
                                           HorizontalContentAlignment}
"
                                      VerticalAlignment
=" {TemplateBinding
                                           VerticalContentAlignment}
"   />
                
</ Grid >

                
< ControlTemplate.Storyboards >
                    
< SetterTimeline  BeginTime =" {x:Null} "  TargetName ="mainRect"
                              x:Name
="clickTimeline"
                              Path
="(Rectangle.Fill).(SolidColorBrush.Color)" >
                        
< ColorAnimation  To ="Red"  Duration ="0:0:0.2"
                                        AutoReverse
="True"   />
                    
</ SetterTimeline >
                
</ ControlTemplate.Storyboards >
            
</ ControlTemplate >
        
</ Setter.Value >
    
</ Setter >
</ Style >

虽然事实上,动画现在嵌入到样式模板中,而不是样式中,我们仍可以和之前同样的方式加载这个动画——使用示例

8-22 所示的代码。图8-11 显示了结果。

8-11


在所有的这些示例中,我们使用了时钟的
ClickController。这就为控制操作提供了可编程的接口,如开始、暂停、停止、倒带等等。这里我们使用了Begin——立即开始了动画。注意到我们只需要为顶级timeline开始这个时钟,子时钟将会被开始于恰当的时间,作为运行父一级的结果。


目录
相关文章
|
4月前
|
文字识别 C# 开发者
WPF开源的一款免费、开箱即用的翻译、OCR工具
WPF开源的一款免费、开箱即用的翻译、OCR工具
103 0
|
C#
【msdn wpf forum翻译】如何在wpf程序(程序激活时)中捕获所有的键盘输入,而不管哪个元素获得焦点?
原文:【msdn wpf forum翻译】如何在wpf程序(程序激活时)中捕获所有的键盘输入,而不管哪个元素获得焦点?原文链接:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/cf884a91-c135-447d-b16b-214d2d9e9972 有时有些特殊的程序需要这样处理。
975 0
|
C#
【msdn wpf forum翻译】获取当前窗口焦点所在的元素
原文:【msdn wpf forum翻译】获取当前窗口焦点所在的元素原文地址: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/6bd7a03a-f0b4-42df-a7f2-5182cf003cb0 Bialgous回答:IInputElement focusedElement = FocusManager.
965 0
|
C#
【msdn wpf forum翻译】TextBlock等类型的默认样式(implicit style)为何有时不起作用?
原文:【msdn wpf forum翻译】TextBlock等类型的默认样式(implicit style)为何有时不起作用?原文链接:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/148e95c6-6fb5-4399-8a56-4...
968 0
|
C#
【msdn wpf forum翻译】TextBox中文本 中对齐 的方法
原文:【msdn wpf forum翻译】TextBox中文本 中对齐 的方法原文链接:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/49864e35-1dbf-4292-a361-93f1a8400558 问题:TextBox中文本中对齐,使用 TextBox.HorizontalContentAlignment="Center"行不通(TextBox.VerticalContentAlignment="Center"则会起到预期的作用。
1228 0
|
C#
《Programming WPF》翻译 目录
原文:《Programming WPF》翻译 目录 注:第1、2章我只做了笔记,没有翻译,请大家阅读时注意。 还有就是,这本书的英文版本下载:[O'Reilly] Programming Windows Presentation Foundation (2005) - BBL 以下是这本书的目录: 1.
1025 0
|
C# 前端开发 API
《Programming WPF》翻译 第3章 1.什么是控件
原文:《Programming WPF》翻译 第3章 1.什么是控件 对于一个应用程序而言,控件是搭建用户界面的积木。它们具备交互式的特征,例如文本框、按钮以及列表框。尽管如此,WPF还有点不寻常,在于其并不直接地依赖其外观。
806 0
|
数据可视化 前端开发 .NET
《Programming WPF》翻译 第3章 2.处理输入
原文:《Programming WPF》翻译 第3章 2.处理输入 在Windows应用程序中,又3种基本的用户输入形式:鼠标、键盘和手写板。同时,还有一种更高级输入方式,其可能来自快捷键、工具栏的按钮、菜单项。
1177 0
|
缓存 C# 虚拟化
【翻译】WPF4.5新特性(MSDN的翻译读不太懂)
我很在意WPF的发展,有人说微软不再维护WPF了,无所谓,随他去。 MSDN上有简体版:http://msdn.microsoft.com/zh-cn/library/vstudio/bb613588.aspx,但翻译的有点糟糕 英文原文地址:http://msdn.microsoft.com/library/vstudio/bb613588  下面是我的翻译: Ribbon Control: WPF4.5包含Ribbon control;Ribbon control包含快速访问工具栏,系统菜单栏和标签页。
1141 0