WPF設置軟件界面背景為MediaElement並播放視頻


    在我們的常見的軟件界面設計中我們經常會設置軟件的背景為SolidColorBrush或者LinerColorBrush、RadialGradientBrush 等一系列的顏色畫刷為背景,有時我們也會使用ImageBrush添加圖片來作為界面的背景,另外常用的還有DrawingBrush以及今天需要進行總結的VisualBrush,這些我們都是比較容易實現的,那么我們如果想將軟件的界面設計成一個動畫或者干脆播放一段視頻作為背景,這個對於整個軟件的效果又是一個巨大的提升。

    首先我們來看看background屬性,MSDN上的解釋是:獲取或設置用於填充控件Control的邊框之間的區域的 Brush。它的類型是:Type: System.Windows.Media.Brush,所以我們能夠使用具有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">
    <Window.Resources>
        <Style TargetType="local:BackgroundPlayer">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="local:BackgroundPlayer">
                        <MediaElement x:Name="Media" Stretch="Fill"></MediaElement>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.Background>
            <VisualBrush>
                <VisualBrush.Visual>                    
                    <local:BackgroundPlayer Source="~/Images/bg.avi"></local:BackgroundPlayer>
                </VisualBrush.Visual>
            </VisualBrush>
        </Grid.Background>
    </Grid>
</Window>

  在這里我們用到了VisualBrush這個畫刷,然后再在VisualBrush的Visual中添加我們自定義的Style,這個是一個非常重要的畫刷,如果我們對WPF的繼承關系清楚的話,我們會發現幾乎所有的控件都是從Visual這個頂級的基類繼承過來的,所以幾乎所有的Control都能夠作為VisualBrush的Visual,所以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這里繼承過來的,我們看一下相關的代碼,然后做進一步的分析。首先我們必須為當前的類添加一個默認的靜態構造函數,這個是非常重要的,它會更改默認的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對象,從而為其添加事件,這是一種非常有效果的方式。

      最后貼出相應的截圖看看動畫的效果(星空風格圖)

    完整的視頻是一副移動的畫面,這里只是截出了很少的照片,正常播放時整個都面都動,上面的文章只是簡約去分析,僅供參考。
 

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM