- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我对自定义控件比较陌生(在代码中从头开始编写控件 - 而不仅仅是对现有控件进行样式设置)。我正在尝试复制 YouTube 视频控件,你知道那个......
首先,我想开发“时间轴”(透明的灰色条,显示视频的当前位置并允许用户拖动以更改位置)。随着预览面板和所有其他内容稍后出现...
我目前已经部分渲染了控件,并且悬停动画和缩放效果非常好......
但是,我正在努力编写正确的代码以允许我拖动“拇指”。当我尝试左键单击代表拇指的 Ellipse
时,根据 WPF 文档,包含 Canvas
的离开事件会触发,所以没有提示,我只是不知道如何实现我想要的,事实上我已经做的是否是正确的方法。
代码:
[ToolboxItem(true)]
[DisplayName("VideoTimeline")]
[Description("Controls which allows the user navigate video media. In addition is can display a " +
"waveform repesenting the audio channels for the loaded video media.")]
//[TemplatePart(Name = "PART_ThumbCanvas", Type = typeof(Canvas))]
[TemplatePart(Name = "PART_TimelineCanvas", Type = typeof(Canvas))]
[TemplatePart(Name = "PART_WaveformCanvas", Type = typeof(Canvas))]
[TemplatePart(Name = "PART_PreviewCanvas", Type = typeof(Canvas))]
[TemplatePart(Name = "PART_Thumb", Type = typeof(Ellipse))] // Is this the right thing to be doing?
public class VideoTimeline : Control
{
private Canvas thumbCanvas;
private Canvas timelineCanvas;
private Canvas waveformCanvas;
private Canvas previewCanvas;
private Rectangle timelineOuterBox = new Rectangle();
private Rectangle timelineProgressBox = new Rectangle();
private Rectangle timelineSelectionBox = new Rectangle();
private Ellipse timelineThumb = new Ellipse();
private Path previewWindow = new Path();
private Point mouseDownPosition;
private Point currentMousePosition;
private const int TIMELINE_ANIMATION_DURATION = 400;
private const string HIGHLIGHT_FILL = "#878787";
private double __timelineWidth;
#region Initialization.
static VideoTimeline()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(VideoTimeline),
new FrameworkPropertyMetadata(typeof(VideoTimeline)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
//thumbCanvas = GetTemplateChild("PART_ThumbCanvas") as Canvas;
//thumbCanvas.Background = new SolidColorBrush(Colors.Transparent);
//thumbCanvas.Children.Add(timelineThumb);
timelineThumb = EnforceInstance<Ellipse>("PART_Thumb");
timelineThumb.MouseLeftButtonDown -= TimelineThumb_MouseLeftButtonDown;
timelineThumb.MouseLeftButtonDown += TimelineThumb_MouseLeftButtonDown;
timelineCanvas = GetTemplateChild("PART_TimelineCanvas") as Canvas;
timelineCanvas.Background = new SolidColorBrush(Colors.Transparent);
timelineCanvas.Children.Add(timelineOuterBox);
timelineCanvas.Children.Add(timelineSelectionBox);
timelineCanvas.Children.Add(timelineProgressBox);
timelineCanvas.Children.Add(timelineThumb);
previewCanvas = GetTemplateChild("PART_PreviewCanvas") as Canvas;
previewCanvas.Background = new SolidColorBrush(Colors.Transparent);
previewCanvas.Children.Add(previewWindow);
}
private T EnforceInstance<T>(string partName) where T : FrameworkElement, new()
{
return GetTemplateChild(partName) as T ?? new T();
}
protected override void OnTemplateChanged(ControlTemplate oldTemplate, ControlTemplate newTemplate)
{
base.OnTemplateChanged(oldTemplate, newTemplate);
if (timelineCanvas != null)
timelineCanvas.Children.Clear();
SetDefaultMeasurements();
}
#endregion // Initialization.
#region Event Overrides.
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
//UpdateWaveformCacheScaling();
SetDefaultMeasurements();
UpdateAllRegions();
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
Canvas c = e.OriginalSource as Canvas;
if (c == null)
c = Utils.FindParent<Canvas>(e.OriginalSource as FrameworkElement);
if (c != null)
{
CaptureMouse();
mouseDownPosition = e.GetPosition(c);
if (c.Name == "PART_TimelineCanvas")
{
Trace.WriteLine("OnMouseLeftDown over TimeLine");
}
}
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
ReleaseMouseCapture();
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
currentMousePosition = e.GetPosition(thumbCanvas);
if (Mouse.Captured == null)
{
Canvas c = e.OriginalSource as Canvas;
if (c == null)
c = Utils.FindParent<Canvas>(e.OriginalSource as FrameworkElement);
}
}
#endregion // Event Overrides.
#region Drawing Methods and Events.
private void UpdateAllRegions()
{
UpdateTimelineCanvas();
}
private void UpdateTimelineCanvas()
{
if (timelineCanvas == null)
return;
SetDefaultMeasurements();
// Bounding timeline box.
timelineOuterBox.Fill = new SolidColorBrush(
(Color)ColorConverter.ConvertFromString("#878787")) { Opacity = 0.25 };
timelineOuterBox.StrokeThickness = 0.0;
timelineOuterBox.Width = __timelineWidth;
timelineOuterBox.Height = TimelineThickness;
timelineOuterBox.Margin = new Thickness(TimelineExpansionFactor * TimelineThickness,
(timelineCanvas.RenderSize.Height - TimelineThickness) / 2, 0, 0);
timelineOuterBox.SnapsToDevicePixels = true;
// Selection timeline box.
timelineSelectionBox.Fill = TimelineSelectionBrush;
timelineSelectionBox.Width = 0.0;
timelineSelectionBox.Height = TimelineThickness;
timelineSelectionBox.Margin = new Thickness(TimelineExpansionFactor * TimelineThickness,
(timelineCanvas.RenderSize.Height - TimelineThickness) / 2, 0, 0);
timelineSelectionBox.SnapsToDevicePixels = true;
// Progress timeline box.
timelineProgressBox.Fill = TimelineProgressBrush;
timelineProgressBox.StrokeThickness = 0.0;
timelineProgressBox.Width = 0.0;
timelineProgressBox.Height = TimelineThickness;
timelineProgressBox.Margin = new Thickness(TimelineExpansionFactor * TimelineThickness,
(timelineCanvas.RenderSize.Height - TimelineThickness) / 2, 0, 0);
timelineProgressBox.SnapsToDevicePixels = true;
// Animation and selection.
timelineCanvas.MouseEnter -= TimelineCanvas_MouseEnter;
timelineCanvas.MouseEnter += TimelineCanvas_MouseEnter;
timelineCanvas.MouseLeave -= TimelineCanvas_MouseLeave;
timelineCanvas.MouseLeave += TimelineCanvas_MouseLeave;
timelineCanvas.MouseMove -= TimelineCanvas_MouseMove;
timelineCanvas.MouseMove += TimelineCanvas_MouseMove;
timelineCanvas.MouseDown -= TimelineCanvas_MouseDown;
timelineCanvas.MouseDown += TimelineCanvas_MouseDown;
// The draggable thumb.
timelineThumb.Fill = TimelineThumbBrush;
//timelineThumb.Stroke = new SolidColorBrush(Colors.Black);
//timelineThumb.StrokeThickness = 0.5;
timelineThumb.VerticalAlignment = VerticalAlignment.Center;
timelineThumb.Height = timelineThumb.Width = 0.0;
timelineThumb.Margin = new Thickness(TimelineExpansionFactor * TimelineThickness,
timelineCanvas.RenderSize.Height / 2, 0, 0);
timelineThumb.SnapsToDevicePixels = true;
timelineThumb.MouseLeftButtonDown -= TimelineThumb_MouseLeftButtonDown;
timelineThumb.MouseLeftButtonDown += TimelineThumb_MouseLeftButtonDown;
timelineThumb.MouseLeftButtonUp -= TimelineThumb_MouseLeftButtonUp;
timelineThumb.MouseLeftButtonUp += TimelineThumb_MouseLeftButtonUp;
// Preview window.
}
private void TimelineCanvas_MouseDown(object sender, MouseButtonEventArgs e)
{
Trace.WriteLine("POON");
}
private void SetDefaultMeasurements()
{
if (timelineCanvas != null)
__timelineWidth = timelineCanvas.RenderSize.Width - 2 * 2 * TimelineThickness;
}
private void TimelineCanvas_MouseEnter(object sender, MouseEventArgs e)
{
timelineThumb.ResetAnimation(Ellipse.WidthProperty, Ellipse.HeightProperty);
timelineProgressBox.ResetAnimation(Rectangle.HeightProperty, Rectangle.MarginProperty);
timelineSelectionBox.ResetAnimation(Rectangle.HeightProperty, Rectangle.MarginProperty);
timelineOuterBox.ResetAnimation(Rectangle.HeightProperty, Rectangle.MarginProperty);
CircleEase easing = new CircleEase();
easing.EasingMode = EasingMode.EaseOut;
// Thumb animation.
Thickness margin = new Thickness(0,
(timelineCanvas.RenderSize.Height - 2 * TimelineExpansionFactor * TimelineThickness) / 2, 0, 0);
EllpiseDiameterAnimation(timelineThumb, TimelineThickness * TimelineExpansionFactor * 2, margin, easing);
// Timeline animation.
margin = new Thickness(TimelineExpansionFactor * TimelineThickness,
(timelineCanvas.RenderSize.Height - (TimelineThickness * TimelineExpansionFactor)) / 2, 0, 0);
TimelineHeightAnimation(timelineProgressBox, TimelineThickness * TimelineExpansionFactor, margin, easing);
TimelineHeightAnimation(timelineSelectionBox, TimelineThickness * TimelineExpansionFactor, margin, easing);
TimelineHeightAnimation(timelineOuterBox, TimelineThickness * TimelineExpansionFactor, margin, easing);
double selectionWidth = (currentMousePosition.X / RenderSize.Width) * timelineOuterBox.Width;
timelineSelectionBox.Width = selectionWidth;
Trace.WriteLine("MouseENTER Canvas");
}
private void TimelineCanvas_MouseLeave(object sender, MouseEventArgs e)
{
timelineThumb.ResetAnimation(Ellipse.WidthProperty, Ellipse.HeightProperty);
timelineProgressBox.ResetAnimation(Rectangle.HeightProperty, Rectangle.MarginProperty);
timelineSelectionBox.ResetAnimation(Rectangle.HeightProperty, Rectangle.MarginProperty);
timelineOuterBox.ResetAnimation(Rectangle.HeightProperty, Rectangle.MarginProperty);
CircleEase easing = new CircleEase();
easing.EasingMode = EasingMode.EaseOut;
// Thumb animation.
Thickness margin = new Thickness(TimelineExpansionFactor * TimelineThickness, timelineCanvas.RenderSize.Height / 2, 0, 0);
EllpiseDiameterAnimation(timelineThumb, 0.0, margin, easing);
// Timeline animation.
margin = new Thickness(TimelineExpansionFactor * TimelineThickness,
(timelineCanvas.RenderSize.Height - TimelineThickness) / 2, 0, 0);
TimelineHeightAnimation(timelineProgressBox, TimelineThickness, margin, easing);
TimelineHeightAnimation(timelineSelectionBox, TimelineThickness, margin, easing);
TimelineHeightAnimation(timelineOuterBox, TimelineThickness, margin, easing);
if (!isDraggingThumb)
timelineSelectionBox.Width = 0.0;
Trace.WriteLine("MouseLeave Canvas");
}
private void TimelineCanvas_MouseMove(object sender, MouseEventArgs e)
{
Point relativePosition = e.GetPosition(timelineOuterBox);
double selectionWidth = (relativePosition.X / timelineOuterBox.Width) * timelineOuterBox.Width;
timelineSelectionBox.Width = selectionWidth.Clamp(0.0, timelineOuterBox.Width);
if (isDraggingThumb)
{
timelineProgressBox.Width = timelineSelectionBox.Width;
Thickness thumbMargin = new Thickness(TimelineExpansionFactor * TimelineThickness,
(timelineCanvas.RenderSize.Height - (TimelineThickness * TimelineExpansionFactor)) / 2, 0, 0);
timelineThumb.Margin = thumbMargin;
}
}
private bool isDraggingThumb = false;
private void TimelineThumb_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
CaptureMouse();
isDraggingThumb = true;
Trace.WriteLine("Dragging Thumb");
}
private void TimelineThumb_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
ReleaseMouseCapture();
isDraggingThumb = false;
Trace.WriteLine("STOPPED Dragging Thumb");
}
#endregion // Drawing Methods and Events.
#region Animation Methods.
private void EllpiseDiameterAnimation(Ellipse ellipse, double diameter, Thickness margin, IEasingFunction easing)
{
AnimationTimeline widthAnimation = ShapeWidthAnimation(ellipse, diameter, easing);
AnimationTimeline heightAnimation = ShapeHeightAnimation(ellipse, diameter, easing);
AnimationTimeline marginAnimation = ShapeMarginAnimation(ellipse, margin, easing);
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(widthAnimation);
storyboard.Children.Add(heightAnimation);
storyboard.Children.Add(marginAnimation);
storyboard.Begin(this);
}
private void TimelineHeightAnimation(Rectangle rectangle, double height, Thickness margin, IEasingFunction easing)
{
AnimationTimeline heightAnimation = ShapeHeightAnimation(rectangle, height, easing);
AnimationTimeline marginAnimation = ShapeMarginAnimation(rectangle, margin, easing);
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(marginAnimation);
storyboard.Children.Add(heightAnimation);
storyboard.Begin(this);
}
private AnimationTimeline ShapeMarginAnimation(Shape shape, Thickness margin, IEasingFunction easing)
{
ThicknessAnimation marginAnimation = new ThicknessAnimation(
margin, TimeSpan.FromMilliseconds((TIMELINE_ANIMATION_DURATION)));
if (easing != null)
marginAnimation.EasingFunction = easing;
Storyboard.SetTarget(marginAnimation, shape);
Storyboard.SetTargetProperty(marginAnimation, new PropertyPath(Rectangle.MarginProperty));
return marginAnimation;
}
private AnimationTimeline ShapeWidthAnimation(Shape shape, double width, IEasingFunction easing)
{
DoubleAnimation widthAnimation = new DoubleAnimation(
width, TimeSpan.FromMilliseconds(TIMELINE_ANIMATION_DURATION));
if (easing != null)
widthAnimation.EasingFunction = easing;
Storyboard.SetTarget(widthAnimation, shape);
Storyboard.SetTargetProperty(widthAnimation, new PropertyPath(Shape.WidthProperty));
return widthAnimation;
}
private AnimationTimeline ShapeHeightAnimation(Shape shape, double height, IEasingFunction easing)
{
DoubleAnimation heightAnimation = new DoubleAnimation(
height, TimeSpan.FromMilliseconds(TIMELINE_ANIMATION_DURATION));
if (easing != null)
heightAnimation.EasingFunction = easing;
Storyboard.SetTarget(heightAnimation, shape);
Storyboard.SetTargetProperty(heightAnimation, new PropertyPath(Shape.HeightProperty));
return heightAnimation;
}
#endregion // Animation Methods.
// Lots of DependencyProperties here...
}
XAML 样式
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MediaControlBuilder">
<Style TargetType="{x:Type local:VideoTimeline}">
<Setter Property="TimelineProgressBrush" Value="DarkOrange"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:VideoTimeline}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.RowDefinitions>
<!--<RowDefinition Height="*"/>-->
<!--<RowDefinition Height="15"/>-->
<RowDefinition Height="*"/>
<RowDefinition Height="20"/>
<!--<RowDefinition Height="*"/>-->
</Grid.RowDefinitions>
<Canvas Name="PART_PreviewCanvas"
Grid.Row="0"
ClipToBounds="True"/>
<Canvas Name="PART_ThumbCanvas"
Grid.Row="1"
ClipToBounds="True"/>
<Canvas Name="PART_TimelineCanvas"
Grid.Row="1"
ClipToBounds="True"/>
<Canvas Name="PART_WaveformCanvas"
Grid.Row="1"
ClipToBounds="True"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
我的问题是:
感谢您的宝贵时间。
附言。具有工作代码的 GitHub 项目是 here这样您就可以重现我遇到的问题。如果有人想帮我开发这个控件,那就太棒了!
Pps。我知道我可以覆盖 slider 以获得“时间轴”的功能,但这只是更全面控制的第一部分,因此需要从头开始编写。
最佳答案
我不确定,但我认为这可以解决您的问题:
private void TimelineCanvas_MouseMove(object sender, MouseEventArgs e)
{
Point relativePosition = e.GetPosition(timelineOuterBox);
double selectionWidth = (relativePosition.X / timelineOuterBox.Width) * timelineOuterBox.Width;
timelineSelectionBox.Width = selectionWidth.Clamp(0.0, timelineOuterBox.Width);
if (isDraggingThumb)
{
timelineProgressBox.Width = timelineSelectionBox.Width;
//Thickness thumbMargin = new Thickness(TimelineThickness * TimelineExpansionFactor,
// (timelineCanvas.RenderSize.Height - (TimelineThickness * TimelineExpansionFactor)) / 2, 0, 0);
//timelineThumb.Margin = thumbMargin;
Canvas.SetLeft(timelineThumb, timelineProgressBox.Width);
}
}
private bool isDraggingThumb = false;
private void TimelineThumb_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
//CaptureMouse();
isDraggingThumb = true;
Trace.WriteLine("Dragging Thumb");
}
private void TimelineThumb_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
//ReleaseMouseCapture();
isDraggingThumb = false;
Trace.WriteLine("STOPPED Dragging Thumb");
}
您可以通过处理事件参数来停止冒泡,离开事件不会被触发。
要更改拇指的位置,您必须设置 Canvas 的 Left 附加属性。
此外,您还必须重置 isdraggingThumb :
/// <summary>
/// Invoked when an unhandled MouseLeftButtonUp routed event reaches an element in
/// its route that is derived from this class. Implement this method to add class
/// handling for this event.
/// </summary>
/// <param name="e">The MouseButtonEventArgs that contains the event data. The event
/// data reports that the left mouse button was released.</param>
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
isDraggingThumb = false;
关于c# - WPF 视频传输控制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43989388/
我一直在做一些关于测量数据传输延迟的实验 CPU->GPU 和 GPU->CPU。我发现对于特定消息大小,CPU->GPU 数据传输速率几乎是 GPU->CPU 传输速率的两倍。谁能解释我为什么会这样
我将 ElasticSearch 用作我的 Post 模型的 Rails pet 项目应用程序的全文引擎。在我的 posts_controller.rb 索引操作中: def index
概述 流经网络的数据总是具有相同的类型:字节,这些字节如何传输主要取决于我们所说的网络传输。用户并不关心传输的细节,只在乎字节是否被可靠地发送和接收 如果使用 Java 网络编程,你会发现,某些时候当
我正在编写一些代码,以便将共享点从该页面转移到另一个页面: Server.Transfer("/DefectManagement/DefectList/default.aspx") 但是我遇到了这个问
我有这个泄漏,任何猜测?这个类有一些奇怪的引用。我的代码的任何地方都没有 contentobserver In com.example:1.5.0:27. com.example.ui.record
我听说过点对点内存传输并阅读了一些关于它的内容,但无法真正理解与标准 PCI-E 总线传输相比它的速度有多快。 我有一个使用多个 GPU 的 CUDA 应用程序,我可能对 P2P 传输感兴趣。我的问题
ftping 文件时,Transmit 中是否有忽略或过滤器列表?我希望它忽略上传 .svn 文件等。 最佳答案 是的。转到首选项并选择 Rules标签。在那里您可以定义要跳过哪些文件的规则。实际上,
我有以下片段来生成声音,在 while 循环中,我想动态更改它,以便它在声音生成期间创建不同频率的声音。 for(uint16_t i = 0; i < sample_N; i++) { da
我正在尝试使用 Delphi 2010 和 Indy 对 Web 服务进行概念验证。我此时的代码是: procedure TForm1.Log(const sEvent, sMsg: String);
我有一个 ActiveMQ JMS 代理,在端口 61616 上使用默认的 openwire TCP 传输公开。 我有许多远程客户端可以绑定(bind)到此代理来监听他们的消息。 如果我想打开 kee
reconnection strategies文档仅使用 JMS 示例,但是 FTP transport documentation确实说明了重新连接策略的使用,但没有任何细节或示例。 进一步,如果你
我有 2 个 TreeView,第一个填充有项目。 try { CheckBoxTreeItem treeRoot = new CheckBoxTreeItem("Root"); tr
在我为学校开发的一个网站上,用户输入他们的学校电子邮件和密码,如果他们已注册,则登录。如果没有,则会显示登录的第二部分,要求输入笔名称并确认密码。正因为如此,以及我复杂的业余 Django 编程,我有
我正在开发一个 Web 服务,我们在其中使用 LINQ-to-SQL 进行数据库抽象。当客户使用我们的网络服务时,对象被序列化为 XML,一切都很好。 现在我们希望开发我们自己的使用本地数据类型的客户
我应该创建一个名为“Backwards”的方法,该方法将列表从尾部横向到头部,但是当我运行代码时,它出现说(第 88 行)它找不到光标 = cusor.prev;象征。我需要在循环中再次设置上一个链接
给定像 Uint8Array 这样的类型化数组,似乎有两种方法可以通过 worker 传输它们。 选项 1 直接发送缓冲区并在接收端进行转换: 发件人:postMessage({fooBuffer:
在 PHP + jQuery 环境中,我和我的 friend 无法得出最佳解决方案。我们正在使用 Ajax 从数据库中获取数据。 解决方案 1 - Ajax 应该只传输数据,而不是 HTML 好处:我
大家好,非常感谢您的宝贵时间。 有一个 std::stringstream 需要传输到远程机器。网络库允许我用以下方法构建数据包: CreatePacket( const void * DATA, s
我正在使用 libcurl 通过 FTP 传输二进制文件 (.exe),并将其保存到本地文件。问题是文件传输后,它已被更改,不再是有效的 Win32 应用程序,因此无法运行。这是我的做法: CURL
各位程序员, 当我将它上传到我的 FTP 时,我的网站出现此错误:资源被解释为样式表,但使用 MIME 类型文本/纯文本传输 BlahBlahi
我是一名优秀的程序员,十分优秀!