WPF 让子元素动起来!
在没有接触Blend之前,自己整出了一个MultiTouchHelper,这东西是做什么的呢?就是利用附加属性让元素可以多点触控。
然后某一天发现Blend里面有一个Behavior的东西,我去,原来有现成的一个叫TranslateZoomRoateBehavior!
第一反应,浪费了本码农两天时间!
第二反应,原来本码农的思想已经达到了这种境界(可以写出和大神类似的东西了),相信要不了多久,本码农就可以升职加薪,当上总经理,出任CEO,迎娶白富美,走上人生巅峰,想想还有点小激动呢,嘿嘿~~
第三反应,TranslateZoomRoateBehavior这玩意儿的名字老长了,而且得添加2个dll,这样的使用方法:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
<xxxUIElement>
<i:Interaction.Behaviors>
<ei:TranslateZoomRotateBehavior/>
</i:Interaction.Behaviors>
</xxxUIElement>
再来看本码农的短(chang)小(cu)~精悍的MultiTouchHelper,使用方法:
<Grid mt:MultiTouchHelper.IsContenter="True">
<xxxUIElement mt:MultiTouchHelper.MaxScale=""
mt:MultiTouchHelper.MinScale="0.5"
mt:MultiTouchHelper.ManipulationMode="All"
mt:MultiTouchHelper.WaitingForRecover="" />
</Grid>
mt:MultiTouchHelper.IsContenter:设定触摸的容器
mt:MultiTouchHelper.MaxScale:放大的最大倍数
mt:MultiTouchHelper.MinScale:缩小的最小倍数
mt:MultiTouchHelper.ManipulationMode:触摸方式
mt:MultiTouchHelper.WaitingForRecover: 恢复初始状态的等待时间
综合使用下来,细节方面TZRB不如MTH,例如MTH支持被触摸的元素置于最顶层,但是效率方面MTH似乎不如TZRB?
MultiTouchHelper会在以后再写一篇文章,下面进入我今天想说的话题(是不是前奏有点长?是不是像某种艺术片让人忍不住跳过~~)
需求:让ListBox中元素依次从左到右移动。 项目进行: 1、创建自定义控件,放个ListBox,遍历ListBox的子元素,为其添加动画,大功告成。
哎呀呀~项目进行的还真是顺利,果然动起来了,任务完成,相信要不了多久我就可以走向人生的巅峰了,想想还真是有点小激动呢~~ 客户:你这个框框太难看了,改改。 好吧,改改就改改。找到自定义控件=》ListBox=》ItemTemplate,嚯嚯嚯嚯!改好了,相信要不了多久就可以迎娶白富美,想想还真是有点小激动呢~~ 客户:你这东西做的不错,xxx页面也来一个。 好嘞,复制粘贴嘛,哪个不会嘛!哦呵呵,还真是有点小激动呢~~ 哎哟,数据实体不一样,子元素的样式不一样哎。再来一个自定义控件?嗯,是个好办法!想想还真是有点小激动呢~~ 等等……这样下去也不是办法啊,这也来一个那也来一个,啥时候升职加薪??? 哎,想想还真是有点小忧桑... 至此,CanvasItemBehavior横空出世,拯救苍生,造福人类……咳咳,请看:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Threading; namespace Near.Helper.Behaviors
{
public class CanvasItemBehavior
{ #region MoveMode 子级移动方式
public static MoveOrientaion GetMoveMode(Canvas obj)
{
return (MoveOrientaion)obj.GetValue(MoveModeProperty);
} public static void SetMoveMode(Canvas obj, MoveOrientaion value)
{
obj.SetValue(MoveModeProperty, value);
} // Using a DependencyProperty as the backing store for MoveMode. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MoveModeProperty =
DependencyProperty.RegisterAttached("MoveMode", typeof(MoveOrientaion), typeof(CanvasItemBehavior), new PropertyMetadata(MoveOrientaion.None, new PropertyChangedCallback(OnMoveModeChanged))); #endregion #region 存储动画
private static Storyboard GetStoryboard(DependencyObject obj)
{
return (Storyboard)obj.GetValue(StoryboardProperty);
} private static void SetStoryboard(DependencyObject obj, Storyboard value)
{
obj.SetValue(StoryboardProperty, value);
} // Using a DependencyProperty as the backing store for Storyboard. This enables animation, styling, binding, etc...
private static readonly DependencyProperty StoryboardProperty =
DependencyProperty.RegisterAttached("Storyboard", typeof(Storyboard), typeof(CanvasItemBehavior), new PropertyMetadata(null));
#endregion #region Duration 动画持续时间
public static Duration GetDuration(DependencyObject obj)
{
return (Duration)obj.GetValue(DurationProperty);
} public static void SetDuration(DependencyObject obj, Duration value)
{
obj.SetValue(DurationProperty, value);
} // Using a DependencyProperty as the backing store for Duration. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DurationProperty =
DependencyProperty.RegisterAttached("Duration", typeof(Duration), typeof(CanvasItemBehavior), new PropertyMetadata(Duration.Automatic));
#endregion #region 元素出来的时间间隔
//public static TimeSpan GetInterval(DependencyObject obj)
//{
// return (TimeSpan)obj.GetValue(IntervalProperty);
//} //public static void SetInterval(DependencyObject obj, TimeSpan value)
//{
// obj.SetValue(IntervalProperty, value);
//} //// Using a DependencyProperty as the backing store for Interval. This enables animation, styling, binding, etc...
//public static readonly DependencyProperty IntervalProperty =
// DependencyProperty.RegisterAttached("Interval", typeof(TimeSpan), typeof(CanvasItemBehavior), new PropertyMetadata(TimeSpan.Zero)); #endregion #region 泡泡模式时指定半径
public static double GetBubbleR(DependencyObject obj)
{
return (double)obj.GetValue(BubbleRProperty);
} public static void SetBubbleR(DependencyObject obj, double value)
{
obj.SetValue(BubbleRProperty, value);
} // Using a DependencyProperty as the backing store for BubbleR. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BubbleRProperty =
DependencyProperty.RegisterAttached("BubbleR", typeof(double), typeof(CanvasItemBehavior), new PropertyMetadata(double.NaN));
#endregion private static void OnMoveModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Canvas)
{
var canvas = d as Canvas;
if ((MoveOrientaion)e.NewValue != MoveOrientaion.None)
{
canvas.Loaded += canvas_Loaded;
}
//else
//{
// canvas.Loaded -= canvas_Loaded;
//}
} } static void canvas_Loaded(object sender, RoutedEventArgs e)
{
var canvas = sender as Canvas;
var mode = GetMoveMode(canvas); if (mode > )
{
var itemSource = VisualHelper.FindVisualParent<ListBox>(canvas).ItemsSource; if (itemSource is System.Collections.Specialized.INotifyCollectionChanged)
{
(itemSource as System.Collections.Specialized.INotifyCollectionChanged).CollectionChanged += (ss, ee) =>
{
if (ee.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
foreach (var item in ee.NewItems)
{
var lt = VisualHelper.FindVisualParent<ListBox>(canvas);
var itemBox = lt.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;
itemBox.Visibility = Visibility.Hidden;
itemBox.PreviewMouseDown += item_MouseDown;
itemBox.IsVisibleChanged += item_IsVisibleChanged;
} }
};
} foreach (UIElement item in canvas.Children)
{
item.Visibility = Visibility.Hidden;
item.PreviewMouseDown += item_MouseDown;
item.IsVisibleChanged += item_IsVisibleChanged;
} if (mode == MoveOrientaion.RightToLeft)
{
canvas.FlowDirection = FlowDirection.RightToLeft;
} var timer = new DispatcherTimer(); int index = ; timer.Interval = TimeSpan.FromMilliseconds(); timer.Tick += (ss, ee) =>
{
if (canvas.Children.Count > )
{
var item = canvas.Children[index++]; if (!item.IsVisible)
{
var t = TimeSpan.Zero; if ((int)mode < )
{
var speed = GetDuration(canvas) != Duration.Automatic ? canvas.ActualWidth / GetDuration(canvas).TimeSpan.Seconds : ; t = TimeSpan.FromSeconds(canvas.Children[].RenderSize.Width / speed);
}
else
{
var speed = GetDuration(canvas) != Duration.Automatic ? canvas.ActualHeight / GetDuration(canvas).TimeSpan.Seconds : ;
t = TimeSpan.FromSeconds(canvas.Children[].RenderSize.Height / speed);
} if (timer.Interval != t)
timer.Interval = t; if ((int)mode < )
{
Canvas.SetTop(item, GetRandom(canvas.ActualHeight - item.RenderSize.Height));
}
else
{
Canvas.SetLeft(item, GetRandom(canvas.ActualWidth - item.RenderSize.Width));
} item.Visibility = Visibility.Visible;
} if (index >= canvas.Children.Count)
index = ; //Console.WriteLine(item);
}
}; timer.Start();
} }
static void item_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var s = GetStoryboard(sender as UIElement);
if (s != null)
{
if (s.GetIsPaused())
s.Resume();
else
s.Pause();
}
} static void item_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
var item = sender as UIElement; if (GetStoryboard(item) == null)
{
var canvas = VisualTreeHelper.GetParent(item) as Canvas; var s = new Storyboard();
var ani = new DoubleAnimation();
Storyboard.SetTarget(ani, item); var mode = GetMoveMode(canvas); if ((int)mode < )
{
ani.From = - item.RenderSize.Width;
ani.To = canvas.ActualWidth;
ani.Duration = GetDuration(canvas) > TimeSpan.Zero ? GetDuration(canvas) : TimeSpan.FromSeconds(canvas.ActualWidth / );
Storyboard.SetTargetProperty(ani, new PropertyPath(Canvas.LeftProperty));
}
else if (mode == MoveOrientaion.TopToBottom)
{
ani.From = - item.RenderSize.Height;
ani.To = canvas.ActualHeight;
ani.Duration = GetDuration(canvas) > TimeSpan.Zero ? GetDuration(canvas) : TimeSpan.FromSeconds(canvas.ActualHeight / );
Storyboard.SetTargetProperty(ani, new PropertyPath(Canvas.TopProperty));
}
else if (mode == MoveOrientaion.BottomToTop)
{
ani.From = canvas.ActualHeight;
ani.To = - item.RenderSize.Height;
ani.Duration = GetDuration(canvas) > TimeSpan.Zero ? GetDuration(canvas) : TimeSpan.FromSeconds(canvas.ActualHeight / );
Storyboard.SetTargetProperty(ani, new PropertyPath(Canvas.TopProperty));
} s.Children.Add(ani); s.Completed += (ss, ee) =>
{
item.Visibility = Visibility.Hidden;
SetStoryboard(item, null);
}; SetStoryboard(item, s); s.Begin();
}
}
} static int GetRandom(int maxValue)
{
Random rd = new Random(Guid.NewGuid().GetHashCode());
return rd.Next(maxValue);
} static int GetRandom(double maxValue)
{
return GetRandom((int)maxValue);
} } public enum MoveOrientaion
{
None = -,
/// <summary>
/// 从左到右
/// </summary>
LeftToRight = ,
/// <summary>
/// 从右到左
/// </summary>
RightToLeft = ,
/// <summary>
/// 从上往下
/// </summary>
TopToBottom = ,
/// <summary>
/// 从下往上
/// </summary>
BottomToTop = ,
/// <summary>
/// 泡泡模式
/// </summary>
Bubble =
}
}
用法:
<ListBox Name="listBox">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas bh:CanvasItemBehavior.MoveMode="LeftToRight" bh:CanvasItemBehavior.Duration="0:0:6" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" Width="" Height=""/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
有了CanvasItemBehavior,妈妈再也不用担心我复制粘贴修改啦~~
CanvasItemBehavior目前只实现了水平、垂直方向上的依次移动,至于里面的Bubble(泡泡模式,也就是win系统的泡泡屏保效果)还没有实现,因为一通代码写下来,发现头都大了,什么数学啊物理啊,期待有志之士有趣之人实现这一效果的能够不吝赐教。
终于又写了一篇博客,相信要不了多久我就会被某位猎头看中,然后跳槽加薪,当上总经理,出任CEO,迎娶白富美,走上人生的巅峰,想想还真是有点小激动呢~~
注:有点小激动的想拍砖的童鞋,请轻拍。
WPF 让子元素动起来!的更多相关文章
- 让子元素在父元素中水平居中align-items
做案例中,我们会发现让子元素在父元素中垂直居中,要设置margin和padding等,各种设置才能垂直居中 现在可以使用CSS3中的align-items实现 align-items 定义子元素在父元 ...
- WPF与缓动(三) 指数缓动
原文:WPF与缓动(三) 指数缓动 WPF与缓动(三) 指数缓动 ...
- WPF与缓动(四) 弧形缓动
原文:WPF与缓动(四) 弧形缓动 WPF与缓动(四) 弧形缓动 ...
- WPF与缓动(二) 正弦与余弦缓动
原文:WPF与缓动(二) 正弦与余弦缓动 WPF与缓动(二) 正弦与余弦缓动 ...
- WPF与缓动(一) N次缓动
原文:WPF与缓动(一) N次缓动 WPF与缓动(一) N次缓动 ...
- 【C#】wpf添加gif动图支持
原文:[C#]wpf添加gif动图支持 1.nuget里下载XamlAnimatedGif包,然后安装. 2.添加XamlAnimatedGif包的命名空间:xmlns:gif="https ...
- WPF 获取元素(Visual)相对于屏幕设备的缩放比例,可用于清晰显示图片
原文:WPF 获取元素(Visual)相对于屏幕设备的缩放比例,可用于清晰显示图片 我们知道,在 WPF 中的坐标单位不是屏幕像素单位,所以如果需要知道某个控件的像素尺寸,以便做一些与屏幕像素尺寸相关 ...
- 七,WPF的元素绑定
数据绑定是一种关系,该关系告诉WPF从一个源对象提取一些信息,并使用这些信息设置目标对象的属性,目标属性总是依赖项属性,然而,源对象可以是任何内容. 源对象是WPF元素并且源属性是依赖项属性的数据绑定 ...
- WPF中元素拖拽的两个实例
今天结合之前做过的一些拖拽的例子来对这个方面进行一些总结,这里主要用两个例子来说明在WPF中如何使用拖拽进行操作,元素拖拽是一个常见的操作,第一个拖拽的例子是将ListBox中的子元素拖拽到ListV ...
随机推荐
- 深入理解Nginx之调试优化技巧
在开发过程中,我们经常会碰到段错误等异常,这时我们需要有相应的机制来进行调试,特别是服务提供在线上时,面对大量的日志信息,合理的调试处理机制对于开发来说是一件非常重要的事情,幸好Nginx本身提供了很 ...
- mkfifo
管道是Linux的十种文件类型之一,使用管道通信本质上还是以文件作为通信的媒介 有名管道+无名管道=管道 有名管道(FIFO文件):就是 有文件名的管道, 可以用于任意两个进程间的通信 无名管道(pi ...
- CentOS系统在不重启的情况下为虚拟机添加新硬盘
一.概述 用过虚拟机的都知道,如果在系统运行的时候去给虚拟机添加一块新设备,比如说硬盘,系统是读取不到这个新硬盘的,因为系统在启动的时候会去检测硬件设备.但是我们也可能会遇到这样的情况,比如正在运行比 ...
- Linux命令行上传文件到百度网盘
利用bpcs_uploader你可以自动将VPS主机上的文件上传到百度网盘中,同时也可以从百度网盘中下载文件到VPS主机上,让你的文件安全地"住"在百度云中.[font=Tahom ...
- linux线程同步(3)-读写锁
一.概述 读写锁与互斥量的功能类似,对临界区的共享资源进行保护!互斥量一次只让一个线程进入临界区, ...
- 鸿雁电器oa系统中决策支持模块效果
公司简介鸿雁电器是国内著名的建筑电器产品的生产.经营企业,同时也是国家863计划CIMS(计算机集成制造系统)应用工程示范企业.浙江省高新技术企业.浙江省专利示范企业和杭州市信息化试点企业.企业系统泛 ...
- 150923-碎觉要-PHP,Linux
今天懒懒的,还是每天都懒懒的. 早上下午都没有更.还好还有晚上更的想法和行动. 总结如下 1.PHP --wamp的一点配置问题,把根文件改为自己所要的文件夹.改动Apache的配置文件以及更改wam ...
- OpenXml入门
一. OpenXml简介: Open XML标准的简单介绍:Ecma Office Open XML(“Open XML”)是针对字处理文档.演示文稿和电子表格的国际化开放标准,可免费供多个应用程序在 ...
- [麦先生]TP3.2之微信开发那点事[基础篇](网页授权开发之小Demo)
用户à 点击按钮进入授权页面并确认授权à 服务器返回code给开发者à 利用code,APPID,APPsecret组合数据请求API获取access_token和openidà 利用access_t ...
- BZOJ2763[JLOI2011]飞行路线 [分层图最短路]
2763: [JLOI2011]飞行路线 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2523 Solved: 946[Submit][Statu ...