WPFでメディア要素を使用してソフトウェアの背景に動画を表示する

一般的なソフトウェアインターフェース設計では、SolidColorBrushやLinearGradientBrush、RadialGradientBrushなどの色ブラシがよく使われます。また、ImageBrushも画像をバックグラウンドとして使用します。さらに、DrawingBrushと今日は説明したいVisualBrushもよく使用されます。これらは比較的簡単に実装できます。

しかし、ソフトウェアの背景にアニメーションや動画を表示したい場合、全体的なソフトウェアの印象を大幅に向上させることができます。

backgroundプロパティ

MSDNによると、backgroundプロパティは「コントロールControlの境界線間の領域を塗りつぶすためのBrush」を取得または設定します。そのタイプはSystem.Windows.Media.Brushです。つまり、backgroundプロパティにはBrushプロパティを持つコントロールまたはプロパティを使用することができます。

フロントエンドスタイルの設計

    
      <Window x:Class="TestBackGroundWorker.MainWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:ui="clr-namespace:X.UI;assembly=X.UI"   
              xmlns:local="clr-namespace:TestBackGroundWorker"
              Title="MainWindow" Height="681" Width="1000">
          
              <Style TargetType="local:BackgroundPlayer">
                  <Setter Property="Template">
                      
                          <ControlTemplate TargetType="local:BackgroundPlayer">
                              <MediaElement x:Name="Media" Stretch="Fill"></MediaElement>
                          </ControlTemplate>
                      
                  </Setter>
              </Style>
          
          <Grid>
              
                  <VisualBrush>
                                          
                          
                      
                  </VisualBrush>
              
          </Grid>
      </Window>
    
  

ここではVisualBrushというブラシを使用しています。そして、VisualBrushのVisualプロパティに自定义のStyleを追加しています。これは非常に重要なブラシです。WPFの継承関係を理解していると、ほぼすべてのコントロールがVisualクラスから派生していることがわかります。そのため、VisualBrushのVisualプロパティにはほぼすべてのControlが使用できます。したがって、GridのBackgroundプロパティは非常に豊富です。ここでは、BackgroundPlayerというカスタムコントロールを定義し、そのコントロールテンプレートを変更しました。

カスタムコントロールのバックエンドの定義

    
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.Windows;
      using System.Windows.Controls;

      namespace TestBackGroundWorker
      {
          public class BackgroundPlayer : System.Windows.Controls.Control
          {
              static BackgroundPlayer()
              {
                  DefaultStyleKeyProperty.OverrideMetadata(typeof(BackgroundPlayer), new FrameworkPropertyMetadata(typeof(BackgroundPlayer)));
              }

              public string Source
              {
                  get { return (string)GetValue(SourceProperty); }
                  set { SetValue(SourceProperty, value); }
              }
            
              public static readonly DependencyProperty SourceProperty =
                  DependencyProperty.Register("Source", typeof(string), typeof(BackgroundPlayer), new FrameworkPropertyMetadata("", (a, b) =>
                  {
                      BackgroundPlayer bp = a as BackgroundPlayer;
                      if (bp.Player != null)
                      {
                          bp.Player.Source = new Uri(b.NewValue.ToString().Replace("~", AppDomain.CurrentDomain.BaseDirectory), UriKind.RelativeOrAbsolute);
                      }               
                  }));

              private MediaElement _player;

              public MediaElement Player
              {
                  get { return _player; }
                  set { _player = value; }
              }

              public override void OnApplyTemplate()
              {
                  Player = GetTemplateChild("Media") as MediaElement;
                  if (null == Player)
                      throw new ArgumentNullException("Media");

                  Player.LoadedBehavior = MediaState.Manual;
                  Player.MediaEnded += Player_MediaEnded;
                  Player.MediaOpened += Player_MediaOpened;
                  Player.MediaFailed += Player_MediaFailed;
                  Player.Loaded += Player_Loaded;
                  if (!string.IsNullOrEmpty(Source))
                  {
                      Player.Source = new Uri(Source.Replace("~", AppDomain.CurrentDomain.BaseDirectory), UriKind.RelativeOrAbsolute);
                      Player.Play();
                  }
                  base.OnApplyTemplate();
              }

              void Player_Loaded(object sender, RoutedEventArgs e)
              {
              }

              void Player_MediaFailed(object sender, ExceptionRoutedEventArgs e)
              {
              }

              void Player_MediaOpened(object sender, RoutedEventArgs e)
              {
                  //Player.Play();
              }

              void Player_MediaEnded(object sender, RoutedEventArgs e)
              {
                  Player.Position = TimeSpan.FromMilliseconds(1);
                  Player.Play();
              }

          }
      }
    
  

ここでのカスタムコントロールはSystem.Windows.Controls.Controlから派生しています。関連コードを見て、さらに解析しましょう。まず、現在のクラスにデフォルトの静的コンストラクタを追加する必要があります。これは非常に重要で、現在のコントロールのスタイルを変更するために必要です。

    
      static BackgroundPlayer()
      {
          DefaultStyleKeyProperty.OverrideMetadata(typeof(BackgroundPlayer), new FrameworkPropertyMetadata(typeof(BackgroundPlayer)));
      }
    
  

次に、カスタムコントロールにいくつかの既定の依存性プロパティを定義します。最初のプロパティはSourceプロパティです。私たちがControlのプロパティにMediaElementを使用しているので、このMediaElementに必要なプロパティを設定する必要があります。ここでSourceプロパティに対して、プロパティ値が変わったときに呼び出すコールバック関数を定義しています。このコールバック関数はXAMLでSourceプロパティに初めて値を設定するときのみトリガーされますが、このコールバック関数は多くの場合有用です。

また、MediaElementにいくつかの一般的なプロパティを設定する必要があります。例えば、現在のビデオが再生終了したら次の操作は何ですか。

ここでは、OnApplyTemplateメソッドをオーバーライドして関連操作を行っています。WPFを理解していると、これらの一般的な仮想メソッドをオーバーライドして操作を行うことを知る必要があります。もちろん、これには日々の経験が必要です。

OnApplyTemplateメソッドが何を行うか見てみましょう。OnApplyTemplateをオーバーライドすることで、GetTemplateChildメソッドを使ってテンプレート内の子コントロールを取得することができます。ただし、OnApplyTemplateの実行順序について注意が必要です。クラスのコンストラクタが実行された後、OnApplyTemplateメソッドは遅延して実行されます。また、このカスタムコントロールがアプリケーションのプロジェクトに配置されている場合、Visibilityが非表示の場合、OnApplyTemplateメソッドは実行されません。この点を覚えておくことが重要です。私たちのプログラムでも、OnApplyTemplateメソッドをオーバーライドしてMediaElementオブジェクトを取得し、イベントを追加することにより、効果的な方法です。

タグ: WPF MediaElement visualbrush background Animation

8月12日 05:03 投稿