c# wpf自定義控件


需要繼承System.Windows.Controls.UserControl類

使用System.Windows.DependencyProperty綁定屬性

注意在自定義控件中 不要設置DataContext 默認就行 否則的話我們使用定義好的自定義控件時,使用動態綁定無效

我們如果使用其他類 可以在我們自定義的UserControl內部的控件上綁定DataContext

MyControl后台類

namespace MyApp.Component
{
    public partial class MyControl : UserControl
    {
        // 這里控件屬性的定義也可以放到一個實體類中  實體類需要繼承DependencyObject
        // 在這里實例化這個實體類,並在綁定(SetBinding)的時候 把Source 設置為這個實體類的對象
        // 建議直接放到自定義控件類內部,因為這些字段需要提供給使用者傳入
        // DependencyProperty暫時不知道怎么回事,無法在頁面綁定 只能在在后台使用SetBinding綁定
        // 頁面上綁定數據 可以新建一個實體類 實現INotifyPropertyChanged
        private static readonly VideoData VideoData = new VideoData();
        public string MediaUrl
        {
            set => SetValue(MediaUrlProperty, value);
            get => (string)GetValue(MediaUrlProperty);
        }
        
        public string Poster
        {
            set => SetValue(PosterProperty, value);
            get => (string)GetValue(PosterProperty);
        }

        public bool IsAudio
        {
            set => SetValue(IsAudioProperty, value);
            get => (bool)GetValue(IsAudioProperty);
        }
        
        public static readonly DependencyProperty MediaUrlProperty = DependencyProperty.Register("MediaUrl", typeof(string), typeof(VideoControl),
            new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.None, (sender, args) => 
            {
                if (args.NewValue != null)
                {
                    //MediaUrl值改變
                    ((MyControl)sender).VlcControl.SourceProvider.MediaPlayer.Play(new Uri(args.NewValue.ToString()), new string[] { });
                }
            })
        );
        
        public static readonly DependencyProperty PosterProperty = DependencyProperty.Register(nameof(Poster), typeof(string), typeof(VideoControl),
            new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.None, (sender, args) => 
            {
                if (args.NewValue != null)
                {
                    VideoData.Poster = args.NewValue as string;
                }
            })
        );

        public static readonly DependencyProperty IsAudioProperty = DependencyProperty.Register(nameof(IsAudio), typeof(bool), typeof(VideoControl),
            new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.None, (sender, args) => 
            {
                //bool 只能取值true和false 所以這里默認值不能設置為空 
                //這里默認值為false 所以這里初始化時控件傳遞過來的是false 這里就不執行了
                //所以需要對我們需要控制的屬性設置好默認值,防止屬性被其他頁面更改為true,另一個頁面初始化時傳遞的是false
                //這里就不會被執行導致實際和預期的屬性值不一樣,導致程序出現bug
                //注意這里VideoData定義為靜態的 
                //注意這里需要注意 VideoData.IsAudio 初始化時一定要是false
                VideoData.IsAudio = (bool)args.NewValue;
            })
        );
        
        public MyControl()
        {
            //!DesignerProperties.GetIsInDesignMode(this)
            //為了處理引入該控件預覽問題
            if (DesignerProperties.GetIsInDesignMode(this))
            {
                //設計模式什么也不處理  主要處理預覽出錯問題
                //這么處理的話不影響引入該控件頁面其他位置的預覽
                //就是當前控件被引入時預覽時不顯示 只顯示一個框框
                return;
            }
            
            //運行模式才進行處理
            InitializeComponent();
            //在后台綁定  (我在前台頁面綁定不生效,不知道什么原因,可能時我的使用姿勢不對)
            //這里把視頻的地址綁定到Tag上 在回調地方把控件的視頻地址修改了
            //VlcControl.SetBinding(Vlc.DotNet.Wpf.VlcControl.TagProperty, new Binding("MediaUrl") { Source = this });
            //nameof(MediaUrl) 等同於 "MediaUrl"
            VlcControl.SetBinding(Vlc.DotNet.Wpf.VlcControl.TagProperty, new Binding(nameof(MediaUrl)) { Source = this });
            //注意不要設置 DataContext = VideoData 否則DependencyProperty 值改變事件無法生效
            //VideoData 是靜態的每次實例化時需要設置默認值 和 IsAudioProperty 的默認值對應 
            //否則可能出現問題
            VideoData.IsAudio = false;
            RootLayout.DataContext = VideoData
        }
        
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            //加載初始化
        }
        
        private void UserControl_Unloaded(object sender, RoutedEventArgs e)
        {
            //結束清理資源
        }
        
    }
}

 

