WPF【无限滚动图片浏览】自定义控件

自定义控件

自定义控件是我比较陌生的一个主题。我好久没练习过wpf了,需要巩固记忆。我想了一会儿,打开动漫之家,忽然觉得这个看漫画的图片浏览控件有意思。于是特地花了一天做了这个图片控件。我原本以为很容易,但实际上并不简单。这个图片浏览控件比我想象中要难许多,有技术上的难题,也有逻辑上的难题。好在最后都解决了。

这个自定义控件算是比较好的练习。里面涉及了依赖属性 Binding 虚拟化加载 VisualState 动态资源 过渡效果 部件 光标这些东西。

光标制作

对于电脑端来说,一个好看的光标是必不可少的。于是我查询了资料,了解到一种比较简洁的自定义光标方式。就是制作光标文件,然后在XAML中直接使用。

xml 复制代码
<Button x:Name="P_Bleft" Opacity="0" Grid.Column="0" Cursor="/程序集;component/路径/left.cur">上一页</Button>
<Button x:Name="P_Bright" Opacity="0" Grid.Column="1" Cursor="/程序集;component/路径/right.cur">下一页</Button>

到哪里找图标呢呢?我想起了FontAwsome.V5 ,这个非常方便,并且美观。于是我到官网上找到了两个箭头图标。下一步是把图标转化成光标文件。FontAwsome.V5 提供了svg格式的图标复制,然后我在这个网站发现了-->在线转换器<--可以将svg转化为cur光标文件,它提供了每天10次的免费额度。但要注意,需要设定光标尺寸。可以设置另存为文件之后,把svg元素的WidthHeight属性改为16。

html 复制代码
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="16" height="16">

最后把光标文件放到项目中,以生成资源的形式编译。这里就能在XAML中直接使用了。如前面所示,是一个黑色箭头。

控制面板

作为一个图片浏览控件,控制面板必不可少。比较经典的做法是点击中间显示面板帮助。点击两边切换图片 。面板帮助我就暂且省略,就做了切换图片的功能。整个自定义控件的是一个Grid,分为2列,然后两个按钮各占1列,再把按钮隐藏起来。幸好,透明度为0时还能捕获事件。下方再重叠几个宽度为2列的Image控件作为视口。

控件结构

经过多次更改,最终我把这个自定义控件设计为了一个分为4层Z-Index的控件。

  • Z-Index=4 上一页、下一页
  • Z-Index=3 当前页
  • Z-Index=2 根据滑动方向确定的下一页
  • Z-Index=1 上一页和下一页Z-Index之间的分隔板
  • Z-Index=0 根据滑动方向确定的上一页
  • 底层容器Grid

这是我为了实现正常显示效果,再调试过程中一层层加上去的。但是XAML中没法给非Canvas子控件设置这个附加属性,所以这个附加属性只能在逻辑控件的代码中进行动态设置。这些设置代码与控件交互逻辑交织,本身就是控制逻辑的一部分。

csharp 复制代码
var P_Bleft = (Button)GetTemplateChild("P_Bleft");
P_Bleft.SetValue(Canvas.ZIndexProperty, 4);
P_Bright.SetValue(Canvas.ZIndexProperty, 4);
P_Bulkhead.SetValue(Canvas.ZIndexProperty, 1);

虚拟化加载

作为一个图片浏览器,把全部图片一次性加载出来是一个方便的选择,但不是一个明智的选择。所以我考虑了虚拟化加载 。最开始我想到了集合控件ListView。但是这个我需要过渡效果。集合控件似乎没有实现这个。并且对内容大小控制也不是很完美。我还是自己从0开始做。

我走了很多弯路,最后确定使用3个水平排列的Image控件进行图片的呈现。使用Storyboard时间线控制过渡效果。我把图片URL集合组织成一个环形,然后让这3个Image在环上移动,这样实现虚拟化加载。

首先是预加载当前页和下一页。点击下一页之后,图片控件向左移动,同时最左边的、移动到视口之外的Image控件加载下下一页。第二次点击时,把首次预加载的图片移动到视口内,再把第二次预加载的图片移动到下一页位置。第三次点击时,这个控件移动到视口内,每个控件都有类似的过程,循环往复。同时还要考虑方向,即点击上一页。所以这要在逻辑代码中判断处理。

