// WpfMediaPlayer/MainWindow.xaml.cs
using Microsoft.Win32;
using SharedInterfaces;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using WpfMediaPlayer.ViewModels;

namespace WpfMediaPlayer
{
    public partial class MainWindow : Window
    {
        private readonly DispatcherTimer timer;  // 用于更新进度条和时间显示
        private bool isDraggingSlider = false;   // 判断用户是否正在拖动进度条
        private readonly PluginManager pluginManager; // 插件管理器

        public MainWindow()
        {
            InitializeComponent();

            // 初始化插件管理器
            pluginManager = new PluginManager();

            // 设置 Popup 的 DataContext 为插件管理器
            pluginListPopup.DataContext = pluginManager;

            // 初始化计时器
            timer = new DispatcherTimer
            {
                Interval = TimeSpan.FromMilliseconds(33) // 大约每秒30帧
            };
            timer.Tick += Timer_Tick;

            // 初始化音量
            volumeSlider.Value = 0.5;
            mediaElement.Volume = volumeSlider.Value;

            // 自动加载 Plugins 文件夹中的所有插件
            LoadAllPlugins();

            // 添加全局点击事件
            this.PreviewMouseDown += MainWindow_PreviewMouseDown;
        }

        #region 控件事件处理

        // 播放按钮事件
        private void PlayButton_Click(object sender, RoutedEventArgs e)
        {
            if (mediaElement.Source != null)
            {
                mediaElement.Play();
                timer.Start();
            }
            else
            {
                OpenFileDialog openFileDialog = new OpenFileDialog
                {
                    Filter = "媒体文件 (*.mpg;*.mp4;*.mp3;*.avi;*.mkv;*.flv)|

*.mp4;*.mp3;*.avi;*.mkv;*.flv|所有文件 (*.*)|*.*"
                };

                if (openFileDialog.ShowDialog() == true)
                {
                    LoadAndPlayMedia(openFileDialog.FileName);
                }
            }
        }

        // 暂停按钮事件
        private void PauseButton_Click(object sender, RoutedEventArgs e)
        {
            mediaElement.Pause();
            timer.Stop();  // 暂停计时器
        }

        // 停止按钮事件
        private void StopButton_Click(object sender, RoutedEventArgs e)
        {
            mediaElement.Stop();
            timer.Stop();  // 停止计时器
            progressSlider.Value = 0;
            if (mediaElement.NaturalDuration.HasTimeSpan)
            {
                timeDisplay.Text = $"00:00:00 / {mediaElement.NaturalDuration.TimeSpan:hh\\:mm\

\:ss}";
            }
            else
            {
                timeDisplay.Text = "00:00:00 / 00:00:00";
            }

            // 清空插件显示内容
            foreach (var plugin in pluginManager.IPlugins)
            {
                try
                {
                    // 如果插件需要处理null帧（如重置状态），调用其ProcessFrame
                    plugin.ProcessFrame(null);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"插件 {plugin.PluginName} 处理异常：{ex.Message}");
                }
            }
        }

        // 快退10秒按钮事件
        private void RewindButton_Click(object sender, RoutedEventArgs e)
        {
            if (mediaElement.Position.TotalSeconds > 10)
            {
                mediaElement.Position -= TimeSpan.FromSeconds(10);
            }
            else
            {
                mediaElement.Position = TimeSpan.Zero;
            }
        }

        // 快进10秒按钮事件
        private void ForwardButton_Click(object sender, RoutedEventArgs e)
        {
            if (mediaElement.NaturalDuration.HasTimeSpan)
            {
                if (mediaElement.Position.TotalSeconds + 10 < 

mediaElement.NaturalDuration.TimeSpan.TotalSeconds)
                {
                    mediaElement.Position += TimeSpan.FromSeconds(10);
                }
                else
                {
                    mediaElement.Position = mediaElement.NaturalDuration.TimeSpan;
                }
            }
        }

        // 音量滑块事件
        private void VolumeSlider_ValueChanged(object sender, 

RoutedPropertyChangedEventArgs<double> e)
        {
            if (mediaElement != null)
            {
                mediaElement.Volume = volumeSlider.Value;
            }
        }

        // 进度条滑块开始拖动事件
        private void ProgressSlider_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs 

e)
        {
            isDraggingSlider = true;
            timer.Stop();
        }

        // 进度条滑块拖动结束事件
        private void ProgressSlider_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs 

