打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
WPF学习之 动画
Admin
2010年6月19日
名人名言:只有劳动才能使人变得幸福,使他的心灵变得开朗、和谐、心满意足。——别林斯基
WPF学习之 动画
对于windowsForm程序员来说,没有动画的概念,如果我们要实现一个动态的效果,就是配置一个定时器,然后根据定时器的频率来循环的调用回调函数在一段时间
不断的更新目标函数的属性来实现动画效果。
用定时器来模拟动画
在界面上面放一个圆
<Canvas>
<Ellipse Canvas.Left="24" Canvas.Top="68" Margin="39,39,0,0" Stroke="Black" Height="38" HorizontalAlignment="Left"
VerticalAlignment="Top" Width="42" Fill="Yellow" Name="yuan" />
<Button Canvas.Left="38" Canvas.Top="213" Height="23" Name="button1" Width="75" Click="button1_Click">开始</Button>
</Canvas>
当点击按钮是创建一个定时器执行
DispatcherTimer timer;
int i = 0;
private void button1_Click(object sender, RoutedEventArgs e)
{
timer = new DispatcherTimer(DispatcherPriority.Normal);
timer.Tick += new EventHandler(timer_Tick);
timer.Interval = TimeSpan.FromMilliseconds(20);
timer.Start();
}
这里定时器对象是在System.Windows.Threading命名空间下面,需要引入System.Windows.Threading
void timer_Tick(object sender, EventArgs e)
{
// throw new NotImplementedException();
move(new Point(0, 1));
}
public void move(Point p)
{
//这里我们希望圆每次移动ppoint
Point pt = new Point(Canvas.GetTop(yuan), Canvas.GetLeft(yuan));//得到当前对象的位置
//改变位置
Canvas.SetTop(yuan, pt.X+ p.X);
Canvas.SetLeft(yuan, pt.Y + p.Y);
i++;
if (i >= 100)
{
timer.Stop();
}
}
这里我们让圆对象向右移动,执行100次之后停止。这样就模拟出一个基于定时器的动画。
当然你也可以使用
System.Timers.Timer
System.Timers.Timer tm = new System.Timers.Timer();
tm.Interval = 20;
tm.Elapsed += new System.Timers.ElapsedEventHandler(tm_Elapsed);
tm.Start();
或者是System.Threading.Timer但是
System.Threading.Timer 是一个简单的轻量计时器,它使用回调方法并由线程池线程提供服务。不建议将其用于 Windows 窗体,因为其回调不在用户界面线程上进行。System.Windows.Forms.Timer 是用于 Windows 窗体的更佳选择。要获取基于服务器的计时器功能,可以考虑使用 System.Timers.Timer,它可以引发事件并具有其他功能。【MSDN】
windows程序员可能很熟悉这种实现方式,但是用定时器来实现动画并不是推荐的办法。定时器无法根据显示器的垂直刷新率进行同步,
也不能与WPF的渲染引擎同步【WPF揭秘】
用Rendering事件来实现基于帧的动画
在WPF中,可以通过System .Windows .Media.CompositionTarget的Rendering事件来实现基于帧的动画,它和Timer不同的就是
它不是在定制的时间区间里引发的,而是在布局后和渲染前的每一帧引发一次。
CompositionTarget 是一个类,表示正在其上绘制您的应用程序的显示图面。【MSDN】
CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
void CompositionTarget_Rendering(object sender, EventArgs e)
{
//throw new NotImplementedException();
move(new Point(0, 1));
}
public void move(Point p)
{
//这里我们希望圆每次移动ppoint
Point pt = new Point(Canvas.GetTop(yuan), Canvas.GetLeft(yuan));//得到当前对象的位置
//改变位置
Canvas.SetTop(yuan, pt.X + p.X);
Canvas.SetLeft(yuan, pt.Y + p.Y);
}
由于Rendering事件和界面的刷新频率有关,所有我们不能够控制它的执行。但处理程序是在UI线程中调用的 ,不用担心线程通信的问题。
WPF动画
虽然使用上面的两种方法也是实现动画的一个办法,在WPF中提供了动画类,让动画成为更加简单和说明性的流程。在
System.Windows.Media.Animation命名空间中定义了许多类,能够很方便的描述动画。
在WPF中实现一个动画需要三个必备的条件:动画对象、故事板、事件触发
一个最简单的WPF动画
在一个按钮下面写上如下代码
//1.创建动画对象
DoubleAnimation doubleAnimation = new DoubleAnimation();
doubleAnimation.From = 10;//设置开始值
doubleAnimation.To = 100;//设置结束值
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));//动画运行时间
doubleAnimation.AutoReverse = true;//设置动画播放完后反向在播放
doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;//设置为循环播放
//2.创建故事板 并把动画对象加入到该故事板中
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(doubleAnimation);
//3. 指定要执行该故事板的对象
Storyboard.SetTarget(doubleAnimation, yuan);//指定要执行动画的对象。
//4.指定要进行动画处理的属性
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("(Canvas.Top)"));
storyboard.Begin();//开始动画
在上面定义了一个DoubleAnimation类型的动画,然后把动画加入了故事板storyboard,最后设置执行动画的对象和改变的属性。
当然Storyboard还提供了 Stop(停止)、Pause(暂停)、Resume(继续)方法来控制动画
动画类型
动画类型总体上分为两类  From/To/By动画和关键帧动画
From/To/By动画:在起始值From和结束值To之间处理动画,之间的时间由Duration属性控制,若要指定相对于起始值的结束值何以设定By属性
关键帧动画:在使用关键帧对象指定的一系列的值之间播放动画。
属性类型
对应的基本 (From/To/By) 动画
对应的关键帧动画
Color
ColorAnimation
ColorAnimationUsingKeyFrames
Double
DoubleAnimation
DoubleAnimationUsingKeyFrames
Point
PointAnimation
PointAnimationUsingKeyFrames
Object
ObjectAnimationUsingKeyFrames
ColorAnimation          在指定的 Duration 内使用线性内插对两个目标值之间的 Color 属性值进行动画处理。
DoubleAnimation        在指定的 Duration 内使用线性内插对两个目标值之间的 Double 属性值进行动画处理。
PointAnimation           在指定的 Duration 内使用线性内插对两个目标值之间的 Point 属性值进行动画处理。
动画是时间线
所有的动画均继承自Timeline对象,因此所有的动画都是专用类型的时间线。常用的属性有
Duration     表示时间线完成一次重复
AutoReverse  指定时间线在到达其 Duration 的终点后是否倒退。如果将此动画属性设置为 true
RepeatBehavior 指定时间线的播放次数
BeginTime   设定动画的开始时间
SpeedRatio  设定动画的速率
FillBehavior  设定动画结束后的行为,有两个值HoldEnd保持当前值,Stop结束后变为初始值。
故事板
故事板对象中提供了一系列的API用于控制对象的播放。开始、暂停、继续、停止等。
对于故事板提供了TargetName和TargetProperty的附加属性,通过在动画上设置这些属性。告诉我们动画对那些内容进行动画处理。
//3. 指定要执行该故事板的对象
Storyboard.SetTarget(doubleAnimation, yuan);//指定要执行动画的对象。
//4.指定要进行动画处理的属性
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("(Canvas.Top)"));
在例子中的第三步和第四步就是完成了对这两个值的设定。
WPF中能够很方便的创建动画,在上面提到的三种创建动画的方式在园子里深蓝的系列教程C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial)
中对于三种动画适用的地方也说的比较详细,而我开始看WPF也是看到深蓝的教程开始的。在WPF揭秘这本书里也是介绍了三种动画的方式。主要还是第三种。
关键帧动画
关键帧动画与From/To/By动画类似,关键帧动画以动画的形式显示了目标属性的值。它通过其Duration创建其目标之间的过渡。
但是,From/To/By动画创建两个值之间的过渡,而点歌关键帧动画可以创建任意数量的目标值之间的过渡。
关键帧动画需要创建关键帧对象,并添加到动画的KeyFrames属性。动画运行是,将在指定的帧之间过渡
一个简单的关键帧动画
<Canvas>
<Ellipse Canvas.Left="38" Canvas.Top="40" Height="49" Name="ellipse1" Stroke="Black" Width="52" Fill="Turquoise" />
<Button Canvas.Left="92" Canvas.Top="233" Height="23" Name="button1" Width="75" Click="button1_Click">开始</Button>
</Canvas>
在界面上放一个圆和一个按钮
然后在按钮单击事件里写上
//1.创建一个故事板
Storyboard storyboard = new Storyboard();
//2.创建关键帧动画
DoubleAnimationUsingKeyFrames doubleAnimationUsingKeyFrames = new DoubleAnimationUsingKeyFrames();
storyboard.Children.Add(doubleAnimationUsingKeyFrames);//把动画添加到故事板
Storyboard.SetTarget(doubleAnimationUsingKeyFrames, ellipse1);//设置Target
Storyboard.SetTargetProperty(doubleAnimationUsingKeyFrames, new PropertyPath("(Canvas.Top)"));//设置TargetProperty
doubleAnimationUsingKeyFrames.Duration = new Duration(TimeSpan.FromSeconds(10));
//3.创建关键帧 并添加到KeyFrames 中 这里创建了3个样条关键帧
LinearDoubleKeyFrame linearDoubleKeyFrame = new LinearDoubleKeyFrame(200, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(2)));
doubleAnimationUsingKeyFrames.KeyFrames.Add(linearDoubleKeyFrame);
doubleAnimationUsingKeyFrames .KeyFrames .Add (new DiscreteDoubleKeyFrame(300,KeyTime.FromTimeSpan(TimeSpan.FromSeconds(5))));
doubleAnimationUsingKeyFrames .KeyFrames .Add (new SplineDoubleKeyFrame(600,KeyTime.FromTimeSpan(TimeSpan.FromSeconds(10)),
new KeySpline (new Point (0,1),new Point (1,0))));
storyboard.Begin();
在这个关键帧动画中,前两秒我们让对象的值从0到200的线性插值,在从2到5秒的时间里对象的值从200到300的离散插值,在5到10秒的时间里对象的值从300到600的样条插值.
这里的对象的值,即ellipse1这个对象的Canvas.Top的值。
关键帧动画的类型
属性类型
对应的关键帧动画类
支持的内插方法
Color
ColorAnimationUsingKeyFrames
离散、线性、样条
Double
DoubleAnimationUsingKeyFrames
离散、线性、样条
Point
PointAnimationUsingKeyFrames
离散、线性、样条
Object
ObjectAnimationUsingKeyFrames
离散
和From/To/By动画相比多了一个Object类型的动画
关键帧和关键时间
关键帧的主要用途是指定KeyTime和目标Value。每一个关键帧都提供了这两个属性。
Value 属性指定了关键帧的目标值
KeyTime属性指定了到达关键帧的Value的时间,这个时间在Duration限定的时间内
关键帧开始后,会按照KeyTime属性定义的顺序来循环方位其关键帧。如果0上没有关键帧,动画将在目标属性当前值和第一帧的Value之间创建一个过渡
动画会使用由第二帧指定的内插方法来创建第一个和第二个关键帧的Value之间的过渡。过渡从第一帧的KeyTime开始,第二帧的KeyTime结束动画将继续,并创建每个后续关键帧及其前面的关键帧之间的过渡。
最终,动画过渡到关键时间最大(等于或小于动画的 Duration)的关键帧值。
关键帧的类型
关键帧的类型主要有Discrete、Linear、Spline三种类型(离散、线性、样条 )
关键帧类型遵循以下命名约定:
_interpolationMethod_typeKeyFrame
其中,_interpolationMethod 是关键帧使用的内插方法(Discrete、Linear、Spline),_type 是类要进行动画处理的值的类型(Double,Color,Point,Object)。 这里object只支持离散的插值方法。
例如,您可以使用以下三种具有 DoubleAnimationUsingKeyFrames 的关键帧类型:DiscreteDoubleKeyFrame、LinearDoubleKeyFrame 和 SplineDoubleKeyFrame。
内插方法
Linear(线性插值):线性插值应该是最好理解的方法,动画将在持续的时间内以固定的速度来播放。时间和值的关系是一个线性的关系。
Discrete(离散插值):使用离散插值,动画函数将从一个值跳到下一个没有内插的值。它的值是一个跳跃的值。
Spline(样条插值):使用样条插值可以用于达到更现实的计时效果。在指定Value和KeyTime的同时,还可以指定KeySpline,用两个控制点,来指定关键帧进度的三次方贝塞尔曲线。当然样条插值比较难理解。如下图:
WPF 图片水滴马赛克效果
马赛克(Mosaic),建筑专业名词为锦砖,分为陶瓷锦砖和玻璃锦砖两种。是一种装饰艺术,通常使用许多小石块或有色玻璃碎片拼成图案,在教堂中的玻璃艺品,又称为花窗玻璃(stained glass)。在拜占庭帝国时代,马赛克随着基督教兴起而发展为教堂及宫殿中的壁画形式。现今马赛克泛指这种类型五彩斑斓的视觉效果。马赛克也指现行广为使用的一种图像(视频)处理手段,此手段将影像特定区域的色阶细节劣化并造成色块打乱的效果,因为这种模糊看上去有一个个的小格子组成,便形象的称这种画面为马赛克。其目的通常是使之无法辨认。
先来看一下程序的运行结果:
要实现这个效果,我们是通过图片的Clip属性。
图片的Cilp属性
用于确定剪辑区域大小的几何图形。一个典型的例子如下:
在没有使用Clip属性之前图片是这样的:
使用的代码是MSDN上的代码
<Image
Source="sampleImages\Waterlilies.jpg"
Width="200" Height="150" HorizontalAlignment="Left">
<Image.Clip>
<EllipseGeometry
RadiusX="100"
RadiusY="75"
Center="100,75"/>
</Image.Clip>
</Image>
使用了Clip属性之后:
CompositionTarget.Rendering
CompositionTarget 是一个类,表示正在其上绘制您的应用程序的显示图面。 WPF 动画引擎为创建基于帧的动画提供了许多功能。 但是,在有些应用程序方案中,您需要根据每个帧控制呈现。 使用 CompositionTarget 对象,可以基于每个帧回调来创建自定义动画。
我们在程序中使用这个重绘的方法来重绘屏幕,具体的代码如下:
void CompositionTarget_Rendering(object sender, EventArgs e)
{
double springness = Spring;
double scale = 1;
//遍历每一个图片
for (int i = 0; i < images.Length; i++)
{
//当前的图片
Image image = images[i];
// 根据目标点重定位图片
double offsetX = -(image.Width - ImageWidth) / ImageWidth * targetPoint.X;
double offsetY = -(image.Height - ImageHeight) / ImageHeight * targetPoint.Y;
image.SetValue(Canvas.LeftProperty, offsetX);
image.SetValue(Canvas.TopProperty, offsetY);
// 更新马赛克
EllipseGeometry ellipseGeometry = (EllipseGeometry)image.Clip;
Point center = ellipseGeometry.Center;
center.X = center.X + (targetPoint.X - offsetX - center.X) * springness;
center.Y = center.Y + (targetPoint.Y - offsetY - center.Y) * springness;
ellipseGeometry.Center = center;
image.Clip = ellipseGeometry;
springness *= SpringDrag;
scale += LayerScale;
}
}
打造马赛克
我们使用多重图片堆叠来打造马赛克,具体的代码如下:
/// <summary>
/// 将打过马赛克的图片添加到窗体中
/// </summary>
private void addImage()
{
double radius = InitialRadius;//初始半径
double scale = 1;
ImageSource imageSource = new BitmapImage(new Uri(ImagePath, UriKind.Relative));
//遍历层数
for (int i = 0; i < LayerCount; i++)
{
// 创建马赛克
EllipseGeometry ellipseGeometry = new EllipseGeometry();
ellipseGeometry.Center = new Point(0, 0);
ellipseGeometry.RadiusX = radius;
ellipseGeometry.RadiusY = radius;
double offsetX = ImageWidth * (1 - scale) / 2;
double offestY = ImageHeight * (1 - scale) / 2;
// 创建图片,并设置图片的位置
Image image = new Image();
image.Source = imageSource;
image.Width = ImageWidth * scale;
image.Height = ImageHeight * scale;
image.SetValue(Canvas.LeftProperty, offsetX);
image.SetValue(Canvas.TopProperty, offestY);
// 用于确定剪辑区域大小的几何图形
image.Clip = ellipseGeometry;
// 将马赛克和图片添加到屏幕中
images[i] = image;
LayoutRoot.Children.Insert(0, image);
scale += LayerScale;
radius += RadiusIncrement;
}
// 将图片添加到窗体的背景中
Image background = new Image();
background.Source = imageSource;
LayoutRoot.Children.Insert(0, background);
}
本文来自Alexis 的博客,原文地址:http://www.cnblogs.com/alexis/archive/2011/01/06/1929108.html
WPF 循环切换图片达到动画效果
最近刚接触WPF, 一边学着一边用着,知识点还没有系统化的进行学习整理.
现在手上有一些美术做好的图片,需要连起来观看形成动画的效果,由于需求比较急,一时半会也静不下心来看WPF关于动画的知识.
潜意识里一个Image控件,循环设定Source属性,一看效果总是显示集合的最后一项.难道是循环速度太快?基于此思路下折腾了好久也无结果。开始不得不借着可以找到的资源进行尝试。试想我们一张张的图片进行播放形成的动画,是不是类似帧的这种概念.顺这个便找到了CompositionTarget.Rendering事件创建基于帧的动画.
第一种尝试:
namespace ImgAniDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
ObservableCollection<BitmapImage> bmList;
public MainWindow()
{
InitializeComponent();
InitList();
CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
}
public void InitList()
{
bmList = new ObservableCollection<BitmapImage>();
for (int i = 1; i < 4; i++)
{
BitmapImage bmImg = new BitmapImage(new Uri(System.Environment.CurrentDirectory + "\\" + i.ToString() + ".jpg"));
bmList.Add(bmImg);
}
}
void CompositionTarget_Rendering(object sender, EventArgs e)
{
for (int i = 0; i < bmList.Count; i++)
{
this.imgViewer.Source = bmList[i];
this.imgViewer.Width = this.imgViewer.Source.Width;
this.imgViewer.Height = this.imgViewer.Source.Height;
}
}
}
}
运行程序ImgAniDemo.exe结果还是只显示了最后一幅图片.
回头认真思考一下,可以做一个这样的猜测,WPF是不是做了优化,如果循环去设置Image的Source属性,用户看到的效果只会是最后一张图片呢?
Render是什么意思?不错,Rendering事件被处理的时候,我们是用了一个循环,按着上面的猜测,只会显示最后一张图片便在情理之中了.
聪明的你一定是想到了方法,我们在Rendering事件的时候不去循环了,只指定某一个图片给Source属性不就ok了吗?
修改后的代码:
namespace ImgAniDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
ObservableCollection<BitmapImage> bmList;
int index = 0; //记录索引
public MainWindow()
{
InitializeComponent();
InitList();
CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
}
public void InitList()
{
bmList = new ObservableCollection<BitmapImage>();
for (int i = 1; i < 4; i++)
{
BitmapImage bmImg = new BitmapImage(new Uri(System.Environment.CurrentDirectory + "\\" + i.ToString() + ".jpg"));
bmList.Add(bmImg);
}
}
void CompositionTarget_Rendering(object sender, EventArgs e)
{
if (index < bmList.Count)
{
this.imgViewer.Source = bmList[index];
this.imgViewer.Width = this.imgViewer.Source.Width;
this.imgViewer.Height = this.imgViewer.Source.Height;
index++;
}
else
{
index = 0;
}
}
}
}
这时候我们已经可以看到图片在自动切换了.会不会感觉速度太快了,我想按着一定的速度来控件切换怎么办?
直接上代码了
namespace ImgAniDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
ObservableCollection<BitmapImage> bmList;
int index = 0; //记录索引
bool isRendering = false;
public MainWindow()
{
InitializeComponent();
InitList();
CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerAsync();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
isRendering = true;
System.Threading.Thread.Sleep(1000); //停1秒
}
}
public void InitList()
{
bmList = new ObservableCollection<BitmapImage>();
for (int i = 1; i < 4; i++)
{
BitmapImage bmImg = new BitmapImage(new Uri(System.Environment.CurrentDirectory + "\\" + i.ToString() + ".jpg"));
bmList.Add(bmImg);
}
}
void CompositionTarget_Rendering(object sender, EventArgs e)
{
if (isRendering)
{
if (index < bmList.Count)
{
this.imgViewer.Source = bmList[index];
this.imgViewer.Width = this.imgViewer.Source.Width;
this.imgViewer.Height = this.imgViewer.Source.Height;
index++;
}
else
{
index = 0;
}
isRendering = false;
}
}
}
}
在运行看下效果呢?
呵呵,图片是不是在自动播放呢?
注:以上代码中用到的图片名称分别为1.jpg,2.jpg,3.jpg,且图片放在exe程序一起即可
以上仅是个人想到的一种方法,若有不正确的地方,还请多多指点...
CSDN博客第一期云计算最佳博主评选CSDN博客第二期最佳移动开发博主评选
WPF中简单的图片浏览功能
分类:WPF2012-11-07 14:10215人阅读评论(0)收藏举报
废话不说直接上代码:
[csharp]view plaincopyprint
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
ObservableCollection<BitmapImage> bmList;
int index = 0; //记录索引
BackgroundWorker bw = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
InitList();
CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
button1.Click += new RoutedEventHandler(button1_Click);
button2.Click += new RoutedEventHandler(button2_Click);
button3.Click += new RoutedEventHandler(button3_Click);
}
void button2_Click(object sender, RoutedEventArgs e)
{
if (index < bmList.Count - 1)
index++;
else
index = 0;
}
void button1_Click(object sender, RoutedEventArgs e)
{
if (index > 0)
index--;
else
index = bmList.Count - 1;
}
bool flag = true;
void button3_Click(object sender, RoutedEventArgs e)
{
if (flag == true)
{
bw.RunWorkerAsync();
flag = false;
(sender as Button).Content = "End";
}
else
{
flag = true;
(sender as Button).Content = "Start";
}
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
while (!e.Cancel)
{
button2_Click(sender, new RoutedEventArgs());
System.Threading.Thread.Sleep(2000); //停2秒
e.Cancel = flag;
}
}
List<string> list = new List<string>();
public void InitList()
{
list = System.IO.Directory.GetFiles("../../Image/").ToList();
bmList = new ObservableCollection<BitmapImage>();
for (int i = 1; i < list.Count; i++)
{
Uri url = new Uri(list[i].Substring(5), UriKind.Relative);
BitmapImage bmImg = new BitmapImage(url);
bmList.Add(bmImg);
}
}
void CompositionTarget_Rendering(object sender, EventArgs e)
{
this.imgViewer.Source = bmList[index];
label1.Content = index.ToString();
this.imgViewer.Width = this.imgViewer.Source.Width;
this.imgViewer.Height = this.imgViewer.Source.Height;
}
}
/// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { ObservableCollection<BitmapImage> bmList; int index = 0; //记录索引 BackgroundWorker bw = new BackgroundWorker(); public MainWindow() { InitializeComponent(); InitList(); CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering); bw.DoWork += new DoWorkEventHandler(bw_DoWork); button1.Click += new RoutedEventHandler(button1_Click); button2.Click += new RoutedEventHandler(button2_Click); button3.Click += new RoutedEventHandler(button3_Click); } void button2_Click(object sender, RoutedEventArgs e) { if (index < bmList.Count - 1) index++; else index = 0; } void button1_Click(object sender, RoutedEventArgs e) { if (index > 0) index--; else index = bmList.Count - 1; } bool flag = true; void button3_Click(object sender, RoutedEventArgs e) { if (flag == true) { bw.RunWorkerAsync(); flag = false; (sender as Button).Content = "End"; } else { flag = true; (sender as Button).Content = "Start"; } } void bw_DoWork(object sender, DoWorkEventArgs e) { while (!e.Cancel) { button2_Click(sender, new RoutedEventArgs()); System.Threading.Thread.Sleep(2000); //停2秒 e.Cancel = flag; } } List<string> list = new List<string>(); public void InitList() { list = System.IO.Directory.GetFiles("../../Image/").ToList(); bmList = new ObservableCollection<BitmapImage>(); for (int i = 1; i < list.Count; i++) { Uri url = new Uri(list[i].Substring(5), UriKind.Relative); BitmapImage bmImg = new BitmapImage(url); bmList.Add(bmImg); } } void CompositionTarget_Rendering(object sender, EventArgs e) { this.imgViewer.Source = bmList[index]; label1.Content = index.ToString(); this.imgViewer.Width = this.imgViewer.Source.Width; this.imgViewer.Height = this.imgViewer.Source.Height; } }
以上代码参考http://www.cnblogs.com/dreamzgj/archive/2012/02/29/2373850.html修改而成。
效果图如下:
如果单击start按钮,程序会自动浏览图片。
如果单击左右按钮,可以手动浏览。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Silverlight MMORPG网页游戏开发课程[一期] 第一课:控制对象移动
【WPF学习】第五十六章 基于帧的动画
【WPF学习】第五十五章 基于路径的动画
WPF 动画实战 点击时显示圆圈淡出效果
在Silverlight中使用定时器(Timer)
WinUI 3 试玩报告
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服