我用简单的取模运算符将数据组织成环形

csharp 复制代码
//当前页
int state = (Current) % 3;

然后在一个switch结构中完成控制逻辑

csharp 复制代码
switch (state)
{
    case 0:
	//很多判断
	break;
    case 1:
	//很多判断
	break;
    case 2:
	//很多判断
	break;
}

swich结构中的几个重要工作是

  • 确定图片那3个Image 控件要从哪里移动到哪里,我选择高效的RenderTransform。位置一个有3个**-width、0、width**。每个控件在每个时刻,个占据一个位置
  • 计算不同时间,每个控件Z-Index的正确值。在前面已经指出了层级了。
  • 找到需要加载的图片,在合适的时机切换某个Image控件的图片源。经过我的碰壁,发现同一时间全部替换,是一个错误的做法。最后换成了每次点击值加载一张图片。即根据滑动方向,加载下下张。但要注意,在必要时时判断是否超出数组索引。
csharp 复制代码
//左移
P_Cimage.Source = new BitmapImage(new Uri(Urls[Current - 1]));
//右移
if(Current + 1 < Urls.Count)
{
    P_Cimage.Source = new BitmapImage(new Uri(Urls[Current + 1]));
}

使用VisualState可以简化这种管理。我把这种切换设计为3个状态Normal R_Translate L_Translate。在不同状态时,3个图片控件分别占据不同位置,然后根据数据组织的环形结构进行状态切换。

这里比较麻烦的地方在于,状态中的动画没法没法绑定到依赖属性,其次也没法用动态资源进行切换属性值。还是得到逻辑代码中进行控制。

csharp 复制代码
P_BL.RenderTransform.Value.Translate(-P_BC.ActualWidth, 0);
P_BC.RenderTransform.Value.Translate(0, 0);
P_BR.RenderTransform.Value.Translate(P_BC.ActualWidth, 0);

d4_.To = -P_BC.ActualWidth;
d5_.To = 0;
d6_.To = P_BC.ActualWidth;

d4.From = 0;
d5.From = P_BC.ActualWidth;
d6.From = -P_BC.ActualWidth;

为了响应控件大小变化后,动画元素还能够精确到达所需偏移位置,就要每次点击前微调 控件位置。要让Image 元素的RenderTransform 使用DynamicResource,才能在代码中进行更新位置。全屏后点击下一页,下一页Image 控件的偏移量是1920,但求出全屏后,需要的偏移量就小多了,需要根据控件大小动态计算。主要原因是因为这里要使用动画,不然的话,使用布局计算可能是是一个比较好的方式。

xml 复制代码
<Border x:Name="P_BL" Grid.Column="0" Grid.ColumnSpan="2" Background="LightPink">
    <Border.RenderTransform>
        <TranslateTransform X="{DynamicResource left}"/>
    </Border.RenderTransform>
    <Image x:Name="P_Limage"/>
</Border>

完整代码

Generic.xaml

