Плавное включение / выключение панели стека поверх элемента MediaElement (оба находятся в одной ячейке сетки)

#c# #wpf #xaml

#c# #wpf #xaml

Вопрос:

Я новичок в WPF, и я столкнулся с проблемой в этом. Я создаю простое видеоприложение, и в приложении есть 3 столбца. 2-й столбец — это разделитель сетки, а 3-й столбец — это элемент MediaElement и StackPanel (содержащий элементы управления видео) поверх него.

Чего я хочу добиться, так это того, чтобы панель стека исчезала, когда указатель мыши входит в элемент MediaElement, и исчезала из панели стека, когда указатель мыши выходит из элемента MediaElement. Однако проблема возникает, когда указатель мыши попадает на панель стека, что вызывает эффект исчезновения (произойдет событие MouseExit элемента MediaElement).

 <Window x:Class="WPF_learningapp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    xmlns:MyNamespace="clr-namespace:WPF_learningapp"
    Title="MiDrama" Height="350" Width="700" ResizeMode="CanResize">
<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Custom assets/CustomScrollbar.xaml"></ResourceDictionary>
        </ResourceDictionary.MergedDictionaries>
        <MyNamespace:PausePlayBooleanConverter x:Key="PausePlayBooleanConverter" />
    </ResourceDictionary>
</Window.Resources>
<MyNamespace:GridControl>
    <Grid.ColumnDefinitions>
        <ColumnDefinition MinWidth="0" MaxWidth="300"/>
        <ColumnDefinition Width="1"/>
        <ColumnDefinition Width= "*">
        </ColumnDefinition>
    </Grid.ColumnDefinitions>
    <StackPanel/>
    <GridSplitter Grid.Column="1" Width="1" HorizontalAlignment="Stretch" />
    <MediaElement Grid.Column="2" Name="myMediaPlayer" LoadedBehavior="Manual" Stretch="Fill">
        <MediaElement.Triggers>
          <EventTrigger RoutedEvent="MouseEnter" >
             <BeginStoryboard>
                 <Storyboard>
                     <DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="VideoControlPanel"
                             From="0.0" To="1.0" Duration="0:0:1"/>
                 </Storyboard>
             </BeginStoryboard>
          </EventTrigger>
          <EventTrigger RoutedEvent="MouseLeave">
             <BeginStoryboard>
                 <Storyboard>
                     <DoubleAnimation Storyboard.TargetProperty="Opacity"           Storyboard.TargetName="VideoControlPanel"
                            From="1.0" To="0" Duration="0:0:1"/>
                 </Storyboard>
             </BeginStoryboard>
          </EventTrigger>
       </MediaElement.Triggers>
    </MediaElement>
    <StackPanel Name="VideoControlPanel" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Height="59" Margin="55,0,41,4" Background="Transparent">
        <Slider Name="VideoSlider" Thumb.DragStarted="slider_DragStarted"  Thumb.DragCompleted="slider_DragCompleted" Margin="0,0,0,5"
                IsMoveToPointEnabled="True" ValueChanged="slider_ValueChanged"/>
        <WrapPanel HorizontalAlignment="Center">
            <Button Content="{Binding Path=isPlaying, Converter={StaticResource PausePlayBooleanConverter}}" Height="34" Width="50" Margin="5 0" Name="playpause_Btn" Click="playpause_Btn_Click"/>
            <Button Height="34" Width="50" Content="Stop" Margin="5 0" Name="stop_Btn" Click="stop_Btn_Click"/>
        </WrapPanel>
    </StackPanel>
</MyNamespace:GridControl>
  

Я попытался инкапсулировать все в canvas в сетке, но панель управления не изменит размер должным образом. Похоже, что даже реализация триггера события в столбце сетки не работает. Есть ли способ добиться этого? Пожалуйста, дайте совет.

Ответ №1:

Я бы сказал, что вам следует поместить EventTrigger для MouseLeave на StackPanel или, возможно, на содержимое StackPanel — не на MediaElement.

Редактировать

Хорошо, я думал, что stackpanel покрывает весь medialelement (я не видел реквизит высоты).

