当前位置:网站首页>WPF 实现平移控件
WPF 实现平移控件
2022-07-29 11:31:00 【yanjinhua】
分享一个 WPF 实现平移控件
Windows 软件快捷小工具
作者:WPFDevelopersOrg
原文链接:https://github.com/WPFDevelopersOrg/WPFDevelopers
PanningItems平滑控件是Microsoft.Expression.Drawing中的控件,支持鼠标 水平|垂直滑动和触摸屏 水平|垂直滑动,但美中不足 不支持自动平滑,所以需要我们自己实现;实现方式使用定时器 DispatcherTimer默认控制 5 秒自动平滑到下一张图片;
1)PanningItems.cs 代码如下;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using WPFDevelopers.Helpers;
namespace Microsoft.Expression.Drawing.Controls
{
public class PanningItems : Selector
{
private DispatcherTimer timer;
static PanningItems()
{
SelectedItemProperty.OverrideMetadata(typeof(PanningItems), new FrameworkPropertyMetadata(new PropertyChangedCallback(selectedItemChanged)));
FrameworkElementFactory frameworkElementFactory = new FrameworkElementFactory(typeof(Grid));
frameworkElementFactory.SetValue(ClipToBoundsProperty, true);
FrameworkElementFactory frameworkElementFactory2 = new FrameworkElementFactory(typeof(ContentPresenter));
Binding binding = new Binding();
binding.RelativeSource = RelativeSource.TemplatedParent;
binding.Path = new PropertyPath(PreviousItemProperty);
frameworkElementFactory2.SetBinding(ContentPresenter.ContentProperty, binding);
Binding binding2 = new Binding();
binding2.RelativeSource = RelativeSource.TemplatedParent;
binding2.Path = new PropertyPath(ItemTemplateProperty);
frameworkElementFactory2.SetBinding(ContentPresenter.ContentTemplateProperty, binding2);
frameworkElementFactory2.Name = "Previous";
frameworkElementFactory.AppendChild(frameworkElementFactory2);
FrameworkElementFactory frameworkElementFactory3 = new FrameworkElementFactory(typeof(ContentPresenter));
Binding binding3 = new Binding();
binding3.RelativeSource = RelativeSource.TemplatedParent;
binding3.Path = new PropertyPath(SelectedItemProperty);
frameworkElementFactory3.SetBinding(ContentPresenter.ContentProperty, binding3);
Binding binding4 = new Binding();
binding4.RelativeSource = RelativeSource.TemplatedParent;
binding4.Path = new PropertyPath(ItemTemplateProperty);
frameworkElementFactory3.SetBinding(ContentPresenter.ContentTemplateProperty, binding4);
frameworkElementFactory3.Name = "Current";
frameworkElementFactory.AppendChild(frameworkElementFactory3);
FrameworkElementFactory frameworkElementFactory4 = new FrameworkElementFactory(typeof(ContentPresenter));
Binding binding5 = new Binding();
binding5.RelativeSource = RelativeSource.TemplatedParent;
binding5.Path = new PropertyPath(NextItemProperty);
frameworkElementFactory4.SetBinding(ContentPresenter.ContentProperty, binding5);
Binding binding6 = new Binding();
binding6.RelativeSource = RelativeSource.TemplatedParent;
binding6.Path = new PropertyPath(ItemTemplateProperty);
frameworkElementFactory4.SetBinding(ContentPresenter.ContentTemplateProperty, binding6);
frameworkElementFactory4.Name = "Next";
frameworkElementFactory.AppendChild(frameworkElementFactory4);
ControlTemplate controlTemplate = new ControlTemplate(typeof(PanningItems));
controlTemplate.VisualTree = frameworkElementFactory;
Style style = new Style(typeof(PanningItems));
Setter item = new Setter(TemplateProperty, controlTemplate);
style.Setters.Add(item);
style.Seal();
StyleProperty.OverrideMetadata(typeof(PanningItems), new FrameworkPropertyMetadata(style));
}
public PanningItems()
{
SelectedIndex = 0;
}
public Orientation ScrollDirection
{
get
{
return (Orientation)GetValue(ScrollDirectionProperty);
}
set
{
SetValue(ScrollDirectionProperty, value);
}
}
public double FlickTolerance
{
get
{
return (double)GetValue(FlickToleranceProperty);
}
set
{
SetValue(FlickToleranceProperty, value);
}
}
public object PreviousItem
{
get
{
return GetValue(PreviousItemProperty);
}
set
{
SetValue(PreviousItemProperty, value);
}
}
public object NextItem
{
get
{
return GetValue(NextItemProperty);
}
set
{
SetValue(NextItemProperty, value);
}
}
public bool LoopContents
{
get
{
return (bool)GetValue(LoopContentsProperty);
}
set
{
SetValue(LoopContentsProperty, value);
}
}
public double SliderValue
{
get
{
return (double)GetValue(SliderValueProperty);
}
set
{
SetValue(SliderValueProperty, value);
}
}
public int Seconds
{
get
{
return (int)GetValue(SecondsProperty);
}
set
{
SetValue(SecondsProperty, value);
}
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
previousTransform = new TranslateTransform();
previous = (ContentPresenter)Template.FindName("Previous", this);
if (previous != null)
{
previous.Opacity = 0.0;
previous.RenderTransform = previousTransform;
}
currentTransform = new TranslateTransform();
current = (ContentPresenter)Template.FindName("Current", this);
if (current != null)
{
current.RenderTransform = currentTransform;
}
nextTransform = new TranslateTransform();
next = (ContentPresenter)Template.FindName("Next", this);
if (next != null)
{
next.Opacity = 0.0;
next.RenderTransform = nextTransform;
}
timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(Seconds) };
var w = SystemParameters.WorkArea.Width;
var h = SystemParameters.WorkArea.Height;
timer.Tick += delegate
{
var point = new Point(w, 0);
var point1 = new Point(w/5, 0);
Vector vector = point - point1;
if (ScrollDirection == Orientation.Horizontal)
{
SliderValue = vector.X / current.ActualWidth;
}
else
{
SliderValue = vector.Y / current.ActualHeight;
}
if (Math.Abs(SliderValue) >= FlickTolerance)
{
isDragging = false;
int num = SelectedIndex;
if (num != -1)
{
if (SliderValue > 0.0)
{
num--;
SliderValue -= 1.0;
}
else
{
num++;
SliderValue += 1.0;
}
num += Items.Count;
num %= Items.Count;
SelectedIndex = num;
}
AnimateSliderValueTo(0.0);
}
};
timer.Start();
}
protected override void OnMouseDown(MouseButtonEventArgs e)
{
CaptureMouse();
OnGestureDown(e.GetPosition(this));
base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseButtonEventArgs e)
{
OnGestureUp();
ReleaseMouseCapture();
base.OnMouseUp(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
OnGestureMove(e.GetPosition(this));
base.OnMouseMove(e);
}
protected override void OnLostMouseCapture(MouseEventArgs e)
{
OnGestureUp();
base.OnLostMouseCapture(e);
}
protected override void OnTouchDown(TouchEventArgs e)
{
CaptureTouch(e.TouchDevice);
OnGestureDown(e.GetTouchPoint(this).Position);
base.OnTouchDown(e);
}
protected override void OnTouchUp(TouchEventArgs e)
{
OnGestureUp();
ReleaseTouchCapture(e.TouchDevice);
base.OnTouchUp(e);
}
protected override void OnTouchMove(TouchEventArgs e)
{
OnGestureMove(e.GetTouchPoint(this).Position);
base.OnTouchMove(e);
}
protected override void OnLostTouchCapture(TouchEventArgs e)
{
OnGestureUp();
base.OnLostTouchCapture(e);
}
private static void SecondsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var panningItems = (PanningItems)d;
if (panningItems == null)return;
if (panningItems.timer != null)
{
panningItems.timer.Stop();
panningItems.timer.Interval = TimeSpan.FromSeconds(panningItems.Seconds);
panningItems.timer.Start();
}
}
private static void flickToleranceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
}
private static object coerceFlickTolerance(DependencyObject sender, object value)
{
double val = (double)value;
return Math.Max(Math.Min(1.0, val), 0.0);
}
private static void sliderValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
PanningItems panningItems = (PanningItems)sender;
if (panningItems.previous != null && panningItems.current != null && panningItems.next != null)
{
panningItems.previous.Opacity = 1.0;
panningItems.next.Opacity = 1.0;
if (panningItems.ScrollDirection == Orientation.Horizontal)
{
panningItems.previousTransform.X = panningItems.current.ActualWidth * (panningItems.SliderValue - 1.0);
panningItems.currentTransform.X = panningItems.current.ActualWidth * panningItems.SliderValue;
panningItems.nextTransform.X = panningItems.current.ActualWidth * (panningItems.SliderValue + 1.0);
panningItems.previousTransform.Y = 0.0;
panningItems.currentTransform.Y = 0.0;
panningItems.nextTransform.Y = 0.0;
return;
}
panningItems.previousTransform.X = 0.0;
panningItems.currentTransform.X = 0.0;
panningItems.nextTransform.X = 0.0;
panningItems.previousTransform.Y = panningItems.current.ActualHeight * (panningItems.SliderValue - 1.0);
panningItems.currentTransform.Y = panningItems.current.ActualHeight * panningItems.SliderValue;
panningItems.nextTransform.Y = panningItems.current.ActualHeight * (panningItems.SliderValue + 1.0);
}
}
private static void selectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
PanningItems panningItems = (PanningItems)sender;
int selectedIndex = panningItems.SelectedIndex;
if (selectedIndex == -1 || panningItems.Items.Count == 0)
{
panningItems.PreviousItem = null;
panningItems.NextItem = null;
return;
}
if (selectedIndex == 0)
{
if (panningItems.LoopContents)
{
panningItems.PreviousItem = panningItems.Items[panningItems.Items.Count - 1];
}
else
{
panningItems.PreviousItem = null;
}
}
else
{
panningItems.PreviousItem = panningItems.Items[selectedIndex - 1];
}
if (selectedIndex != panningItems.Items.Count - 1)
{
panningItems.NextItem = panningItems.Items[selectedIndex + 1];
return;
}
if (panningItems.LoopContents)
{
panningItems.NextItem = panningItems.Items[0];
return;
}
panningItems.NextItem = null;
}
private void OnGestureDown(Point point)
{
touchDown = point;
isDragging = true;
}
private void OnGestureUp()
{
if (isDragging)
{
AnimateSliderValueTo(0.0);
}
isDragging = false;
}
private void OnGestureMove(Point point)
{
if (isDragging)
{
Vector vector = point - touchDown;
if (ScrollDirection == Orientation.Horizontal)
{
SliderValue = vector.X / current.ActualWidth;
}
else
{
SliderValue = vector.Y / current.ActualHeight;
}
if (Math.Abs(SliderValue) >= FlickTolerance)
{
isDragging = false;
int num = SelectedIndex;
if (num != -1)
{
if (SliderValue > 0.0)
{
num--;
SliderValue -= 1.0;
}
else
{
num++;
SliderValue += 1.0;
}
num += Items.Count;
num %= Items.Count;
SelectedIndex = num;
}
AnimateSliderValueTo(0.0);
}
}
}
private void AnimateSliderValueTo(double target)
{
DoubleAnimation doubleAnimation = new DoubleAnimation(target, new Duration(TimeSpan.FromSeconds(0.25)));
doubleAnimation.FillBehavior = System.Windows.Media.Animation.FillBehavior.Stop;
doubleAnimation.Completed += delegate (object o, EventArgs e)
{
SliderValue = 0.0;
};
BeginAnimation(SliderValueProperty, doubleAnimation);
}
public static readonly DependencyProperty ScrollDirectionProperty = DependencyProperty.Register("ScrollDirection", typeof(Orientation), typeof(PanningItems), new PropertyMetadata(Orientation.Horizontal));
public static readonly DependencyProperty FlickToleranceProperty = DependencyProperty.Register("FlickTolerance", typeof(double), typeof(PanningItems), new PropertyMetadata(0.25, new PropertyChangedCallback(flickToleranceChanged), new CoerceValueCallback(coerceFlickTolerance)));
public static readonly DependencyProperty PreviousItemProperty = DependencyProperty.Register("PreviousItem", typeof(object), typeof(PanningItems), new PropertyMetadata(null));
public static readonly DependencyProperty NextItemProperty = DependencyProperty.Register("NextItem", typeof(object), typeof(PanningItems), new PropertyMetadata(null));
public static readonly DependencyProperty LoopContentsProperty = DependencyProperty.Register("LoopContents", typeof(bool), typeof(PanningItems), new PropertyMetadata(true));
public static readonly DependencyProperty SliderValueProperty = DependencyProperty.Register("SliderValue", typeof(double), typeof(PanningItems), new PropertyMetadata(0.0, new PropertyChangedCallback(sliderValueChanged)));
public static readonly DependencyProperty SecondsProperty = DependencyProperty.Register("Seconds", typeof(int), typeof(PanningItems), new PropertyMetadata(5, new PropertyChangedCallback(SecondsChanged)));
private Point touchDown;
private bool isDragging;
private TranslateTransform previousTransform;
private TranslateTransform currentTransform;
private TranslateTransform nextTransform;
private ContentPresenter previous;
private ContentPresenter current;
private ContentPresenter next;
}
}
2)PanningItemsExample.xaml 水平代码如下;
<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.PanningItemsExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:draw="http://www.microsoft.net/drawing"
xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"
xmlns:controls="clr-namespace:Microsoft.Expression.Drawing.Controls;assembly=WPFDevelopers"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<controls:PanningItems>
<Image Source="../../Images/Craouse/0.jpg"></Image>
<Image Source="../../Images/Craouse/1.jpg"></Image>
<Image Source="../../Images/Craouse/2.jpg"></Image>
<Image Source="../../Images/Craouse/3.jpg"></Image>
<Image Source="../../Images/Craouse/4.jpg"></Image>
</controls:PanningItems>
</Grid>
</UserControl>
垂直 ScrollDirection="Vertical"
<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.PanningItemsExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:draw="http://www.microsoft.net/drawing"
xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"
xmlns:controls="clr-namespace:Microsoft.Expression.Drawing.Controls;assembly=WPFDevelopers"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<controls:PanningItems ScrollDirection="Vertical">
<Image Source="../../Images/Craouse/0.jpg"></Image>
<Image Source="../../Images/Craouse/1.jpg"></Image>
<Image Source="../../Images/Craouse/2.jpg"></Image>
<Image Source="../../Images/Craouse/3.jpg"></Image>
<Image Source="../../Images/Craouse/4.jpg"></Image>
</controls:PanningItems>
</Grid>
</UserControl>
边栏推荐
- Watch the open source summit first | quick view of the sub Forum & Activity agenda on July 29
- Regular expression matching URL
- How to use grep to find pattern matching across multiple lines
- "100 Interview Knowledge Collections" 1. Interview Skills丨Do you really understand HR's careful thinking?
- WeChat red envelope test case
- Leetcode bit operation
- [SwiftUI 开发] @State @Binding @ObservedObject @EnvironmentObject
- Based on the flask to write a small shopping mall project
- Great golang Road
- Is this it?TypeScript actually not difficult!(recommended collection)
猜你喜欢