e)
        {
            isDraggingSlider = false;
            UpdateMediaPosition();
            timer.Start();
        }

        // 插件加载按钮点击事件，加载 IPluginBase 或 IPluginWithUI 类型的 DLL 并设置其处理逻辑
        private void PlugButton_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog
            {
                Filter = "DLL文件 (*.dll)|*.dll"
            };

            if (openFileDialog.ShowDialog() == true)
            {
                try
                {
                    // 加载插件
                    Assembly assembly = Assembly.LoadFile(openFileDialog.FileName);

                    // 获取实现了IPluginWithUI接口的类型
                    foreach (Type type in assembly.GetTypes())
                    {
                        if (typeof(IPluginWithUI).IsAssignableFrom(type) && !type.IsInterface && 

!type.IsAbstract)
                        {
                            IPluginWithUI pluginWithUI = (IPluginWithUI)Activator.CreateInstance

(type);
                            pluginWithUI.Initialize();
                            pluginManager.AddIPluginWithUI(pluginWithUI);
                            MessageBox.Show($"插件 {pluginWithUI.PluginName} 加载成功，并设置为处

理帧。");
                        }
                        else if (typeof(IPluginBase).IsAssignableFrom(type) && !type.IsInterface 

&& !type.IsAbstract)
                        {
                            // 获取仅实现了IPluginBase接口的插件
                            IPluginBase pluginBase = (IPluginBase)Activator.CreateInstance(type);
                            pluginBase.Initialize();
                            pluginManager.AddIPlugin(pluginBase);
                            MessageBox.Show($"插件 {pluginBase.PluginName} 加载成功，并设置为处理

帧。");
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"加载插件失败: {ex.Message}");
                }
            }
        }

        // 进度条滑块值变化事件
        private void ProgressSlider_ValueChanged(object sender, 

RoutedPropertyChangedEventArgs<double> e)
        {
            if (mediaElement != null && mediaElement.NaturalDuration.HasTimeSpan && !

isDraggingSlider)
            {
                mediaElement.Position = TimeSpan.FromSeconds(progressSlider.Value);
                UpdateTimeDisplay();
            }
        }

        #endregion

        #region 媒体事件处理

        // 当媒体文件加载完成后
        private void MediaElement_MediaOpened(object sender, RoutedEventArgs e)
        {
            if (mediaElement.NaturalDuration.HasTimeSpan)
            {
                progressSlider.IsEnabled = true;
                progressSlider.Minimum = 0;
                progressSlider.Maximum = mediaElement.NaturalDuration.TimeSpan.TotalSeconds;
                progressSlider.Value = mediaElement.Position.TotalSeconds;

                // 设置时间显示
                timeDisplay.Text = $"{mediaElement.Position:hh\\:mm\\:ss} / 

{mediaElement.NaturalDuration.TimeSpan:hh\\:mm\\:ss}";
                Console.WriteLine("媒体文件已打开。");
            }
        }

        // 当媒体播放结束
        private void MediaElement_MediaEnded(object sender, RoutedEventArgs e)
        {
            mediaElement.Stop();
            timer.Stop();
            progressSlider.Value = 0;
            if (mediaElement.NaturalDuration.HasTimeSpan)
            {
                timeDisplay.Text = "00:00:00 / " + mediaElement.NaturalDuration.TimeSpan.ToString

(@"hh\:mm\:ss");
            }
            else
            {
                timeDisplay.Text = "00:00:00 / 00:00:00";
            }

            // 清空插件显示内容
            foreach (var plugin in pluginManager.IPlugins)
            {
                try
                {
                    // 如果插件需要处理null帧（如重置状态），调用其ProcessFrame
                    plugin.ProcessFrame(null);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"插件 {plugin.PluginName} 处理异常：{ex.Message}");
                }
            }
        }

        #endregion

        #region 计时器和进度更新

        // 计时器更新视频帧及进度条
        private void Timer_Tick(object sender, EventArgs e)
        {
            if (mediaElement.NaturalDuration.HasTimeSpan && !isDraggingSlider)
            {
                progressSlider.Maximum = mediaElement.NaturalDuration.TimeSpan.TotalSeconds;
                progressSlider.Value = mediaElement.Position.TotalSeconds;

                // 更新时间显示
                UpdateTimeDisplay();

                // 捕获并处理当前帧
                CaptureAndProcessFrame();
            }
        }

        // 更新时间显示
        private void UpdateTimeDisplay()
        {
            if (mediaElement.NaturalDuration.HasTimeSpan)
            {
                timeDisplay.Text = $"{mediaElement.Position:hh\\:mm\\:ss} / 

{mediaElement.NaturalDuration.TimeSpan:hh\\:mm\\:ss}";
            }
            else
            {
                timeDisplay.Text = $"{mediaElement.Position:hh\\:mm\\:ss} / 00:00:00";
            }
        }

        // 捕获当前视频帧并处理
        private void CaptureAndProcessFrame()
        {
            BitmapSource frame = CaptureCurrentFrame();
            if (frame != null)
            {
                Console.WriteLine("捕获到一帧视频。");

                // 在 UI 线程上处理帧
                Dispatcher.BeginInvoke(new Action(() =>
                {
                    BitmapSource processedFrame = frame;

                    // 依次应用所有启用的 IPluginBase 插件
                    foreach (var plugin in pluginManager.IPlugins.Where(p => p.IsEnabled))
                    {
                        try
                        {
                            processedFrame = plugin.ProcessFrame(processedFrame);
                            Console.WriteLine($"插件 {plugin.PluginName} 处理完成。");
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"插件 {plugin.PluginName} 处理异常：{ex.Message}");
                        }
                    }

                    // 更新图像显示
                    imageDisplay.Source = processedFrame;
                    Console.WriteLine("更新 imageDisplay.Source 成功。");
                }), DispatcherPriority.Background);
            }
            else
            {
                Console.WriteLine("帧捕获返回null。");
            }
        }

        // 捕获当前视频帧的方法
        private BitmapSource CaptureCurrentFrame()
        {
            double width = mediaElement.ActualWidth;
            double height = mediaElement.ActualHeight;

            if (width == 0 || height == 0)
                return null;

            try
            {
                RenderTargetBitmap rtb = new RenderTargetBitmap(
                    (int)width, (int)height,
                    96, 96,
                    PixelFormats.Pbgra32); // 确保正确的像素格式

                DrawingVisual dv = new DrawingVisual();
                using (DrawingContext dc = dv.RenderOpen())
                {
                    dc.DrawRectangle(new VisualBrush(mediaElement), null, new Rect(new Point(), 

new Size(width, height)));
                }
                rtb.Render(dv);
                return rtb;
            }
            catch
            {
                return null;
            }
        }

        #endregion

        #region 插件管理

        // 自动加载 Plugins 文件夹中的所有插件
        private void LoadAllPlugins()
        {
            string pluginsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");

            if (Directory.Exists(pluginsPath))
            {
                pluginManager.LoadPlugins(pluginsPath);
            }
            else
            {
                // 如果 Plugins 文件夹不存在，创建一个
                Directory.CreateDirectory(pluginsPath);
                Console.WriteLine("Plugins 文件夹已创建。");
            }
        }

        #endregion

        #region 拖放处理

        // 统一处理拖放事件
        private void Window_DragOver(object sender, DragEventArgs e)
        {
            HandleDragOver(e, allowDll: false);
        }

        private void Window_Drop(object sender, DragEventArgs e)
        {
            HandleDrop(e, allowDll: false);
        }

        private void PluginListPopup_DragOver(object sender, DragEventArgs e)
        {
            HandleDragOver(e, allowDll: true);
        }

        private void PluginListPopup_Drop(object sender, DragEventArgs e)
        {
            HandleDrop(e, allowDll: true);
        }

        // 统一处理拖放事件的逻辑
        private void HandleDragOver(DragEventArgs e, bool allowDll = false)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                var files = (string[])e.Data.GetData(DataFormats.FileDrop);
                bool hasValidFile = false;

                foreach (var file in files)
                {
                    string extension = Path.GetExtension(file).ToLower();
                    if (allowDll && extension == ".dll")
                    {
                        hasValidFile = true;
                        break;
                    }
                    else if (!allowDll && IsMediaFile(extension))
                    {
                        hasValidFile = true;
                        break;
                    }
                }

                e.Effects = hasValidFile ? DragDropEffects.Copy : DragDropEffects.None;
            }
            else
            {
                e.Effects = DragDropEffects.None;
            }

            e.Handled = true;
        }

        private void HandleDrop(DragEventArgs e, bool allowDll = false)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
                foreach (string filePath in files)
                {
                    string extension = Path.GetExtension(filePath).ToLower();

                    if (allowDll && extension == ".dll")
                    {
                        // 加载插件 DLL
                        try
                        {
                            Assembly assembly = Assembly.LoadFile(filePath);
                            foreach (Type type in assembly.GetTypes())
                            {
                                if (typeof(IPluginWithUI).IsAssignableFrom(type) && !

type.IsInterface && !type.IsAbstract)
                                {
                                    IPluginWithUI pluginWithUI = 

(IPluginWithUI)Activator.CreateInstance(type);
                                    pluginWithUI.Initialize();
                                    pluginManager.AddIPluginWithUI(pluginWithUI);
                                    Console.WriteLine($"插件 {pluginWithUI.PluginName} 加载成

功。");
                                }
                                else if (typeof(IPluginBase).IsAssignableFrom(type) && !

type.IsInterface && !type.IsAbstract)
                                {
                                    // 获取仅实现了IPluginBase接口的插件
                                    IPluginBase pluginBase = 

(IPluginBase)Activator.CreateInstance(type);
                                    pluginBase.Initialize();
                                    pluginManager.AddIPlugin(pluginBase);
                                    Console.WriteLine($"插件 {pluginBase.PluginName} 加载成功，无

UI控件。");
                                }
                            }

                            MessageBox.Show($"插件加载成功: {filePath}");
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show($"加载插件失败: {ex.Message}");
                            Console.WriteLine($"加载插件失败: {ex.Message}");
                        }
                    }
                    else if (!allowDll && IsMediaFile(extension))
                    {
                        // 加载并播放媒体文件
                        LoadAndPlayMedia(filePath);
                    }
                }
            }
        }

        // 判断是否为支持的媒体文件
        private bool IsMediaFile(string extension)
        {
            string[] supportedExtensions = { ".mp4", ".mp3", ".avi", ".mkv", ".flv" };
            return supportedExtensions.Contains(extension);
        }

        #endregion

        #region 外部点击关闭 Popup

        private void MainWindow_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (pluginListPopup.IsOpen)
            {
                // 获取点击的元素
                DependencyObject clickedElement = e.OriginalSource as DependencyObject;

                // 检查点击是否在 Popup 内部
                if (!IsDescendant(pluginListPopup.Child, clickedElement))
                {
                    pluginListPopup.IsOpen = false;

                    // 如果使用 ToggleButton，取消选中状态
                    pluginListButton.IsChecked = false;
                }
            }
        }

        // 递归检查是否为子孙元素
        private bool IsDescendant(DependencyObject parent, DependencyObject child)
        {
            if (child == null) return false;
            if (parent == child) return true;

            DependencyObject current = child;
            while (current != null)
            {
                if (current == parent)
                    return true;
                current = VisualTreeHelper.GetParent(current);
            }
            return false;
        }

        #endregion

        #region 媒体播放

        // 加载并播放媒体文件
        private void LoadAndPlayMedia(string filePath)
        {
            try
            {
                mediaElement.Source = new Uri(filePath);
                mediaElement.Play();
                timer.Start(); // 启动计时器以更新进度条
                Console.WriteLine($"播放媒体文件: {filePath}");
            }
            catch (Exception ex)
            {
                MessageBox.Show($"无法播放文件: {ex.Message}", "播放错误", MessageBoxButton.OK, 

MessageBoxImage.Error);
                Console.WriteLine($"无法播放文件: {ex.Message}");
            }
        }

        // 更新视频播放位置
        private void UpdateMediaPosition()
        {
            if (mediaElement != null && mediaElement.NaturalDuration.HasTimeSpan)
            {
                mediaElement.Position = TimeSpan.FromSeconds(progressSlider.Value);
            }
        }

        #endregion

        #region Expander Toggle

        private void ExpanderToggle_Click(object sender, RoutedEventArgs e)
        {
            Button button = sender as Button;
            if (button != null)
            {
                Expander expander = button.Parent as Expander;
                if (expander != null)
                {
                    expander.IsExpanded = !expander.IsExpanded;
                }
            }
        }

        #endregion
    }
}
<!-- WpfMediaPlayer/MainWindow.xaml -->
<Window x:Class="WpfMediaPlayer.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfMediaPlayer"
        Title="WPF媒体播放器" Height="600" Width="800"
        AllowDrop="True"
        Drop="Window_Drop"
        DragOver="Window_DragOver">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <!-- 主内容区，包含视频和处理后的视频 -->
        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <!-- 左侧视频显示区域 -->
            <MediaElement Grid.Column="0" x:Name="mediaElement"
                          LoadedBehavior="Manual"
                          UnloadedBehavior="Stop"
                          Stretch="Uniform"
                          MediaOpened="MediaElement_MediaOpened"
                          MediaEnded="MediaElement_MediaEnded" />

            <!-- 右侧处理后的视频显示区域，使用 Border 设置背景 -->
            <Border Grid.Column="1" Background="LightGray">
                <Image x:Name="imageDisplay" Stretch="Uniform" />
            </Border>
        </Grid>

        <!-- 控制面板 -->
        <Border Grid.Row="1" Background="Black" Padding="10">
            <StackPanel Orientation="Vertical">
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" 