Решением могло бы быть размещение mediaelement и stackpanel внутри какого-либо элемента управления контентом, как в примере ниже:

 <Window x:Class="SO40188046.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        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:local="clr-namespace:SO40188046"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
  <Border Background="Blue">
    <Border.Triggers>
      <EventTrigger RoutedEvent="MouseEnter">
        <BeginStoryboard>
          <Storyboard>
            <DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="VideoControlPanel" From="0.0" To="1.0" Duration="0:0:1"/>
          </Storyboard>
        </BeginStoryboard>
      </EventTrigger>
      <EventTrigger RoutedEvent="MouseLeave">
        <BeginStoryboard>
          <Storyboard>
            <DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="VideoControlPanel" From="1.0" To="0" Duration="0:0:1"/>
          </Storyboard>
        </BeginStoryboard>
      </EventTrigger>
    </Border.Triggers>
    <Grid>
      <MediaElement Source="SOME MEDIA URI" />
      <Border Name="VideoControlPanel" Background="Red" Height="100" VerticalAlignment="Bottom" Opacity="0" />
    </Grid>
  </Border>
</Window>
  

ПРАВКА 2:

Здесь я изменил ваш собственный ответ, поэтому для определения размера и положения элементов управления не требуется никакого кода. Я заменил Canvas ContentControl и заменил некоторые другие элементы управления. Но общий макет тот же:

 <Window x:Class="WPF_learningapp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:MyNamespace="clr-namespace:WPF_learningapp"
        Title="MiDrama" Height="350" Width="700" ResizeMode="CanResize">
  <Window.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Custom assets/CustomScrollbar.xaml"></ResourceDictionary>
      </ResourceDictionary.MergedDictionaries>
      <MyNamespace:PausePlayBooleanConverter x:Key="PausePlayBooleanConverter" />
    </ResourceDictionary>
  </Window.Resources>
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition MinWidth="0" MaxWidth="300"/>
      <ColumnDefinition Width="Auto"/>
      <ColumnDefinition Width= "*">
      </ColumnDefinition>
    </Grid.ColumnDefinitions>
    <StackPanel/>
    <GridSplitter Grid.Column="1" Width="4" HorizontalAlignment="Center" VerticalAlignment="Stretch" />
    <ContentControl Grid.Column="2" Background="AliceBlue">
      <ContentControl.Triggers>
        <EventTrigger RoutedEvent="MouseEnter" >
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimation 
                Storyboard.TargetProperty="Opacity" 
                Storyboard.TargetName="VideoControlPanel"
                From="0.0" 
                To="1.0" 
                Duration="0:0:1"/>
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="MouseLeave">
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimation 
                Storyboard.TargetProperty="Opacity" 
                Storyboard.TargetName="VideoControlPanel"
                From="1.0" 
                To="0" 
                Duration="0:0:1"/>
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </ContentControl.Triggers>
      <Grid>
        <MediaElement 
          Name="myMediaPlayer" 
          Stretch="Fill"  />
        <Grid Name="VideoControlPanel" VerticalAlignment="Bottom" Height="60" Background="Transparent" Opacity="0">
          <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
          </Grid.RowDefinitions>
          <Slider 
            Name="VideoSlider" 
            Grid.Column="0"
            Grid.ColumnSpan="2"
            Thumb.DragStarted="slider_DragStarted"  
            Thumb.DragCompleted="slider_DragCompleted" 
            Margin="10,5"
            IsMoveToPointEnabled="True" 
            ValueChanged="slider_ValueChanged"/>
          <Button 
            Grid.Column="0"
            Grid.Row="1"
            HorizontalAlignment="Right"
            Content="Play" 
            Height="26" 
            Width="50" 
            Name="playpause_Btn" 
            Click="playpause_Btn_Click"/>
          <Button 
            Grid.Column="1"
            Grid.Row="1"
            HorizontalAlignment="Left"
            Height="26" 
            Width="50"
            Content="Stop"
            Name="stop_Btn" 
            Click="stop_Btn_Click"/>
        </Grid>
      </Grid>
    </ContentControl>
  </Grid>
</Window>
  

