zoukankan      html  css  js  c++  java
  • 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="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 } }

    用法:

      <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="400" Height="300"/>
                    </DataTemplate>
                </ListBox.ItemTemplate>
      </ListBox>

    有了CanvasItemBehavior,妈妈再也不用担心我复制粘贴修改啦~~

    CanvasItemBehavior目前只实现了水平、垂直方向上的依次移动,至于里面的Bubble(泡泡模式,也就是win系统的泡泡屏保效果)还没有实现,因为一通代码写下来,发现头都大了,什么数学啊物理啊,期待有志之士有趣之人实现这一效果的能够不吝赐教。

    终于又写了一篇博客,相信要不了多久我就会被某位猎头看中,然后跳槽加薪,当上总经理,出任CEO,迎娶白富美,走上人生的巅峰,想想还真是有点小激动呢~~

    注:有点小激动的想拍砖的童鞋,请轻拍。

  • 相关阅读:
    冲刺阶段站立会议每日任务3
    冲刺阶段站立会议每日任务2
    典型场景描述
    冲刺阶段站立会议每天任务1
    第七周学习进度
    第六周学习进度
    四则运算网页版
    团队项目简介(1000字)
    返回一个二维整数数组中最大联通子数组的和
    本周学习进度
  • 原文地址:https://www.cnblogs.com/LCHL/p/3574745.html
Copyright © 2011-2022 走看看