VerticalAlignment="Center">
                    <!-- 播放控制按钮 -->
                    <Button x:Name="playButton" Content="播放" Width="60" 

Click="PlayButton_Click"/>
                    <Button x:Name="pauseButton" Content="暂停" Width="60" Margin="5,0" 

Click="PauseButton_Click"/>
                    <Button x:Name="stopButton" Content="停止" Width="60" Margin="5,0" 

Click="StopButton_Click"/>
                    <Button x:Name="rewindButton" Content="&lt;&lt; 10秒" Width="90" Margin="5,0" 

Click="RewindButton_Click"/>
                    <Button x:Name="forwardButton" Content="10秒 &gt;&gt;" Width="90" Margin="5,0" 

Click="ForwardButton_Click"/>

                    <!-- 使用 ToggleButton 作为插件列表按钮 -->
                    <ToggleButton x:Name="pluginListButton" Content="插件列表" Width="80" 

Margin="5,0"/>

                    <!-- 视频进度条 -->
                    <Slider x:Name="progressSlider"
                            Minimum="0"
                            Value="0"
                            IsEnabled="False"
                            ValueChanged="ProgressSlider_ValueChanged"
                            PreviewMouseLeftButtonDown="ProgressSlider_PreviewMouseLeftButtonDown"
                            PreviewMouseLeftButtonUp="ProgressSlider_PreviewMouseLeftButtonUp" 
                            Width="300"
                            Margin="10,0"/>

                    <!-- 音量控制 -->
                    <TextBlock Text="音量" Foreground="White" VerticalAlignment="Center" 