xml 复制代码
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Pictures" 
    xmlns:sys="clr-namespace:System;assembly=mscorlib" 
    xmlns:sys2="http://schemas.microsoft.com/netfx/2009/xaml/presentation">
    
    <!--<local:NegativeValueConverter x:Key="NegativeValueConverter"/>-->
    <sys:Double x:Key="left">-1200</sys:Double>
    <sys:Double x:Key="right">1200</sys:Double>
    <sys2:Duration x:Key="dur">0:0:0.2</sys2:Duration>
    <sys2:PowerEase EasingMode="EaseOut" Power="0.3" x:Key="ea"/>


    <Style TargetType="{x:Type local:CustomControl2}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:CustomControl2}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition/>
                                <ColumnDefinition/>
                            </Grid.ColumnDefinitions>
                            <Border x:Name="P_Bulkhead" Grid.Column="0" Grid.ColumnSpan="2" Background="White"></Border>
                            <Border x:Name="P_BC" Grid.Column="0" Grid.ColumnSpan="2" Background="LightGreen">
                                <Border.RenderTransform>
                                    <!--这个始终为零就不需要使用资源了-->
                                    <TranslateTransform X="0"/>
                                </Border.RenderTransform>
                                <Image x:Name="P_Cimage"/>
                            </Border>
                            <Border x:Name="P_BL" Grid.Column="0" Grid.ColumnSpan="2" Background="LightPink">
                                <Border.RenderTransform>
                                    <TranslateTransform X="{DynamicResource left}"/>
                                </Border.RenderTransform>
                                <Image x:Name="P_Limage"/>
                            </Border>
                            <Border x:Name="P_BR" Grid.Column="0" Grid.ColumnSpan="2" Background="LightBlue">
                                <Border.RenderTransform>
                                    <TranslateTransform X="{DynamicResource right}"/>
                                </Border.RenderTransform>
                                <Image x:Name="P_Rimage"/>
                            </Border>
                            <TextBlock Grid.Column="2" Text="{Binding Current, RelativeSource={RelativeSource TemplatedParent}, StringFormat='{}{0}'}"/>
                            <Button x:Name="P_Bleft" Opacity="0" Grid.Column="0" Cursor="/Pictures;component/images/left.cur">上一页</Button>
                            <Button x:Name="P_Bright" Opacity="0" Grid.Column="1" Cursor="/Pictures;component/images/right.cur">下一页</Button>

                        </Grid>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="group1">
                                <VisualState x:Name="Normal">
                                    <Storyboard>
                                        <DoubleAnimation x:Name="d1_" Storyboard.TargetName="P_BL" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="0:0:0" To="{DynamicResource left}"/>
                                        <DoubleAnimation x:Name="d2_" Storyboard.TargetName="P_BC" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="0:0:0" To="0"/>
                                        <DoubleAnimation x:Name="d3_" Storyboard.TargetName="P_BR" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="0:0:0" To="{DynamicResource right}"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="R_Translate">
                                    <Storyboard>
                                        <DoubleAnimation x:Name="d4_" Storyboard.TargetName="P_BC" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="0:0:0" To="{DynamicResource left}"/>
                                        <DoubleAnimation x:Name="d5_" Storyboard.TargetName="P_BR" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="0:0:0" To="0"/>
                                        <DoubleAnimation x:Name="d6_" Storyboard.TargetName="P_BL" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="0:0:0" To="{DynamicResource right}"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="L_Translate">
                                    <Storyboard>
                                        <DoubleAnimation x:Name="d7_" Storyboard.TargetName="P_BR" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="0:0:0" To="{DynamicResource left}"/>
                                        <DoubleAnimation x:Name="d8_" Storyboard.TargetName="P_BL" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="0:0:0" To="0"/>
                                        <DoubleAnimation x:Name="d9_" Storyboard.TargetName="P_BC" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="0:0:0" To="{DynamicResource right}"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualStateGroup.Transitions>
                                    <VisualTransition To="Normal">
                                        <Storyboard>
                                            <DoubleAnimation x:Name="d1" Storyboard.TargetName="P_BL" EasingFunction="{StaticResource ea}" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="{StaticResource dur}" To="{DynamicResource left}"/>
                                            <DoubleAnimation x:Name="d2" Storyboard.TargetName="P_BC" EasingFunction="{StaticResource ea}" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="{StaticResource dur}" To="0"/>
                                            <DoubleAnimation x:Name="d3" Storyboard.TargetName="P_BR" EasingFunction="{StaticResource ea}" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="{StaticResource dur}" To="{DynamicResource right}"/>
                                        </Storyboard>
                                    </VisualTransition>
                                    <VisualTransition To="R_Translate">
                                        <Storyboard>
                                            <DoubleAnimation x:Name="d4" Storyboard.TargetName="P_BC" EasingFunction="{StaticResource ea}" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="{StaticResource dur}" To="{DynamicResource left}"/>
                                            <DoubleAnimation x:Name="d5" Storyboard.TargetName="P_BR" EasingFunction="{StaticResource ea}" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="{StaticResource dur}" To="0"/>
                                            <DoubleAnimation x:Name="d6" Storyboard.TargetName="P_BL" EasingFunction="{StaticResource ea}" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="{StaticResource dur}" To="{DynamicResource right}"/>
                                        </Storyboard>
                                    </VisualTransition>
                                    <VisualTransition To="L_Translate">
                                        <Storyboard>
                                            <DoubleAnimation x:Name="d7" Storyboard.TargetName="P_BR" EasingFunction="{StaticResource ea}" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="{StaticResource dur}" To="{DynamicResource left}"/>
                                            <DoubleAnimation x:Name="d8" Storyboard.TargetName="P_BL" EasingFunction="{StaticResource ea}" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="{StaticResource dur}" To="0"/>
                                            <DoubleAnimation x:Name="d9" Storyboard.TargetName="P_BC" EasingFunction="{StaticResource ea}" Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)" Duration="{StaticResource dur}" To="{DynamicResource right}"/>
                                        </Storyboard>
                                    </VisualTransition>
                                </VisualStateGroup.Transitions>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

