郑宇军 《C#语言程序设计(第3版)》 清华大学出版社
Windows界面 第8章 WPF应用程序基础
第8章 WPF应用程序基础 WPF窗体和控件 使用XAML设计界面 绘制图形 动画和多媒体
图形用户界面 媒体接口 User32 DirectX GDI+ Windows
图形用户界面 界面设计 Win32 WPF Win Form 媒体接口 User32 DirectX GDI+ Windows
图形用户界面 Windows Form WPF GDI+ Windows 2003, XP dpi相关 Code-behind 外观固定 媒体播放借助插件 System.Windows.Forms DirectX Windows Vista, 7, 8 物理尺寸相关 XAML 外观可定制 直接支持流媒体 System.Windows
WPF窗体和控件 创建WPF程序
WPF窗体和控件 窗体和布局 DispatcherObject DependencyObject Visual UIElement FrameworkElement Shape Control Panel
WPF窗体和控件 窗体和布局 Panel StackPanel DockPanel Grid Canvas WrapPanel TabPanel UniformGrid
WPF窗体和控件 窗体和布局 StackPanel: 水平或垂直堆放
WPF窗体和控件 窗体和布局 StackPanel: 水平或垂直堆放 WrapPanel: 单行/列, 自动换行
WPF窗体和控件 窗体和布局 StackPanel: 水平或垂直堆放 WrapPanel: 单行/列, 自动换行 DockPanel: 按方向停靠
WPF窗体和控件 窗体和布局 StackPanel: 水平或垂直堆放 WrapPanel: 单行/列, 自动换行 DockPanel: 按方向停靠 Grid: 网格 UniformGrid: 均匀网格
WPF窗体和控件 窗体和布局 StackPanel: 水平或垂直堆放 WrapPanel: 单行/列, 自动换行 DockPanel: 按方向停靠 Grid: 网格 UniformGrid: 均匀网格 Canvas: 坐标位置
HeaderedContentControl WPF窗体和控件 控件内容模型 Control ContentControl Frame Label ToolTip Window HeaderedContentControl UserControl
WPF窗体和控件 控件内容模型 ContentControl.Content: object
HeaderedContentControl WPF窗体和控件 控件内容模型 Control ContentControl Frame Label ToolTip Window HeaderedContentControl UserControl
WPF窗体和控件 Window 属性 事件 Title, Icon … WindowState, WindowStyle … TopMost, IsActive, ShowInTaskbar … 事件 Closing, Closed, Activated, Deactivated …
GridViewColumnHeader WPF窗体和控件 控件内容模型 ContentControl ButtonBase Button GridViewColumnHeader ToggleButton RepeatButton CheckBox RadioButton
WPF窗体和控件 ButtonBase ClickMode: Release, Press, Hover Command, CommandParameter, CommandTarget Click: RoutedEventHandler
HeaderedContentControl WPF窗体和控件 控件内容模型 Control ContentControl Frame Label ToolTip Window HeaderedContentControl UserControl
HeaderedContentControl WPF窗体和控件 控件内容模型 ContentControl HeaderedContentControl GroupBox TabItem Expander
WPF窗体和控件 控件内容模型 ContentControl.Content HeaderedContentControl.Header
HeaderedItemsControl WPF窗体和控件 控件内容模型 Control ItemsControl HeaderedItemsControl MenuBase Selector StatusBar TreeView ComboBox ListBox TabControl
WPF窗体和控件 ItemsControl Items: ItemCollection ItemsSource: IEnumerable public class ItemCollection { public object this[int index] …… }
HeaderedItemsControl WPF窗体和控件 控件内容模型 Control ItemsControl HeaderedItemsControl MenuBase Selector StatusBar TreeView ComboBox ListBox TabControl
HeaderedItemsControl WPF窗体和控件 控件内容模型 ItemsControl HeaderedItemsControl MenuItem ToolBar TreeViewItem
WPF窗体和控件 HeaderItemsControl Header: object Items, ItemsSource (继承)
WPF窗体和控件 文本框控件 Control TextBoxBase PasswordBox TextBox RichTextBox
WPF窗体和控件 TextBoxBase Copy(), Cut(), Paste() Redo(), Undo() LineUp(), LineDown(), LineLeft(), LineRight() PageUp(), PageDown(), PageLeft(), PageRight()
WPF窗体和控件 范围控件 Control RangeBase ScrollBar ProgressBar Slider
WPF窗体和控件 RangeBase Value, Minimum, Maximum: double
使用XAML设计界面 WPF XAML XPS XAML XAML WF XAML SilverLight XAML
使用XAML设计界面 WPF XAML XPS XAML XAML WF XAML SilverLight XAML BAML
StartupUri="MainWindow.xaml" App.xaml MainWindow.xaml App.xaml.cs MainWindow.xaml.cs
使用XAML设计界面 XAML元素 .NET对象
使用XAML设计界面 根元素 Application Window Page 编译器生成类 <Application x:Class="WpfContentExample.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="MainWindow.xaml"> ………… </Application>
使用XAML设计界面 简单属性 属性值:文本描述 类型解析:TypeConverter 命名元素 <TextBox Name="textBox1" Text="请在这里输入邮箱地址..." />
使用XAML设计界面 复杂属性 Parent.Property <Grid> <Grid.Background> <LinearGradientBrush> <GradientStop Offset='0' Color='Red' /> <GradientStop Offset='.5' Color='White' /> <GradientStop Offset='1' Color='Blue' /> </LinearGradientBrush> </Grid.Background> ……
使用XAML设计界面 元素嵌套 <Grid> …… <Grid.RowDefinitions> <RowDefinition Height="50" /> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <TextBox Name="textBox1" Text="请输入邮箱地址..." />
使用XAML设计界面 附加属性 <Grid> …… <Grid.RowDefinitions> <RowDefinition Height="50" /> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <TextBox Name="textBox1" Text="请输入邮箱地址..." Grid.Row="1"/>
使用XAML设计界面 定义资源 <Window.Resources> <LinearGradientBrush x:Key="lgBrush"> <GradientStop Offset='0' Color='Red' /> <GradientStop Offset='.5' Color='White' /> <GradientStop Offset='1' Color='Blue' /> </LinearGradientBrush> </Window.Resources> <Grid Background="{StaticResource lgBrush}"> …… </Grid> <TextBox Name="textBox1" Background="{StaticResource lgBrush}">
使用XAML设计界面 定义资源 静态资源 动态资源 <Window.Resources> <LinearGradientBrush x:Key="lgBrush"> <GradientStop Offset='0' Color='Red' /> <GradientStop Offset='.5' Color='White' /> <GradientStop Offset='1' Color='Blue' /> </LinearGradientBrush> </Window.Resources> <TextBox Name="textBox1" Background="{DynamicResource lgBrush}">
使用XAML设计界面 定义资源 控件资源 窗体/页面资源 应用程序资源 <Button.Resources> …… <Window.Resources> …… </Window.Resources> <Application.Resources> …… </Application.Resources>
使用XAML设计界面 定义资源 控件资源 窗体/页面资源 应用程序资源 资源字典 <ResourceDictionary> …… <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="res1.xaml" /> <ResourceDictionary Source="res2.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> …… </Application.Resources>
使用XAML设计界面 事件绑定 <Button Name="button1" Content="提交" Click="button1_Click" /> private void button1_Click(object sender, RoutedEventArgs e) { }
使用XAML设计界面 表达式绑定 ElementName Path <Ellipse Name="ellipse1" Height="{Binding ElementName=slider1, Path=Value}" Width="{Binding ElementName=slider2, Path=Value}" Stroke="Black" Fill="Blue"/>
XAML基础 样式Style <Window.Resources> <FontFamily x:Key="ff1"> 黑体 </FontFamily> <FontWeight x:Key="fw1"> Bold </FontWeight> <FontSize x:Key="fs1"> 17 </FontSize> </Window.Resources> <Button Content="button1" FontFamily="{StaticResource ff1}" FontWeight="{StaticResource fw1}" FontSize="{StaticResource fs1}" />
使用XAML设计界面 样式Style Setter: Property, Value <Style x:Key="Sty1"> <Setter Property="Control.FontFamily" Value="黑体" /> <Setter Property="Control.FontWeight" Value="Bold" /> <Setter Property="Control.FontSize" Value="17" /> </Style> <Button Content="button1" Style="{StaticResource Sty1}" />
使用XAML设计界面 样式Style Setter: Property, Value <Style x:Key="Sty1"> <Setter Property="Control.FontFamily" Value="黑体" /> <Setter Property="Control.FontWeight" Value="Bold" /> <Setter Property="Control.FontSize" Value="17" /> </Style> <Button Content="button1" Style="{StaticResource Sty1}" /> <Label Content="浙江工业大学" Style="{StaticResource Sty1}" />
使用XAML设计界面 样式Style TargetType: 自动应用 <Style TargetType="Button"> <Setter Property="Control.FontFamily" Value="黑体" /> <Setter Property="Control.FontWeight" Value="Bold" /> <Setter Property="Control.FontSize" Value="17" /> </Style> <Button Content="button1" /> <Button Content="button2" />
使用XAML设计界面 样式Style TargetType: 自动应用 <Style TargetType="Button"> <Setter Property="Control.FontFamily" Value="黑体" /> <Setter Property="Control.FontWeight" Value="Bold" /> <Setter Property="Control.FontSize" Value="17" /> </Style> <Button Content="button1" /> <Button Content="button2" /> <Button Content="button3" Style="{x: Null}" />
使用XAML设计界面 样式Style Setter.Value <Style x:Key="BkSty"> <Setter Property="Control.Background"> <Setter.Value> <LinearGradientBrush x:Key="lgBrush"> <GradientStop Offset='0' Color='Red' /> <GradientStop Offset='.5' Color='White' /> <GradientStop Offset='1' Color='Blue' /> </LinearGradientBrush> </Setter.Value> </Setter> </Style>
使用XAML设计界面 触发器Trigger Trigger: Property, Value Setter: Property, Value <Style x:Key="EmpSty"> <Style.Triggers> <Trigger Property="Control.IsMouseOver" Value="True"> <Setter Property="Control.FontWeight" Value="Bold"/> </Trigger> </Style.Triggers> </Style> <Button Content="button1" Style="{StaticResource ResourceKey=EmpSty}"/>
使用XAML设计界面 触发器Trigger Triggers集合 <Style TargetType="Button"> <Style.Triggers> <Trigger Property="Control.IsMouseOver" Value="True"> <Setter Property="Control.FontWeight" Value="Bold"/> </Trigger> <Trigger Property="Button.IsPressed" Value="True"> <Setter Property="Control.Foreground" Value="Red"/> </Style.Triggers> </Style>
使用XAML设计界面 触发器Trigger MultiTrigger: 多条件触发器 <Style TargetType="Button"> <Style.Triggers> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="Control.IsEnabled" Value="True"/> <Condition Property="Control.IsMouseOver" Value="True"/> </MultiTrigger.Conditions> <MultiTrigger.Setters> <Setter Property="Control.Foreground" Value="Red"/> </MultiTrigger.Setters> </MultiTrigger> </Style.Triggers> </Style>
使用XAML设计界面 事件设置器EventSetter Event: 响应的事件 Handler: 关联事件处理程序 <Style x:Key="lightSty"> <EventSetter Event="Control.MouseEnter" Handler="I_MouseIn"/> <EventSetter Event="Control.MouseLeave" Handler="I_MouseOut"/> </Style> private void I_MouseIn(object sender, MouseEventArgs e) { }
使用XAML设计界面 Style SetterBase Setter EventSetter TargetType: Type Setters: SetterBaseCollection Triggers: TriggerBaseCollection TriggerBase Trigger EventTrigger MultiTrigger DataTrigger MultiDataTrigger
绘制图形 Brush Control.Background, Foreground, BorderThickness Shape.Fill, Stroke
绘制图形 Brush DependencyObject Freezable Animatable Brush SolidColorBrush GradientBrush BitmapCacheBrush TileBrush LinearGradientBrush RadialGradientBrush ImageBrush VisualBrush DrawingBrush
绘制图形 Brush Brushes.Red, Blue, Yellow… SystemColors.ControlBrush, ActiveBorderBrush…
绘制图形 Brush DependencyObject Freezable Animatable Brush SolidColorBrush GradientBrush BitmapCacheBrush TileBrush LinearGradientBrush RadialGradientBrush ImageBrush VisualBrush DrawingBrush
绘制图形 FrameworkElement Shape Line Polyline Polygon Ellipse Rectangle Path
绘制图形 Shape Fill, Stroke: Brush Stretch GeometryTransform
绘制图形 Ellipse <Ellipse Name="ellipse1" Canvas.Left="450" Canvas.Top="50" Fill="Red" Height="80" Width="80" /> double x0 = (double)ellipse1.GetValue(Canvas.LeftProperty) + ellipse1.Width / 2; double y0 = (double)ellipse1.GetValue(Canvas.TopProperty) + ellipse1.Height / 2;
绘制图形 Rectangle <Rectangle Canvas.Left="100" Canvas.Top="220" Height="80" Width="120" Stroke="Black"/>
绘制图形 Rectangle RadiuX, RadiusY <Rectangle Canvas.Left="300" Canvas.Top="220" Height="80" Width="120" Stroke="Black" RadiusX="10" RadiusY="10"/>
绘制图形 Line X1, X2, Y1, Y2 <Line Stroke="Blue" X1="0" Y1="300" X2="{Binding ElementName=canvas1, Path=ActualWidth}" Y2="300"/>
绘制图形 Polyline Points <Polyline Stroke="Black" Fill="Cyan" Points="100,225 90,225 160,180 230,225 220,225" />
绘制图形 Polygon Points <Polygon Stroke="Black" Fill="Gray" Points="290,225 320,180 400,180 430,225" />
绘制图形 Shape StrokeThickness StrokeDashArray StrokeStartLineCap, StrokeEndLineCap <Rectangle Canvas.Left="180" Canvas.Top="240" Stroke="Black" StrokeDashArray="1,1" Height="60" Width="20" /> <Rectangle Canvas.Left="380" Canvas.Top="240" Stroke="Black" StrokeDashArray="4,2" Height="60" Width="20" />
绘制图形 Path Path Data: Geometry Geometry LineGeometry EllipseGeometry GeometryGroup StreamGeometry RectangleGeometry PathGeometry CombinedGeometry
绘制图形 Path Data: Geometry <Window.Resources> <GeometryGroup x:Key="WinGeo"> <RectangleGeometry Rect="0,0 20,20"/> <RectangleGeometry Rect="0,20 20,20"/> <RectangleGeometry Rect="20,0 20,20"/> <RectangleGeometry Rect="20,20 20,20"/> </GeometryGroup> </Window.Resources> <Path Canvas.Left="115" Canvas.Top="235" Stroke="Blue" Fill="Yellow" Data="{StaticResource WinGeo}" /> <Path Canvas.Left="315" Canvas.Top="235" Stroke="Blue" Fill="Yellow" Data="{StaticResource WinGeo}" />
绘制图形 Path Path Data: Geometry Geometry LineGeometry EllipseGeometry GeometryGroup StreamGeometry RectangleGeometry PathGeometry CombinedGeometry
QuadraticBezierSegment 绘制图形 Path PathGeometry Figures …… PathFigure Segments …… PathSegment LineSegment ArcSegment BezierSegment QuadraticBezierSegment PolyLineSegment PolyBezierSegment
绘制图形 DispatcherObject DependencyObject Visual UIElement ContainerVisual Viewport3DVisual FrameworkElement DrawingVisual HostVisual Shape
绘制图形 DrawingVisual RenderOpen(): DrawingContext DrawingContext DrawLine(), DrawRectangle(), DrawEllipse()… DrawText() DrawGeometry() DrawingVisual dv = new DrawingVisual(); DrawingContext dc = dv.RenderOpen(); dc.DrawEllipse(Brushes.Red, null, new Point(50,50), 30, 20); dc.DrawText(new Pen(Brushes.Blue), new Point(5,10), new Point(90,50)); …… dc.Close();
Demo
动画 动画技术 基于计时器 void timer_Tick(object sender, EventArgs e) { double x1 = Canvas.GetLeft(ellipse1); double y1 = Canvas.GetTop(ellipse1); Canvas.SetLeft(ellipse1, x1 + 5); Canvas.SetTop(ellipse1, y1 + 5); }
动画 动画技术 基于计时器 基于属性
动画 基于属性的动画技术 DoubleAnimation: Animation System.Windows.Media.Animation From: 起始值 To: 终止值 Duration: 持续时间 DoubleAnimation ani1 = new DoubleAnimation(); ani1.From = 0; ani1.To = 100; ani1.Duration = TimeSpan.FromSeconds(5); ellipse1.BeginAnimation(Ellipse.WidthProperty, ani1);
动画 基于属性的动画技术 DoubleAnimation: AnimationTimeline StoryBoard: ParellelTimeline <Storyboard> <DoubleAnimation From="0" To="100" Duration='0:0:5' Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="Width" /> </Storyboard>
动画 基于属性的动画技术 DoubleAnimation: AnimationTimeline StoryBoard: ParellelTimeline <EventTrigger RoutedEvent="Button.Click"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation To="100" Duration='0:0:5' Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="Width" /> </Storyboard> </BeginStoryboard> </EventTrigger>
动画 基于属性的动画技术 DoubleAnimation: Animation System.Windows.Media.Animation From: 起始值 To: 终止值 Duration: 持续时间 DoubleAnimation ani1 = new DoubleAnimation(); ani1.From = 100; ani1.To = 10; ani1.Duration = TimeSpan.FromSeconds(5); ellipse1.BeginAnimation(Canvas.TopProperty, ani1);
动画 基于属性的动画技术 DoubleAnimation: Animation System.Windows.Media.Animation From: 起始值 To: 终止值 Duration: 持续时间 <Style x:Key="ImgFadeStyle" TargetType="Image"> <Style.Triggers> <Trigger Property="Control.IsMouseOver" Value="True"> <Trigger.EnterActions> <BeginStoryboard> <Storyboard> <DoubleAnimation From="1.0" To="0.0" Duration="0:0:5" Storyboard.TargetProperty="Opacity" /> </Storyboard> </BeginStoryboard> </Trigger.EnterActions> </Trigger> </Style.Triggers> </Style>
动画 DispatcherObject DependencyObject Freezable Animatable Timeline AnimationTimeline TimelineGroup MediaTimeline ParallelTimeline
动画 TimeLine Duration SpeedRatio AutoReverse DoubleAnimation ani1 = new DoubleAnimation(); ani1.From = 0; ani1.To = 100; ani1.Duration = TimeSpan.FromSeconds(5); ani.AutoReverse = true; ellipse1.BeginAnimation(Ellipse.WidthProperty, ani1);
动画 TimeLine Duration SpeedRatio AutoReverse RepeatBehavior DoubleAnimation ani1 = new DoubleAnimation(); ani1.From = 0; ani1.To = 100; ani1.Duration = TimeSpan.FromSeconds(5); ani.RepeatBehavior = new RepeatBehavior(3); ellipse1.BeginAnimation(Ellipse.WidthProperty, ani1);
动画 TimeLine Duration SpeedRatio AutoReverse RepeatBehavior DoubleAnimation ani1 = new DoubleAnimation(); ani1.From = 0; ani1.To = 100; ani1.Duration = TimeSpan.FromSeconds(5); ani.RepeatBehavior = RepeatBehavior.Forever; ellipse1.BeginAnimation(Ellipse.WidthProperty, ani1);
动画 TimeLine Duration SpeedRatio AutoReverse RepeatBehavior DoubleAnimation ani1 = new DoubleAnimation(); ani1.From = 0; ani1.To = 100; ani1.Duration = TimeSpan.FromSeconds(5); ani1.RepeatBehavior = new RepeatBehavior(TimeSpan.FromHours(1)); ellipse1.BeginAnimation(Ellipse.WidthProperty, ani1);
动画 TimeLine Duration SpeedRatio AutoReverse RepeatBehavior AccelerationRatio, DecelerationRatio DoubleAnimation ani1 = new DoubleAnimation(); ani1.From = 0; ani1.To = 100; ani1.Duration = TimeSpan.FromSeconds(5); ani1.AccelerationRatio = 0.2; ani1.DecelerationRatio = 0.3; ellipse1.BeginAnimation(Ellipse.WidthProperty, ani1);
动画 DispatcherObject DependencyObject Freezable Animatable Timeline AnimationTimeline TimelineGroup MediaTimeline ParallelTimeline
动画 AnimationTimeline GetCurrentValue
动画 AnimationTimeline DoubleAnimationBase Int32AnimationBase ByteAnimationBase …… DoubleAnimation DoubleAnimationUsingKeyFrames DoubleAnimationUsingPaths Int32Animation Int32AnimationUsingKeyFrames
动画 AnimationTimeline ColorAnimationBase PointAnimationBase SizeAnimationBase VectorAnimationBase
动画 ColorAnimation <Window.Resources> <SolidBrush x:Key="AniBrush"Color="Blue" /> … <Storyboard> <ColorAnimation From="Blue" To="Red" Storyboard.TargetName="{StaticResource AniBrush}" Storyboard.TargetProperty="SolidBrush.Color" /> </Storyboard> <Window.Resource>
动画 Timeline TimelineGroup ParallelTimeline Storyboard
动画 Storyboard Children: TimelineCollection DoubleAnimation ani1 = new DoubleAnimation() {From = 200, To = 0}; DoubleAnimation ani2 = new DoubleAnimation() {From = 0, To = 300}; Storyboard story1 = new Storyboard(){Duration=TimeSpan.FromSeconds(3)}; story1.Children.Add(ani1); story1.Children.Add(ani2);
动画 Storyboard Children: TimelineCollection SetTarget, SetTargetName, SetTargetProperty DoubleAnimation ani1 = new DoubleAnimation() {From = 200, To = 0}; DoubleAnimation ani2 = new DoubleAnimation() {From = 0, To = 300}; Storyboard story1 = new Storyboard(){Duration=TimeSpan.FromSeconds(3)}; story1.Children.Add(ani1); story1.Children.Add(ani2); Storyboard.SetTargetName(ani1, "ellipse1"); Storyboard.SetTargetProperty(ani1, new PropertyPath(Canvas.TopProperty)); Storyboard.SetTargetName(ani2, "ellipse1"); Storyboard.SetTargetProperty(ani2, new PropertyPath(Canvas.LeftProperty));
动画 Storyboard Children: TimelineCollection SetTarget, SetTargetName, SetTargetProperty DoubleAnimation ani1 = new DoubleAnimation() {From = 200, To = 0}; DoubleAnimation ani2 = new DoubleAnimation() {From = 0, To = 300}; Storyboard story1 = new Storyboard(){Duration=TimeSpan.FromSeconds(3)}; story1.Children.Add(ani1); story1.Children.Add(ani2); Storyboard.SetTargetName(ani1, "ellipse1"); Storyboard.SetTargetProperty(ani1, new PropertyPath(Canvas.TopProperty)); Storyboard.SetTargetName(ani2, "ellipse1"); Storyboard.SetTargetProperty(ani2, new PropertyPath(Canvas.LeftProperty)); story1.Begin(ellipse1);
动画 Transform TranslateTransform RotateTransform ScaleTransform SkewTransform <Storyboard> <DoubleAnimation To="360" Duration="0:0:1" RepeatBehavior="Forever" Storyboard.TargetProperty="RenderTransform.Angle"/> </Storyboard> <Button> <Button.RenderTransform> <RotateTransform/> </Button.RenderTransform> </Button>
动画 Transform TranslateTransform RotateTransform ScaleTransform SkewTransform MatrixTransform TransformGroup
动画 AnimationTimeline DoubleAnimationBase Int32AnimationBase ByteAnimationBase …… DoubleAnimation DoubleAnimationUsingKeyFrames DoubleAnimationUsingPaths Int32Animation Int32AnimationUsingKeyFrames
基于路径的动画 ×××AnimationUsingPath PathGeometry Source DoubleAnimationUsingPath ani1 = new DoubleAnimationUsingPath(); ani1.PathGeometry = new PathGeometry() {……}; ani1.Source = PathAnimationSource.Y;
基于帧的动画 ×××AnimationUsingKeyFrames ×××KeyFrame <PointAnimationUsingKeyFrames Storyboard.TargetName="ellipse" Storyboard.TargetProperty="Fill.GradientOrigin"> <DiscretePointKeyFrame Value="0.7,0.3" KeyTime="0:0:20" /> <DiscretePointKeyFrame Value="0.3,0.7" KeyTime="0:0:25" /> <DiscretePointKeyFrame Value="0.5,0.9" KeyTime="0:0:28" /> <DiscretePointKeyFrame Value="0.9,0.6" KeyTime="0:0:20" /> <DiscretePointKeyFrame Value="0.8,0.2" KeyTime="0:0:22" /> <DiscretePointKeyFrame Value="0.7,0.3" KeyTime="0:0:24" /> </PointAnimationUsingKeyFrames>
第8章课后练习习题 设计一个只能被横向拉伸、纵向尺寸不会被改变的WPF窗体。