Margin="10,0,5,0"/>
                    <Slider x:Name="volumeSlider" Minimum="0" Maximum="1" Value="0.5" Width="100" 

ValueChanged="VolumeSlider_ValueChanged"/>

                    <!-- 时间显示 -->
                    <TextBlock x:Name="timeDisplay" Foreground="White" Margin="10,0" 

VerticalAlignment="Center"/>

                    <!-- 插件加载按钮 -->
                    <Button x:Name="plugButton" Content="加载插件" Width="80" Margin="5,0" 

Click="PlugButton_Click"/>
                </StackPanel>
            </StackPanel>
        </Border>

        <!-- 插件列表弹出框 -->
        <Popup x:Name="pluginListPopup" 
               Placement="Bottom" 
               PlacementTarget="{Binding ElementName=pluginListButton}" 
               StaysOpen="False"
               AllowsTransparency="True"
               PopupAnimation="Slide"
               Width="300"
               IsOpen="{Binding IsChecked, ElementName=pluginListButton, Mode=TwoWay}"
               Focusable="False">
            <Border Background="White" BorderBrush="Gray" BorderThickness="1" CornerRadius="5" 

Padding="10">
                <StackPanel Width="280" Margin="0">
                    <TextBlock Text="已加载插件：" FontWeight="Bold" Margin="5"/>

                    <!-- 修改 ItemsSource 绑定到 PluginViewModels -->
                    <ItemsControl ItemsSource="{Binding PluginViewModels}">
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <Expander Header="{Binding PluginName}" IsExpanded="False" 

Margin="5">
                                    <StackPanel>
                                        <CheckBox Content="启用" IsChecked="{Binding IsEnabled, 

Mode=TwoWay}" Margin="0,0,0,5"/>
                                        <!-- 插件参数 UserControl -->
                                        <ContentPresenter Content="{Binding Control}" />
                                    </StackPanel>
                                </Expander>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>

                    <!-- 插件加载提示 -->
                    <TextBlock Text="拖入 DLL 文件以加载插件" 
                               Foreground="Gray" 
                               FontStyle="Italic" 
                               HorizontalAlignment="Center" 
                               Margin="5,10,5,0"/>
                </StackPanel>
            </Border>
        </Popup>
    </Grid>
</Window>
// WpfMediaPlayer/PluginManager.cs
using SharedInterfaces;
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using WpfMediaPlayer.ViewModels;

namespace WpfMediaPlayer
{
    public class PluginManager
    {
        public ObservableCollection<IPluginBase> IPlugins { get; private set; } = new 

ObservableCollection<IPluginBase>();
        public ObservableCollection<IPluginWithUI> IPluginsWithUI { get; private set; } = new 

ObservableCollection<IPluginWithUI>();
        public ObservableCollection<PluginViewModel> PluginViewModels { get; private set; } = new 

ObservableCollection<PluginViewModel>();

        // Reference to the UI Image control where frames will be displayed
        private readonly Image _imageDisplay;

        // Constructor accepts the Image control reference
        public PluginManager(Image imageDisplay)
        {
            _imageDisplay = imageDisplay;
        }

        /// <summary>
        /// Loads all plugin DLLs from the specified path.
        /// </summary>
        /// <param name="pluginsPath">Path to the plugins folder.</param>
        public void LoadPlugins(string pluginsPath)
        {
            if (!Directory.Exists(pluginsPath))
            {
                Console.WriteLine($"插件文件夹不存在: {pluginsPath}");
                return;
            }

            var dllFiles = Directory.GetFiles(pluginsPath, "*.dll");
            foreach (var dll in dllFiles)
            {
                try
                {
                    Assembly assembly = Assembly.LoadFrom(dll);
                    var types = assembly.GetTypes();

                    foreach (var type in types)
                    {
                        if (typeof(IPluginWithUI).IsAssignableFrom(type) && !type.IsInterface && 

!type.IsAbstract)
                        {
                            // Plugin implements IPluginWithUI
                            IPluginWithUI pluginWithUI = (IPluginWithUI)Activator.CreateInstance

(type);
                            pluginWithUI.Initialize();

                            // Subscribe to the FrameProcessed event
                            pluginWithUI.FrameProcessed += OnFrameProcessed;

                            IPlugins.Add(pluginWithUI);
                            IPluginsWithUI.Add(pluginWithUI);
                            PluginViewModels.Add(new PluginViewModel(pluginWithUI));
                            Console.WriteLine($"已加载 IPluginWithUI: {pluginWithUI.PluginName}");
                        }
                        else if (typeof(IPluginBase).IsAssignableFrom(type) && !type.IsInterface 

&& !type.IsAbstract)
                        {
                            // Plugin implements only IPluginBase
                            IPluginBase pluginBase = (IPluginBase)Activator.CreateInstance(type);
                            pluginBase.Initialize();
                            IPlugins.Add(pluginBase);
                            PluginViewModels.Add(new PluginViewModel(pluginBase));
                            Console.WriteLine($"已加载 IPluginBase: {pluginBase.PluginName}");
                        }
                    }
                }
                catch (ReflectionTypeLoadException rex)
                {
                    Console.WriteLine($"无法加载插件类型从 {dll}: {rex.Message}");
                    foreach (var loaderEx in rex.LoaderExceptions)
                    {
                        Console.WriteLine($"Loader Exception: {loaderEx.Message}");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"加载插件失败从 {dll}: {ex.Message}");
                }
            }
        }

