Avalonia中LibVLCSharp的VideoView在ScrollViewer内滚动异常问题
Avalonia中ScrollViewer内LibVLCSharp VideoView滚动时位置异常的问题
在Avalonia的UserControl中,ScrollViewer内部使用LibVLCSharp的VideoView时出现以下问题:滚动ScrollViewer时,VideoView(及其内部控件)会停留在固定位置不跟随滚动,其他元素滚动正常;但拖动窗口后,VideoView又会回到正确的布局位置。
已尝试过调用Render()等重绘方法,以及滚动时将窗口上下移动1像素的临时方案,但这些方法都不适合滚动场景,寻求有效解决办法。
对应的XAML代码如下:
<UserControl xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="using:LauncherSIPAvalonia.ViewModels" xmlns:views="using:LauncherSIPAvalonia.Views" xmlns:lvs="using:LibVLCSharp.Avalonia" mc:Ignorable="d" x:Class="LauncherSIPAvalonia.Views.LearnMore.LearnMoreView"> <ScrollViewer> <StackPanel Margin="40" Orientation="Vertical"> <Grid HorizontalAlignment="Left" ColumnDefinitions="1.2* *"> <Grid RowDefinitions="3* *" Grid.Column="0"> <Border CornerRadius="6" Width="640" Height="360"> <lvs:VideoView x:Name="Video" Width="640" Height="360" IsVisible="False"> <Grid RowDefinitions="8* *" x:Name="VideoViewInnerControls" IsVisible="False"> <Border Grid.Row="1" Background="rgba(0, 0, 0, 0.7)"/> <Grid Grid.Row="1" RowDefinitions="* 2*"> <Rectangle Fill="#7F1D1D" x:Name="ProgressBarBackground" Grid.Row="0" PointerPressed="ProgressBar_PointerPressed"/> <Rectangle x:Name="ProgressBar" Fill="#B91C1C" HorizontalAlignment="Left" MaxWidth="640" Grid.Row="0" PointerPressed="ProgressBar_PointerPressed"/> <Grid Grid.Row="1" ColumnDefinitions="* * * 15*"> <Button Grid.Column="0" Width="32" Height="32" Classes="Toolbar" Click="PlayControl_Click"> <Image x:Name="PlayControl" Width="32" Height="32"/> </Button> <Button Grid.Column="1" Width="32" Height="32" Classes="Toolbar" Click="VolumeControl_Click"> <Image Source="/Assets/volume.png" x:Name="VolumeControl" Width="16" Height="16"/> </Button> </Grid> </Grid> </Grid> </lvs:VideoView> </Border> <Image x:Name="ScreenshotImage" IsVisible="True" Stretch="UniformToFill" Width="640" Height="360"/> <Grid Grid.Row="1" Height="84" Width="640" Margin="0 15" HorizontalAlignment="Stretch"> <Border Background="rgba(0, 0, 0, 0.3)" CornerRadius="0 0 6 6"/> <ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Disabled" HorizontalAlignment="Stretch"> <UniformGrid x:Name="ListOfMedia" Rows="1" HorizontalAlignment="Stretch"> </UniformGrid> </ScrollViewer> </Grid> </Grid> <Grid Margin="20 0" Grid.Column="1" RowDefinitions="2.84* *"> <StackPanel Grid.Row="0" Orientation="Vertical" Spacing="10"> <TextBlock x:Name="TitleBlock" FontSize="24" LineHeight="32" FontWeight="SemiBold" TextWrapping="Wrap"/> <TextBlock x:Name="DescriptionBlock" FontSize="16" LineHeight="28" FontWeight="Regular" TextWrapping="Wrap"/> </StackPanel> <Grid Grid.Row="1" RowDefinitions="* 2*"> <Grid Grid.Row="0"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="10"> <TextBlock x:Name="PriceBlock" HorizontalAlignment="Right" FontSize="28" FontWeight="SemiBold"/> <TextBlock x:Name="OriginalPriceBlock" HorizontalAlignment="Right" FontSize="28" FontWeight="SemiBold" TextDecorations="Strikethrough" Foreground="#9CA3AF" IsVisible="False"/> </StackPanel> </Grid> <Button Grid.Row="1" HorizontalAlignment="Stretch" Height="50" Click="Interact_Click" Name="ActionButton"> <TextBlock FontSize="18" FontWeight="SemiBold" HorizontalAlignment="Center" VerticalAlignment="Center" Name="ActionLabel"> Купить </TextBlock> </Button> </Grid> </Grid> </Grid> <StackPanel Spacing="6"> <TextBlock x:Name="TagsBlock" FontSize="14"> <Run Text="Теги:" FontWeight="Bold"/> </TextBlock> <StackPanel Orientation="Horizontal" Spacing="6"> <StackPanel Orientation="Vertical" Name="SystemRequirementsItems" Spacing="6"> <TextBlock FontWeight="Bold" Padding=" 0 0 0 4" FontSize="14"> Системные требования: </TextBlock> </StackPanel> <StackPanel Orientation="Vertical" Name="MinimalSystemRequirements" Width="300" Spacing="6"> <TextBlock FontWeight="SemiBold" Padding=" 0 0 0 4" FontSize="14"> Минимальные </TextBlock> </StackPanel> <StackPanel Orientation="Vertical" Name="RecommendedSystemRequirements" Width="300" Spacing="6"> <TextBlock FontWeight="SemiBold" Padding=" 0 0 0 4" FontSize="14"> Рекомендуемые </TextBlock> </StackPanel> </StackPanel> </StackPanel> </StackPanel> </ScrollViewer> </UserControl>
解决方案
1. 切换VideoView的渲染模式
LibVLCSharp的VideoView默认使用硬件渲染,这类渲染元素在ScrollViewer中可能无法正确响应滚动偏移。可以尝试强制启用软件渲染:
// 在初始化MediaPlayer后添加 Video.MediaPlayer.SetRendererOptions(new RendererOptions { HardwareAcceleration = HardwareAcceleration.Disabled });
如果使用的LibVLCSharp.Avalonia版本支持,也可以直接在XAML中设置:
<lvs:VideoView RenderOptions="Software" ... />
2. 将VideoView移出ScrollViewer,通过绑定同步位置
把VideoView放在ScrollViewer的同级容器,通过绑定ScrollViewer的VerticalOffset来手动同步位置,模拟跟随滚动的效果:
步骤1:修改XAML结构
<Grid> <!-- 原ScrollViewer,添加名称便于绑定 --> <ScrollViewer x:Name="MainScrollViewer"> <StackPanel Margin="40" Orientation="Vertical"> <Grid HorizontalAlignment="Left" ColumnDefinitions="1.2* *"> <Grid RowDefinitions="3* *" Grid.Column="0"> <!-- 保留占位Border,维持原有布局结构 --> <Border CornerRadius="6" Width="640" Height="360"/> <!-- 原有的Image、下方媒体列表等元素 --> <Image x:Name="ScreenshotImage" IsVisible="True" Stretch="UniformToFill" Width="640" Height="360"/> <Grid Grid.Row="1" Height="84" Width="640" Margin="0 15" HorizontalAlignment="Stretch"> <Border Background="rgba(0, 0, 0, 0.3)" CornerRadius="0 0 6 6"/> <ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Disabled" HorizontalAlignment="Stretch"> <UniformGrid x:Name="ListOfMedia" Rows="1" HorizontalAlignment="Stretch"/> </ScrollViewer> </Grid> </Grid> <!-- 右侧的标题、价格等内容 --> <Grid Margin="20 0" Grid.Column="1" RowDefinitions="2.84* *"> <!-- 原右侧内容不变 --> </Grid> </Grid> <!-- 下方的标签、系统要求等内容 --> </StackPanel> </ScrollViewer> <!-- VideoView放在Grid顶层,绝对定位 --> <lvs:VideoView x:Name="Video" Width="640" Height="360" IsVisible="False" Margin="{Binding ElementName=MainScrollViewer, Path=VerticalOffset, Converter={StaticResource ScrollOffsetConverter}}"> <!-- 原有的内部控件不变 --> </lvs:VideoView> </Grid>
步骤2:实现滚动偏移转换器
public class ScrollOffsetConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is double verticalOffset) { // 计算VideoView的初始Top位置(对应原StackPanel的Margin 40),减去滚动偏移量 return new Thickness(40, 40 - verticalOffset, 0, 0); } return new Thickness(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
步骤3:注册转换器
在UserControl的资源中添加转换器:
<UserControl.Resources> <local:ScrollOffsetConverter x:Key="ScrollOffsetConverter"/> </UserControl.Resources>
3. 监听滚动事件,强制更新VideoView位置
在ScrollViewer的ScrollChanged事件中,手动调整VideoView的渲染变换,抵消滚动偏移:
步骤1:绑定滚动事件
<ScrollViewer x:Name="MainScrollViewer" ScrollChanged="MainScrollViewer_ScrollChanged">
步骤2:实现事件处理逻辑
private void MainScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) { if (Video == null) return; // 使用TranslateTransform抵消滚动的垂直偏移 var transform = Video.RenderTransform as TranslateTransform ?? new TranslateTransform(); transform.Y -= e.VerticalChange; Video.RenderTransform = transform; // 强制触发控件重绘 Video.InvalidateVisual(); }
内容的提问来源于stack exchange,提问作者Александр Карпов
相关产品推荐
相关产品推荐

