在沒有接觸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="4" mt:MultiTouchHelper.MinScale="0.5" mt:MultiTouchHelper.ManipulationMode="All" mt:MultiTouchHelper.WaitingForRecover="500" /> </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 > 0)
{
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 = 0;
timer.Interval = TimeSpan.FromMilliseconds(50);
timer.Tick += (ss, ee) =>
{
if (canvas.Children.Count > 1)
{
var item = canvas.Children[index++];
if (!item.IsVisible)
{
var t = TimeSpan.Zero;
if ((int)mode < 3)
{
var speed = GetDuration(canvas) != Duration.Automatic ? canvas.ActualWidth / GetDuration(canvas).TimeSpan.Seconds : 100;
t = TimeSpan.FromSeconds(canvas.Children[0].RenderSize.Width / speed);
}
else
{
var speed = GetDuration(canvas) != Duration.Automatic ? canvas.ActualHeight / GetDuration(canvas).TimeSpan.Seconds : 100;
t = TimeSpan.FromSeconds(canvas.Children[0].RenderSize.Height / speed);
}
if (timer.Interval != t)
timer.Interval = t;
if ((int)mode < 3)
{
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 = 0;
//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 < 3)
{
ani.From = 0 - item.RenderSize.Width;
ani.To = canvas.ActualWidth;
ani.Duration = GetDuration(canvas) > TimeSpan.Zero ? GetDuration(canvas) : TimeSpan.FromSeconds(canvas.ActualWidth / 100);
Storyboard.SetTargetProperty(ani, new PropertyPath(Canvas.LeftProperty));
}
else if (mode == MoveOrientaion.TopToBottom)
{
ani.From = 0 - item.RenderSize.Height;
ani.To = canvas.ActualHeight;
ani.Duration = GetDuration(canvas) > TimeSpan.Zero ? GetDuration(canvas) : TimeSpan.FromSeconds(canvas.ActualHeight / 100);
Storyboard.SetTargetProperty(ani, new PropertyPath(Canvas.TopProperty));
}
else if (mode == MoveOrientaion.BottomToTop)
{
ani.From = canvas.ActualHeight;
ani.To = 0 - item.RenderSize.Height;
ani.Duration = GetDuration(canvas) > TimeSpan.Zero ? GetDuration(canvas) : TimeSpan.FromSeconds(canvas.ActualHeight / 100);
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 = -1,
/// <summary>
/// 從左到右
/// </summary>
LeftToRight = 1,
/// <summary>
/// 從右到左
/// </summary>
RightToLeft = 2,
/// <summary>
/// 從上往下
/// </summary>
TopToBottom = 3,
/// <summary>
/// 從下往上
/// </summary>
BottomToTop = 4,
/// <summary>
/// 泡泡模式
/// </summary>
Bubble = 0
}
}
本欄目