VideoData類

namespace MyApp.custom
{
    internal class VideoData : INotifyPropertyChanged
    {
        private bool _isPlaying;
        private string _formatShow;
        private bool _isFullscreen;
        private bool _isStart;
        private bool _isLoaded;
        private string _poster; // 視頻封面圖
        private bool _isAudio;
        private string _videoPath; //當前正在播放的音視頻地址
        private bool _isSeekable;
​
        public bool IsPlaying
        {
            set
            {
                _isPlaying = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsPlaying"));
            }
​
            get => _isPlaying;
        }
​
        public string FormatShow
        {
            set
            {
                _formatShow = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("FormatShow"));
            }
​
            get => _formatShow;
        }
​
        public bool IsFullscreen
        {
            set
            {
                _isFullscreen = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsFullscreen"));
            }
            get => _isFullscreen;
        }
​
        public bool IsStart
        {
            set
            {
                _isStart = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsStart"));
            }
            get => _isStart;
        }
​
        public bool IsLoaded
        {
            set
            {
                _isLoaded = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsLoaded"));
            }
​
            get => _isLoaded;
        }
        
       public string Poster
        {
            set
            {
                _poster = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("poster"));
            }
            get => _poster;
        }
        
        public bool IsAudio
        {
            set
            {
                _isAudio = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsAudio"));
            }
​
            get => _isAudio;
        }
​
        public string VideoPath
        {
            set
            {
                _videoPath = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("VideoPath"));
            }
​
            get => _videoPath;
        }
​
        public bool IsSeekable 
        {
            set
            {
                _isSeekable = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsSeekable"));
            }
​
            get => _isSeekable;
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
}

 

 

MyControl.xaml 前台頁面

<UserControl x:Class="MyApp.custom.MyControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:MyApp"
             xmlns:res="clr-namespace:MyApp.Properties"
             xmlns:vlc="clr-namespace:Vlc.DotNet.Wpf;assembly=Vlc.DotNet.Wpf" 
             mc:Ignorable="d" 
             Loaded="UserControl_Loaded"
             Unloaded="UserControl_Unloaded"
             d:DesignHeight="675" d:DesignWidth="1200">
    
    <Grid x:Name="RootLayout">
        <vlc:VlcControl Name="VlcControl"></vlc:VlcControl>
        <!--視頻封面-->
        <Grid>
            <Image Stretch="Fill" Name="PosterImage">
                <Image.Style>
                    <Style TargetType="Image">
                        <Setter Property="Source" Value="{Binding Poster}" />
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Poster}" Value="{x:Null}">
                                <Setter Property="Source" Value="{x:Null}" />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Image.Style>
            </Image>
        </Grid>
    </Grid>
    
</UserControl>

 

使用MyControl

<Page x:Class="MyApp.ui.VideoPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:MyApp"
      xmlns:res="clr-namespace:MyApp.Properties"
      xmlns:my="clr-namespace:MyApp.custom"
      mc:Ignorable="d" 
      Loaded="Page_Loaded"
      d:DesignHeight="1080" d:DesignWidth="1920"
      Title="視頻測試">
    <Grid>
        <!--可以使用Binding動態綁定
        如果自定義控件MyControl 設置了DataContext = xxxx則無法使用動態綁定
        -->
        <my:MyControl MediaUrl="視頻地址"></my:MyControl>
    </Grid>
</Page>

 

 


免責聲明!

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



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