Комментарии:

1. Я не могу этого сделать, StackPanel — это всего лишь небольшая часть внутри сетки, и я хочу, чтобы она появлялась, как только я вхожу в сетку. Единственный элемент управления, который покрывает всю сетку, — это MediaElement.

2. ?? Кто вы и почему отклоняете?

3. Я обновил свой код xaml. Я не думаю, что рисование границы сработает, мне нужна анимация, 1. Введите мышью 3-й столбец, отобразите StackPanel. 2. Мышь выходит из 3-го столбца, удалите StackPanel.

4. @Ytan: Но граница — это всего лишь пример элемента управления содержимым. Вы можете, например, скопировать весь мой код из <Border … /Border> и поместите это в свой третий столбец и измените Border на ContentControl или что-либо еще, что вы хотите, и это будет работать так, как вы описываете… Вы должны самостоятельно подумать о пути нашего ответа, иначе это не стоит того, чтобы беспокоиться 🙂

5. Я вижу, наконец, я просто инкапсулировал все в третий столбец внутри canvas и вручную изменил размер всего внутри. Я думал, что будет более простая альтернатива. Я также обновил свой пользовательский интерфейс xaml.

Ответ №2:

Это решение проблемы, описанной выше. Поместите все внутри canvas в ячейку сетки (которая, я думаю, является единственным контейнером, с которым легко работать с перекрывающимися элементами управления).

 <Window x:Class="WPF_learningapp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:MyNamespace="clr-namespace:WPF_learningapp"
        Title="MiDrama" Height="350" Width="700" ResizeMode="CanResize">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Custom assets/CustomScrollbar.xaml"></ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
            <MyNamespace:PausePlayBooleanConverter x:Key="PausePlayBooleanConverter" />
        </ResourceDictionary>
    </Window.Resources>
    <MyNamespace:GridControl>
        <Grid.ColumnDefinitions>
            <ColumnDefinition MinWidth="0" MaxWidth="300"/>
            <ColumnDefinition Width="1"/>
            <ColumnDefinition Width= "*">
            </ColumnDefinition>
        </Grid.ColumnDefinitions>
        <StackPanel/>
        <GridSplitter Grid.Column="1" Width="1" HorizontalAlignment="Stretch" />
        <Canvas Grid.Column="2" Name="VideoCanvas" SizeChanged="VideoCanvas_sizeChanged" Background="AliceBlue">
            <Canvas.Triggers>
                <EventTrigger RoutedEvent="MouseEnter" >
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="VideoControlPanel"
                             From="0.0" To="1.0" Duration="0:0:1"/>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
                <EventTrigger RoutedEvent="MouseLeave">
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="VideoControlPanel"
                            From="1.0" To="0" Duration="0:0:1"/>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Canvas.Triggers>
            <MediaElement Grid.Column="2" Name="myMediaPlayer" LoadedBehavior="Manual" Stretch="Fill" Height="{Binding Path=ActualHeight, ElementName=VideoCanvas}"  Width="{Binding Path=ActualWidth, ElementName=VideoCanvas}"/>
            <StackPanel Name="VideoControlPanel" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Height="59" Background="Transparent" Canvas.Left="10" Canvas.Top="250" Width="371">
                <Slider Name="VideoSlider" Thumb.DragStarted="slider_DragStarted"  Thumb.DragCompleted="slider_DragCompleted" Margin="0,0,0,5"
                    IsMoveToPointEnabled="True" ValueChanged="slider_ValueChanged"/>
                <WrapPanel HorizontalAlignment="Center">
                    <Button Content="{Binding Path=isPlaying, Converter={StaticResource PausePlayBooleanConverter}}" Height="34" Width="50" Margin="5 0" Name="playpause_Btn" Click="playpause_Btn_Click"/>
                    <Button Height="34" Width="50" Content="Stop" Margin="5 0" Name="stop_Btn" Click="stop_Btn_Click"/>
                </WrapPanel>
            </StackPanel>
        </Canvas>
    </MyNamespace:GridControl>
</Window>
  

Комментарии:

1. Смотрите мою ПРАВКУ 2 в моем ответе.