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>

 

原文地址:https://www.cnblogs.com/rchao/p/15221630.html