        /// <summary>
        /// Event handler for frames processed by plugins.
        /// Updates the image display with the processed frame.
        /// </summary>
        /// <param name="frame">Processed BitmapSource frame.</param>
        private void OnFrameProcessed(BitmapSource frame)
        {
            // Update the Image control's Source on the UI thread
            _imageDisplay.Dispatcher.Invoke(() =>
            {
                _imageDisplay.Source = frame;
                Console.WriteLine("更新 imageDisplay.Source 成功。");
            });
        }

        /// <summary>
        /// Unloads all plugins.
        /// </summary>
        public void UnloadPlugins()
        {
            // Unsubscribe from FrameProcessed events and unload plugins
            foreach (var pluginWithUI in IPluginsWithUI)
            {
                pluginWithUI.FrameProcessed -= OnFrameProcessed;
                pluginWithUI.GetControl()?.Dispatcher.Invoke(() => pluginWithUI.GetControl

().ClearValue(UserControl.ContentProperty));
                pluginWithUI.Unload();
            }
            IPluginsWithUI.Clear();

            // Unload IPluginBase plugins
            foreach (var pluginBase in IPlugins)
            {
                pluginBase.Unload();
            }
            IPlugins.Clear();
            PluginViewModels.Clear();

            Console.WriteLine("已卸载所有插件。");
        }

        /// <summary>
        /// Adds an IPluginBase plugin to the manager.
        /// </summary>
        /// <param name="plugin">Plugin instance.</param>
        public void AddIPlugin(IPluginBase plugin)
        {
            if (plugin != null)
            {
                plugin.Initialize();
                IPlugins.Add(plugin);
                PluginViewModels.Add(new PluginViewModel(plugin));
                Console.WriteLine($"已加载 IPluginBase: {plugin.PluginName}");
            }
        }

        /// <summary>
        /// Adds an IPluginWithUI plugin to the manager.
        /// </summary>
        /// <param name="plugin">Plugin instance.</param>
        public void AddIPluginWithUI(IPluginWithUI plugin)
        {
            if (plugin != null)
            {
                plugin.Initialize();

                // Subscribe to the FrameProcessed event
                plugin.FrameProcessed += OnFrameProcessed;

                IPlugins.Add(plugin);
                IPluginsWithUI.Add(plugin);
                PluginViewModels.Add(new PluginViewModel(plugin));
                Console.WriteLine($"已加载 IPluginWithUI: {plugin.PluginName}");
            }
        }
    }
}
// WpfMediaPlayer/ViewModels/PluginViewModel.cs
using SharedInterfaces;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Controls;

namespace WpfMediaPlayer.ViewModels
{
    public class PluginViewModel : INotifyPropertyChanged
    {
        private bool _isEnabled;

        public string PluginName => Plugin.PluginName;

        public bool IsEnabled
        {
            get => _isEnabled;
            set
            {
                if (_isEnabled != value)
                {
                    _isEnabled = value;
                    Plugin.IsEnabled = value;
                    OnPropertyChanged(nameof(IsEnabled));
                }
            }
        }

        public ObservableCollection<PluginParameterViewModel> Parameters { get; set; } = new 

ObservableCollection<PluginParameterViewModel>();

        public IPluginBase Plugin { get; set; }

        public UserControl Control
        {
            get
            {
                if (Plugin is IPluginWithUI pluginWithUI)
                {
                    return pluginWithUI.GetControl();
                }
                return null;
            }
        }

