gpt4 book ai didi

c# - WPF 视频传输控制

转载 作者:太空狗 更新时间:2023-10-29 20:23:03 25 4
gpt4 key购买 nike

我对自定义控件比较陌生(在代码中从头开始编写控件 - 而不仅仅是对现有控件进行样式设置)。我正在尝试复制 YouTube 视频控件,你知道那个......

enter image description here

首先,我想开发“时间轴”(透明的灰色条,显示视频的当前位置并允许用户拖动以更改位置)。随着预览面板和所有其他内容稍后出现...

我目前已经部分渲染了控件,并且悬停动画和缩放效果非常好......

enter image description here

但是,我正在努力编写正确的代码以允许我拖动“拇指”。当我尝试左键单击代表拇指的 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>

我的问题是:

  1. 我绘制可拖动拇指的方法是否正确?
  2. 我怎样才能真正更改代码以使我的“拇指”拖动起作用?

感谢您的宝贵时间。

附言。具有工作代码的 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com