ECCV 2022 | SSP: 自支持匹配的小样本任务新思想

LED透明屏和LED玻璃显示屏区别

How to use grep to display file names and line numbers before matching lines

如何使用“COPY –link”加速 Docker 构建和优化缓存

Watch the open source summit first | quick view of the sub Forum & Activity agenda on July 29

2022 latest WiFi master applet independent version 3.0.8

QT's user-defined interface (borderless and movable)

【Untitled】

Similarities and differences of QWidget, qdialog and qmainwindow

Self collection online computer wallpaper PHP source code v2.0 adaptive end
随机推荐
2.安装MySQL
AMH6.X升级到AMH7.0后,登录后台提示MySQL连接出错怎么解决?
Use anyio instead of asyncio
LED透明屏和LED玻璃显示屏区别
DNS protocol, ICMP protocol, NAT technology
「PHP基础知识」使用数组保存数据
ASN.1接口描述语言详解
一键搭建博客:如何使用WordPress插件搭建专属博客
On CompareTo method in string
【图像检测】基于灰度图像的积累加权边缘检测方法研究附matlab代码
Pyqt5 rapid development and practice 6.6 qformlayout & 6.7 nested layout & 6.8 qsplitter
LeetCode_416_分割等和子集
What is kubernetes custom resource definition (CRD)?
How to use grep to find pattern matching across multiple lines
Matplotlib Chinese question
力扣sql刷题(四)
golang 实现文件上传下载
DNS协议、ICMP协议、NAT技术
MyCat中间件高可用、读写分离、分片、主从切换、ER分片
Alibaba architects spent a year sorting out the "Lucene advanced document", and you are also a big factory employee!