        public PluginViewModel(IPluginBase plugin)
        {
            Plugin = plugin;
            IsEnabled = plugin.IsEnabled;

            if (plugin is IPluginWithUI pluginWithUI)
            {
                foreach (var param in pluginWithUI.Parameters)
                {
                    Parameters.Add(new PluginParameterViewModel
                    {
                        Name = param.Key,
                        DisplayName = param.Key, // 可以根据需要更改显示名称
                        Value = Convert.ToDouble(param.Value),
                        Minimum = 0, // 根据插件定义设置
                        Maximum = 2, // 根据插件定义设置
                        Plugin = pluginWithUI
                    });
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
// WpfMediaPlayer/ViewModels/PluginParameterViewModel.cs
using SharedInterfaces;
using System.ComponentModel;

namespace WpfMediaPlayer.ViewModels
{
    public class PluginParameterViewModel : INotifyPropertyChanged
    {
        private double _value;

        public string Name { get; set; }
        public string DisplayName { get; set; }
        public double Value
        {
            get => _value;
            set
            {
                if (_value != value)
                {
                    _value = value;
                    OnPropertyChanged(nameof(Value));
                    // 更新插件的参数
                    if (Plugin != null && Plugin.Parameters.ContainsKey(Name))
                    {
                        Plugin.Parameters[Name] = value;
                    }
                }
            }
        }
        public double Minimum { get; set; }
        public double Maximum { get; set; }

        public IPluginWithUI Plugin { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

// SharedInterfaces/IComponent.cs
using System.Windows.Controls;

namespace SharedInterfaces
{
    public interface IComponent
    {
        /// <summary>
        /// 组件的名称
        /// </summary>
        string ComponentName { get; }

        /// <summary>
        /// 初始化组件
        /// </summary>
        void Initialize();

        /// <summary>
        /// 获取组件的 UserControl 界面
        /// </summary>
        /// <returns>UserControl用于显示</returns>
        UserControl GetControl();

        /// <summary>
        /// 释放组件资源
        /// </summary>
        void Unload();
    }
}
// SharedInterfaces/IPluginBase.cs
using System.Windows.Media.Imaging;

namespace SharedInterfaces
{
    public interface IPluginBase
    {
        /// <summary>
        /// 插件的名称
        /// </summary>
        string PluginName { get; }

        /// <summary>
        /// 插件是否启用
        /// </summary>
        bool IsEnabled { get; set; }

        /// <summary>
        /// 初始化插件
        /// </summary>
        void Initialize();

        /// <summary>
        /// 卸载插件，释放资源
        /// </summary>
        void Unload();

        /// <summary>
        /// 处理传入的帧并返回处理后的帧
        /// </summary>
        /// <param name="frame">输入的原始帧</param>
        /// <returns>处理后的帧</returns>
        BitmapSource ProcessFrame(BitmapSource frame);
    }
}
// SharedInterfaces/IPluginWithUI.cs
using System.Collections.Generic;
using System.Windows.Controls;

namespace SharedInterfaces
{
    public interface IPluginWithUI : IPluginBase
    {
        /// <summary>
        /// 获取插件的 UserControl 界面
        /// </summary>
        /// <returns>UserControl 用于显示</returns>
        UserControl GetControl();

        /// <summary>
        /// 获取插件的参数字典
        /// </summary>
        IDictionary<string, object> Parameters { get; }
    }
}
// SharedInterfaces/PluginParameter.cs
using System.ComponentModel;

namespace SharedInterfaces
{
    public class PluginParameter : INotifyPropertyChanged
    {
        private string name;
        private double value;
        private double min;
        private double max;

        public string Name
        {
            get => name;
            set { name = value; OnPropertyChanged(nameof(Name)); }
        }

        public double Value
        {
            get => value;
            set { this.value = value; OnPropertyChanged(nameof(Value)); }
        }

        public double Min
        {
            get => min;
            set { min = value; OnPropertyChanged(nameof(Min)); }
        }

        public double Max
        {
            get => max;
            set { max = value; OnPropertyChanged(nameof(Max)); }
        }

        public PluginParameter(string name, double value, double min, double max)
        {
            Name = name;
            Value = value;
            Min = min;
            Max = max;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
// FullFrameTbcPlugin/FullFrameStateMachine.cs
using System;

namespace FullFrameTbcPlugin
{
    public enum SyncState
    {
        Idle,
        DetectingHSYNC,
        DetectingVSYNC,
        SyncEstablished
    }

    public class FullFrameStateMachine
    {
        public SyncState CurrentState { get; private set; } = SyncState.Idle;
        public int HSYNCCount { get; private set; } = 0;
        public int VSYNCCount { get; private set; } = 0;

        // Parameters for detecting sync
        public double DriftThreshold { get; set; } = 0.5; // Threshold for drift detection

        public void Reset()
        {
            CurrentState = SyncState.Idle;
            HSYNCCount = 0;
            VSYNCCount = 0;
        }

        /// <summary>
        /// Process synchronization signals.
        /// </summary>
        /// <returns>True if synchronization is maintained, else False indicating drift.</returns>
        public bool ProcessSyncSignals()
        {
            // Placeholder for processing H-sync and V-sync signals
            // Implement actual sync signal detection based on frame analysis

            // For demonstration, simulate synchronization maintenance
            // In reality, analyze frame timestamps or frame content to detect sync

            // Example logic:
            // Detect if the current frame aligns with expected H-sync and V-sync positions

            // Simulate synchronization logic
            // Always return true as a placeholder
            return true;
        }
    }
}
// FullFrameTbcPlugin/FullFrameTbcPlugin.cs
using SharedInterfaces;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Windows.Threading;

namespace FullFrameTbcPlugin
{
    public class FullFrameTbcPlugin : IPluginWithUI
    {
        // Plugin Metadata
        public string PluginName => "Full Frame Time Base Corrector";

        // Plugin Enabled State
        public bool IsEnabled { get; set; } = true;

        // Plugin Parameters Dictionary
        public IDictionary<string, object> Parameters { get; private set; }

        // UserControl for UI
        private UserControl _control;
        public UserControl GetControl()
        {
            return _control;
        }

        // Event to notify processed frames
        public event Action<BitmapSource> FrameProcessed;

        // Frame Buffering
        private readonly int _bufferSize = 10; // Number of frames in the sliding window
        private readonly Queue<BitmapSource> _frameBuffer;

        // DispatcherTimer for synchronization
        private readonly DispatcherTimer _timer;
        private double _syncInterval = 16.67; // Approx. 60 FPS

        // Drift Correction Parameter
        private double _driftCorrectionAmount = 1.0;

        // State Machine for synchronization
        private readonly FullFrameStateMachine _stateMachine;

        // Constructor
        public FullFrameTbcPlugin()
        {
            // Initialize Parameters with default values
            Parameters = new Dictionary<string, object>
            {
                { "EnableTbc", true },
                { "SyncInterval", _syncInterval }, // in milliseconds
                { "BufferSize", _bufferSize },
                { "DriftCorrectionAmount", _driftCorrectionAmount }
            };

            // Initialize Frame Buffer
            _frameBuffer = new Queue<BitmapSource>(_bufferSize);

            // Initialize State Machine
            _stateMachine = new FullFrameStateMachine
            {
                DriftThreshold = _driftCorrectionAmount
            };

            // Initialize UserControl for UI
            _control = new TbcPluginControl(this);

            // Initialize Timer
            _timer = new DispatcherTimer
            {
                Interval = TimeSpan.FromMilliseconds(_syncInterval)
            };
            _timer.Tick += Timer_Tick;
        }

        // Initialize the plugin (start the timer)
        public void Initialize()
        {
            if ((bool)Parameters["EnableTbc"])
            {
                _timer.Start();
                Console.WriteLine($"{PluginName} 已初始化并开始处理。");
            }
        }

        // Unload the plugin (stop the timer and clear the buffer)
        public void Unload()
        {
            _timer.Stop();
            lock (_frameBuffer)
            {
                _frameBuffer.Clear();
            }
            _stateMachine.Reset();
            Console.WriteLine($"{PluginName} 已卸载并停止处理。");
        }

        /// <summary>
        /// Receives a new frame for processing.
        /// This method should be called by the host application with each incoming frame.
        /// </summary>
        /// <param name="frame">The incoming frame as BitmapSource.</param>
        public void ReceiveFrame(BitmapSource frame)
        {
            if (!IsEnabled || !(bool)Parameters["EnableTbc"])
                return;

            lock (_frameBuffer)
            {
                if (_frameBuffer.Count >= _bufferSize)
                    _frameBuffer.Dequeue();
                _frameBuffer.Enqueue(frame);
            }
        }

        /// <summary>
        /// Timer tick event for synchronization and frame output.
        /// </summary>
        private void Timer_Tick(object sender, EventArgs e)
        {
            if (!IsEnabled || !(bool)Parameters["EnableTbc"])
                return;

            BitmapSource frameToOutput = null;

            // Implement Sliding Window Algorithm
            lock (_frameBuffer)
            {
                if (_frameBuffer.Count > 0)
                {
                    // Simple drift correction: pick the middle frame
                    int middleIndex = _frameBuffer.Count / 2;
                    frameToOutput = GetFrameAt(middleIndex);
                }
            }

            if (frameToOutput != null)
            {
                // Analyze synchronization signals
                bool isSyncMaintained = _stateMachine.ProcessSyncSignals();

                if (!isSyncMaintained)
                {
                    // Drift detected, apply correction
                    frameToOutput = ApplyDriftCorrection(frameToOutput);
                }

                // Output the corrected frame
                OutputFrame(frameToOutput);
            }
        }

        /// <summary>
        /// Retrieves a frame at the specified index from the buffer without dequeuing.
        /// </summary>
        /// <param name="index">Zero-based index</param>
        /// <returns>BitmapSource at the specified index</returns>
        private BitmapSource GetFrameAt(int index)
        {
            if (index < 0 || index >= _frameBuffer.Count)
                return null;

            return new List<BitmapSource>(_frameBuffer)[index];
        }

        /// <summary>
        /// Applies drift correction to the frame based on the drift correction amount.
        /// Implement the actual TBC logic here.
        /// </summary>
        /// <param name="frame">Frame to correct</param>
        /// <returns>Corrected frame</returns>
        private BitmapSource ApplyDriftCorrection(BitmapSource frame)
        {
            // TODO: Implement actual TBC drift correction logic here
            // Steps:
            // 1. Convert RGB to YCrCb if necessary
            // 2. Analyze frame alignment based on synchronization signals
            // 3. Adjust frame timing or position to correct drift

            // Placeholder example: Apply contrast adjustment based on driftCorrectionAmount
            // Replace with actual TBC algorithm

            WriteableBitmap wb = new WriteableBitmap(frame);
            int bytesPerPixel = (wb.Format.BitsPerPixel + 7) / 8;
            int stride = wb.PixelWidth * bytesPerPixel;
            byte[] pixelData = new byte[wb.PixelHeight * stride];
            wb.CopyPixels(pixelData, stride, 0);

            double contrast = _driftCorrectionAmount; // Example parameter usage

            for (int i = 0; i < pixelData.Length; i += bytesPerPixel)
            {
                // Adjust R, G, B channels
                for (int channel = 0; channel < 3; channel++)
                {
                    int pixelIndex = i + channel;
                    double color = pixelData[pixelIndex] / 255.0;
                    color = (color - 0.5) * contrast + 0.5;
                    color = Math.Max(0, Math.Min(1, color));
                    pixelData[pixelIndex] = (byte)(color * 255);
                }
                // Skip Alpha channel if present
            }

            wb.WritePixels(new System.Windows.Int32Rect(0, 0, wb.PixelWidth, wb.PixelHeight), 

pixelData, stride, 0);
            return wb;
        }

        /// <summary>
        /// Outputs the frame by raising the FrameProcessed event.
        /// </summary>
        /// <param name="frame">Processed frame</param>
        private void OutputFrame(BitmapSource frame)
        {
            FrameProcessed?.Invoke(frame);
            Console.WriteLine($"插件 {PluginName} 处理完成。");
        }

        public BitmapSource ProcessFrame(BitmapSource frame)
        {
            throw new NotImplementedException();
        }
    }
}
<!-- FullFrameTbcPlugin/TbcPluginControl.xaml -->
<UserControl x:Class="FullFrameTbcPlugin.TbcPluginControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Height="250" Width="350">
    <Grid>
        <StackPanel Margin="10">
            <TextBlock Text="Time Base Corrector Settings" FontWeight="Bold" FontSize="16" 

Margin="0,0,0,20"/>

            <!-- Enable TBC Toggle -->
            <CheckBox Content="Enable TBC" IsChecked="{Binding EnableTbc}" FontSize="14" 

Margin="0,0,0,15"/>

            <!-- Sync Interval Slider -->
            <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="0,0,0,10">
                <TextBlock Text="Sync Interval (ms): " Width="160" VerticalAlignment="Center" 

FontSize="14"/>
                <Slider Minimum="10" Maximum="1000" Value="{Binding SyncInterval}" Width="120"/>
                <TextBlock Text="{Binding SyncInterval, StringFormat=F0}" Width="50" 

VerticalAlignment="Center" Margin="10,0,0,0" FontSize="14"/>
            </StackPanel>

            <!-- Buffer Size Slider -->
            <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="0,0,0,10">
                <TextBlock Text="Buffer Size: " Width="160" VerticalAlignment="Center" 

FontSize="14"/>
                <Slider Minimum="5" Maximum="50" Value="{Binding BufferSize}" Width="120"/>
                <TextBlock Text="{Binding BufferSize, StringFormat=F0}" Width="50" 

VerticalAlignment="Center" Margin="10,0,0,0" FontSize="14"/>
            </StackPanel>

            <!-- Drift Correction Amount Slider -->
            <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="0,0,0,10">
                <TextBlock Text="Drift Correction Amount: " Width="160" VerticalAlignment="Center" 

FontSize="14"/>
                <Slider Minimum="0.5" Maximum="5.0" Value="{Binding DriftCorrectionAmount}" 

Width="120"/>
                <TextBlock Text="{Binding DriftCorrectionAmount, StringFormat=F1}" Width="50" 

VerticalAlignment="Center" Margin="10,0,0,0" FontSize="14"/>
            </StackPanel>
        </StackPanel>
    </Grid>
</UserControl>
// FullFrameTbcPlugin/TbcPluginControl.xaml.cs
using System.Windows.Controls;

namespace FullFrameTbcPlugin
{
    /// <summary>
    /// Interaction logic for TbcPluginControl.xaml
    /// </summary>
    public partial class TbcPluginControl : UserControl
    {
        private readonly TbcPluginViewModel _viewModel;

        public TbcPluginControl(FullFrameTbcPlugin plugin)
        {
            InitializeComponent();

            // Initialize ViewModel with plugin reference
            _viewModel = new TbcPluginViewModel
            {
                Plugin = plugin
            };
            _viewModel.Initialize();

            // Set DataContext
            this.DataContext = _viewModel;
        }
    }
}
// FullFrameTbcPlugin/TbcPluginViewModel.cs
using SharedInterfaces;
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace FullFrameTbcPlugin
{
    public class TbcPluginViewModel : INotifyPropertyChanged
    {
        private bool _enableTbc;
        private double _syncInterval;
        private int _bufferSize;
        private double _driftCorrectionAmount;

        public bool EnableTbc
        {
            get => _enableTbc;
            set
            {
                if (_enableTbc != value)
                {
                    _enableTbc = value;
                    OnPropertyChanged();
                    UpdatePluginParameter("EnableTbc", value);
                }
            }
        }

        public double SyncInterval
        {
            get => _syncInterval;
            set
            {
                if (_syncInterval != value)
                {
                    _syncInterval = value;
                    OnPropertyChanged();
                    UpdatePluginParameter("SyncInterval", value);
                }
            }
        }

        public int BufferSize
        {
            get => _bufferSize;
            set
            {
                if (_bufferSize != value)
                {
                    _bufferSize = value;
                    OnPropertyChanged();
                    UpdatePluginParameter("BufferSize", value);
                }
            }
        }

        public double DriftCorrectionAmount
        {
            get => _driftCorrectionAmount;
            set
            {
                if (_driftCorrectionAmount != value)
                {
                    _driftCorrectionAmount = value;
                    OnPropertyChanged();
                    UpdatePluginParameter("DriftCorrectionAmount", value);
                }
            }
        }

        public FullFrameTbcPlugin Plugin { get; set; }

        // Initialize ViewModel properties based on plugin parameters
        public void Initialize()
        {
            if (Plugin != null)
            {
                EnableTbc = Plugin.Parameters.ContainsKey("EnableTbc") ? (bool)Plugin.Parameters

["EnableTbc"] : true;
                SyncInterval = Plugin.Parameters.ContainsKey("SyncInterval") ? 

(double)Plugin.Parameters["SyncInterval"] : 16.67;
                BufferSize = Plugin.Parameters.ContainsKey("BufferSize") ? Convert.ToInt32

(Plugin.Parameters["BufferSize"]) : 10;
                DriftCorrectionAmount = Plugin.Parameters.ContainsKey("DriftCorrectionAmount") ? 

(double)Plugin.Parameters["DriftCorrectionAmount"] : 1.0;
            }
        }

        // Update plugin parameters when ViewModel properties change
        private void UpdatePluginParameter(string key, object value)
        {
            if (Plugin != null && Plugin.Parameters.ContainsKey(key))
            {
                Plugin.Parameters[key] = value;

                // Apply changes to the plugin as needed
                if (key == "SyncInterval")
                {
                    // Update timer interval
                    if (Plugin is FullFrameTbcPlugin tbcPlugin)
                    {
                        tbcPlugin.GetControl()?.Dispatcher.Invoke(() =>
                        {
                            // Assuming the plugin has a way to update the timer interval
                            // This might require additional implementation in the plugin class
                        });
                    }
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }
}

严重性	代码	说明	项目	文件	行	禁止显示状态
错误	CS1061	“IPluginWithUI”未包含“FrameProcessed”的定义，并且找不到可接受第一

个“IPluginWithUI”类型参数的可访问扩展方法“FrameProcessed”(是否缺少 using 指令或程序集引用?)		

I:\编程项目\2024 播放器\2024 播放器\PluginManager.cs	114	
错误	CS7036	未提供与“PluginManager.PluginManager(Image)”的必需形参“imageDisplay”对应的实参	

2024 播放器	I:\编程项目\2024 播放器\2024 播放器\MainWindow.xaml.cs	29	活动
错误	CS7036	未提供与“PluginManager.PluginManager(Image)”的必需形参“imageDisplay”对应的实参	

	I:\编程项目\2024 播放器\2024 播放器\MainWindow.xaml.cs	29	
消息	IDE0044	将字段设置为只读	JPN TBC	I:\编程项目\2024 播放器\JPN TBC

\FullFrameTbcPlugin\FullFrameTbcPlugin.cs	24	活动
消息	IDE0044	将字段设置为只读	JPN TBC	I:\编程项目\2024 播放器\JPN TBC

\FullFrameTbcPlugin\FullFrameTbcPlugin.cs	39	活动
消息	IDE0044	将字段设置为只读	JPN TBC	I:\编程项目\2024 播放器\JPN TBC

\FullFrameTbcPlugin\FullFrameTbcPlugin.cs	42	活动
消息	IDE0075	可以简化条件表达式	JPN TBC	I:\编程项目\2024 播放器\JPN TBC

\TbcPluginViewModel.cs	79	活动
消息	IDE0019	使用模式匹配	2024 播放器	I:\编程项目\2024 播放器\2024 播放器

\MainWindow.xaml.cs	580	活动
消息	IDE0019	使用模式匹配	2024 播放器	I:\编程项目\2024 播放器\2024 播放器

\MainWindow.xaml.cs	583	活动
错误	CS1061	“IPluginWithUI”未包含“FrameProcessed”的定义，并且找不到可接受第一

个“IPluginWithUI”类型参数的可访问扩展方法“FrameProcessed”(是否缺少 using 指令或程序集引用?)	

2024 播放器	I:\编程项目\2024 播放器\2024 播放器\PluginManager.cs	58	活动
错误	CS1061	“IPluginWithUI”未包含“FrameProcessed”的定义，并且找不到可接受第一

个“IPluginWithUI”类型参数的可访问扩展方法“FrameProcessed”(是否缺少 using 指令或程序集引用?)	

2024 播放器	I:\编程项目\2024 播放器\2024 播放器\PluginManager.cs	114	活动
错误	CS1061	“IPluginWithUI”未包含“FrameProcessed”的定义，并且找不到可接受第一

个“IPluginWithUI”类型参数的可访问扩展方法“FrameProcessed”(是否缺少 using 指令或程序集引用?)	

2024 播放器	I:\编程项目\2024 播放器\2024 播放器\PluginManager.cs	157	活动
错误	CS1061	“IPluginWithUI”未包含“FrameProcessed”的定义，并且找不到可接受第一

个“IPluginWithUI”类型参数的可访问扩展方法“FrameProcessed”(是否缺少 using 指令或程序集引用?)		

I:\编程项目\2024 播放器\2024 播放器\PluginManager.cs	58	
错误	CS1061	“IPluginWithUI”未包含“FrameProcessed”的定义，并且找不到可接受第一

个“IPluginWithUI”类型参数的可访问扩展方法“FrameProcessed”(是否缺少 using 指令或程序集引用?)		

I:\编程项目\2024 播放器\2024 播放器\PluginManager.cs	157	 NET4.8