后台代码

csharp 复制代码
namespace Pictures
{
    [TemplatePart(Name = "P_Bleft",Type = typeof(Button))]
    [TemplatePart(Name = "P_Bright", Type = typeof(Button))]
    [TemplatePart(Name = "P_Limage", Type = typeof(Image))]
    [TemplatePart(Name = "P_Cimage", Type = typeof(Image))]
    [TemplatePart(Name = "P_Rimage", Type = typeof(Image))]
    [TemplatePart(Name = "P_BC", Type = typeof(Border))]
    [TemplatePart(Name = "P_BL", Type = typeof(Border))]
    [TemplatePart(Name = "P_BR", Type = typeof(Border))]
    [TemplatePart(Name = "P_Bulkhead",Type =typeof(Border))]
    [TemplatePart(Name = "P_BC", Type = typeof(Border))]
    [TemplatePart(Name = "P_BL", Type = typeof(Border))]
    [TemplatePart(Name = "P_BR", Type = typeof(Border))]
    [TemplateVisualState(GroupName = "group1",Name = "L_Translate")]
    [TemplateVisualState(GroupName = "group1", Name = "R_Translate")]
    [TemplateVisualState(GroupName = "group1", Name = "Normal")]
    [TemplatePart(Name = "d1", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d2", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d3", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d4", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d5", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d6", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d7", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d8", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d9", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d1_", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d2_", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d3_", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d4_", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d5_", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d6_", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d7_", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d8_", Type = typeof(DoubleAnimation))]
    [TemplatePart(Name = "d9_", Type = typeof(DoubleAnimation))]
    public class CustomControl2 : Control
    {
        public const string L_Translate = "L_Translate";
        public const string R_Translate = "R_Translate";
        public const string Normal = "Normal";
        static CustomControl2()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl2), new FrameworkPropertyMetadata(typeof(CustomControl2)));
        }

        /// <summary>
        /// 当前页
        /// </summary>
        public int Current
        {
            get { return (int)GetValue(CurrentProperty); }
            set { SetValue(CurrentProperty, value); }
        }

        public static readonly DependencyProperty CurrentProperty =
            DependencyProperty.Register("Current", typeof(int), typeof(CustomControl2), new PropertyMetadata(0));

        /// <summary>
        /// 图片
        /// </summary>
        public ObservableCollection<string> Urls
        {
            get { return (ObservableCollection<string>)GetValue(UrlsProperty); }
            set { SetValue(UrlsProperty, value); }
        }
        public static readonly DependencyProperty UrlsProperty =
            DependencyProperty.Register("Urls", typeof(ObservableCollection<string>), typeof(CustomControl2), new PropertyMetadata(null, OnUrlsChanged));
        private static void OnUrlsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CustomControl2 control = d as CustomControl2;
            if (control != null)
            {
                control.OnUrlsChanged((ObservableCollection<string>)e.OldValue, (ObservableCollection<string>)e.NewValue);
            }
        }

        private void OnUrlsChanged(ObservableCollection<string> oldValue, ObservableCollection<string> newValue)
        {
            Current = 0;
            BeginStoryBoard(0, true);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            Button P_Bleft = (Button)GetTemplateChild("P_Bleft");
            Button P_Bright = (Button)GetTemplateChild("P_Bright");
            //隔板
            Border P_Bulkhead = (Border)GetTemplateChild("P_Bulkhead");
            P_Bleft.SetValue(Canvas.ZIndexProperty, 4);
            P_Bright.SetValue(Canvas.ZIndexProperty, 4);
            P_Bulkhead.SetValue(Canvas.ZIndexProperty, 1);
            P_Bleft.Click += (s, e) => ToPage(-1);
            P_Bright.Click += (s, e) => ToPage(1);
        }

        private void ToPage(int offset)
        {
            if (Current==0 && offset<0)
            {
                return;
            }
            if (Current>=Urls.Count-1 && offset>0)
            {
                return;
            }
            Current += offset;

            BeginStoryBoard(offset);
        }

        private void BeginStoryBoard(int offset,bool init=false)
        {
            Image P_Cimage = (Image)GetTemplateChild("P_Cimage");
            Image P_Limage = (Image)GetTemplateChild("P_Limage");
            Image P_Rimage = (Image)GetTemplateChild("P_Rimage");
            Border P_BC = (Border)GetTemplateChild("P_BC");
            Border P_BL = (Border)GetTemplateChild("P_BL");
            Border P_BR = (Border)GetTemplateChild("P_BR");
            Application.Current.Resources["left"]= -P_BC.ActualWidth;
            Application.Current.Resources["right"] = P_BC.ActualWidth;
            //当前页
            int state = (Current) % 3;

            //由于动画不能绑定To属性,只能在代码中动态调整
            #region 调整状态
            DoubleAnimation d1 = (DoubleAnimation)GetTemplateChild("d1");
            DoubleAnimation d2 = (DoubleAnimation)GetTemplateChild("d2");
            DoubleAnimation d3 = (DoubleAnimation)GetTemplateChild("d3");
            DoubleAnimation d4 = (DoubleAnimation)GetTemplateChild("d4");
            DoubleAnimation d5 = (DoubleAnimation)GetTemplateChild("d5");
            DoubleAnimation d6 = (DoubleAnimation)GetTemplateChild("d6");
            DoubleAnimation d7 = (DoubleAnimation)GetTemplateChild("d7");
            DoubleAnimation d8 = (DoubleAnimation)GetTemplateChild("d8");
            DoubleAnimation d9 = (DoubleAnimation)GetTemplateChild("d9");
            DoubleAnimation d1_ = (DoubleAnimation)GetTemplateChild("d1_");
            DoubleAnimation d2_ = (DoubleAnimation)GetTemplateChild("d2_");
            DoubleAnimation d3_ = (DoubleAnimation)GetTemplateChild("d3_");
            DoubleAnimation d4_ = (DoubleAnimation)GetTemplateChild("d4_");
            DoubleAnimation d5_ = (DoubleAnimation)GetTemplateChild("d5_");
            DoubleAnimation d6_ = (DoubleAnimation)GetTemplateChild("d6_");
            DoubleAnimation d7_ = (DoubleAnimation)GetTemplateChild("d7_");
            DoubleAnimation d8_ = (DoubleAnimation)GetTemplateChild("d8_");
            DoubleAnimation d9_ = (DoubleAnimation)GetTemplateChild("d9_");
            d1.To = -P_BC.ActualWidth;
            d2.To = 0;
            d3.To = P_BC.ActualWidth;
            d4.To = -P_BC.ActualWidth;
            d5.To = 0;
            d6.To = P_BC.ActualWidth;
            d7.To = -P_BC.ActualWidth;
            d8.To = 0;
            d9.To = P_BC.ActualWidth;
            d1_.To = -P_BC.ActualWidth;
            d2_.To = 0;
            d3_.To = P_BC.ActualWidth;
            d4_.To = -P_BC.ActualWidth;
            d5_.To = 0;
            d6_.To = P_BC.ActualWidth;
            d7_.To = -P_BC.ActualWidth;
            d8_.To = 0;
            d9_.To = P_BC.ActualWidth;
            #endregion

            switch (state)
            {
                case 0:
                    P_BC.SetValue(Canvas.ZIndexProperty, 3);
                    if (init)
                    {
                        if (Urls.Count>0)
                        {
                            P_Cimage.Source = new BitmapImage(new Uri(Urls[0]));
                        }
                        if (Urls.Count > 1)
                        {
                            P_Rimage.Source = new BitmapImage(new Uri(Urls[1]));
                        }
                        P_BL.RenderTransform.Value.Translate(-P_BC.ActualWidth, 0);
                        P_BC.RenderTransform.Value.Translate(0, 0);
                        P_BR.RenderTransform.Value.Translate(P_BC.ActualWidth, 0);
                    }
                    else
                    {
                        if (offset==1)
                        {
                            //右移
                            if(Current + 1 < Urls.Count)
                            {
                                P_Rimage.Source = new BitmapImage(new Uri(Urls[Current + 1]));
                            }
                            P_BL.SetValue(Canvas.ZIndexProperty, 2);
                            P_BR.SetValue(Canvas.ZIndexProperty, 0);
                            d1.From = 0;
                            d2.From = P_BC.ActualWidth;
                            d3.From = -P_BC.ActualWidth;
                        }
                        if (offset==-1)
                        {
                            //左移
                            if (Current>0)
                            {
                                P_Limage.Source = new BitmapImage(new Uri(Urls[Current - 1]));
                            }
                            P_BL.SetValue(Canvas.ZIndexProperty, 0);
                            P_BR.SetValue(Canvas.ZIndexProperty, 2);
                            d1.From = P_BC.ActualWidth;
                            d2.From = -P_BC.ActualWidth;
                            d3.From = 0;
                        }
                    }
                    VisualStateManager.GoToState(this, Normal, true);
                    break;
                case 1:
                    P_BR.SetValue(Canvas.ZIndexProperty, 3);
                    if (offset == 1)
                    {
                        //右移
                        if (Current+1<Urls.Count)
                        {
                            P_Limage.Source = new BitmapImage(new Uri(Urls[Current + 1]));
                        }
                        P_BC.SetValue(Canvas.ZIndexProperty, 2);
                        P_BL.SetValue(Canvas.ZIndexProperty, 0);
                        d4.From = 0;
                        d5.From = P_BC.ActualWidth;
                        d6.From = -P_BC.ActualWidth;
                    }
                    if (offset == -1)
                    {
                        //左移
                        P_Cimage.Source = new BitmapImage(new Uri(Urls[Current - 1]));
                        P_BC.SetValue(Canvas.ZIndexProperty, 0);
                        P_BL.SetValue(Canvas.ZIndexProperty, 2);
                        d4.From = P_BC.ActualWidth;
                        d5.From = -P_BC.ActualWidth;
                        d6.From = 0;
                    }
                    VisualStateManager.GoToState(this, R_Translate, true);
                    break;
                case 2:
                    P_BL.SetValue(Canvas.ZIndexProperty, 3);
                    if (offset == 1)
                    {
                        //右移
                        if(Current + 1 < Urls.Count)
                        {
                            P_Cimage.Source = new BitmapImage(new Uri(Urls[Current + 1]));
                        }
                        P_BC.SetValue(Canvas.ZIndexProperty, 0);
                        P_BR.SetValue(Canvas.ZIndexProperty, 2);
                        d7.From=0;
                        d8.From = P_BC.ActualWidth;
                        d9.From=-P_BC.ActualWidth;
                    }
                    if (offset == -1)
                    {
                        //左移
                        P_Rimage.Source = new BitmapImage(new Uri(Urls[Current - 1]));
                        P_BC.SetValue(Canvas.ZIndexProperty, 2);
                        P_BR.SetValue(Canvas.ZIndexProperty, 0);
                        d7.From = P_BC.ActualWidth;
                        d8.From = -P_BC.ActualWidth;
                        d9.From = 0;
                    }
                    VisualStateManager.GoToState(this, L_Translate, true);
                    break;
            }
        }
    }
}
相关推荐
漫谈网络3 天前
KVM创建的虚拟机,虚拟机的网卡是如何生成的
运维·服务器·网络·qemu·虚拟化·kvm
玖笙&3 天前
✨WPF编程基础【2.1】布局原则
c++·wpf·visual studio
玖笙&3 天前
✨WPF编程基础【2.2】:布局面板实战
c++·wpf·visual studio
SEO-狼术3 天前
.NET WPF 数据编辑器集合提供列表框控件
.net·wpf
FuckPatience7 天前
WPF 具有跨线程功能的UI元素
wpf
诗仙&李白7 天前
HEFrame.WpfUI :一个现代化的 开源 WPF UI库
ui·开源·wpf
He BianGu7 天前
【笔记】在WPF中Binding里的详细功能介绍
笔记·wpf
He BianGu7 天前
【笔记】在WPF中 BulletDecorator 的功能、使用方式并对比 HeaderedContentControl 与常见 Panel 布局的区别
笔记·wpf
123梦野8 天前
WPF——效果和可视化对象
wpf
He BianGu8 天前
【笔记】在WPF中Decorator是什么以及何时优先考虑 Decorator 派生类
笔记·wpf