admin 发布的文章

1.创建Vue项目

vue create my-project

自定义.png

2.调整初始化目录(删除多余的初始化文件、修改router 和 App.vue、新增其他企业规范化推荐目录)
根据这个项目可以添加 utils(工具函数) 、 plugins(插件配置vant) 、 services(api、request)

3.使用Vant组件库(UI组件)来快速的构建应用界面, 文档地址:vant-ui.github.io/vant/v2/
推荐自动按需引入组件,按需导入可以在 main.js 或者 指定VUE文件中导入,也可以单独封装一个vantUi.js导入到main.js
配置 Viewport 布局
其他组件库.png

4.创建view页面(首页导航)后先配置一级路由再配置二级路由

Aspose.Slides for .NET 22.11 新增将演示文稿转换为视频(将 PowerPoint 演示文稿转换为具有动画和过渡效果的视频)
Aspose.Slides 现在可以播放演示文稿,并以特定的每秒帧数 (FPS) 为整个动画生成一组帧。然后可以使用这些帧通过 FFmpeg 等工具创建视频。
此 C# 代码演示了将演示文稿导出为视频的操作,其中帧设置为 30FPS:

const int FPS = 30;

using (Presentation presentation = new Presentation("animated.pptx"))
{
    using (var animationsGenerator = new PresentationAnimationsGenerator(presentation))
    using (var player = new PresentationPlayer(animationsGenerator, FPS))
    {
        player.FrameTick += (sender, args) =>
        {
            args.GetFrame().Save($"frame_{sender.FrameIndex}.png");
        };

        animationsGenerator.Run(presentation.Slides);
    }
}

PresentationAnimationsGenerator类是一个按顺序生成单个动画效果的源,然后使用PresentationPlayer类播放这些效果。每个帧都会生成一个FrameTick事件,以便您可以将当前帧保存到磁盘或将帧写入视频流。

教程:https://blog.aspose.com/slides/convert-ppt-to-video-csharp/

核心问题 由于一个处理的不是骑缝章 ModifyRidingSeamStampWidth和ModifyRidingSeamStampHeight 为0

 // 将骑缝章的cm尺寸转化为px
            (double widthPx, double heightPx) = ImageUtilities.CentimetersToPixels(RidingSeamStampWidth, RidingSeamStampHeight, RidingSeamStampDpiX, RidingSeamStampDpiY);

            // 调整图片大小、透明度
            BitmapSource modifyImage = ImageUtilities.ModifyImage(RidingSeamStampFilePath, widthPx, heightPx, RidingSeamStampTransparency);

            // 将骑缝章的像素尺寸转化为point
            (double widthPt, double heightPt) = ImageUtilities.PixelsToPoints(modifyImage.PixelWidth, modifyImage.PixelHeight, RidingSeamStampDpiX, RidingSeamStampDpiY);

            // 调整骑缝章尺寸
            modifyImage = ImageUtilities.ResizeBitmapSource(modifyImage, widthPt, heightPt);

            // 获取调整后骑缝章图片的宽度和高度
            ModifyRidingSeamStampWidth = widthPt;
            ModifyRidingSeamStampHeight = heightPt;
// 调整图片大小
img.ScaleAbsolute((float)ModifyRidingSeamStampWidth, (float)ModifyRidingSeamStampHeight);

<CheckBox Width="90" Content="比例缩放" VerticalAlignment="Center" VerticalContentAlignment="Center" IsChecked="{Binding IsProportional}" Cursor="Hand" Padding="0 0 0 0">
                                <CheckBox.Style>
                                    <Style TargetType="CheckBox">
                                        <Style.Triggers>
                                            <DataTrigger Binding="{Binding StampFilePath}" Value="{x:Null}">
                                                <Setter Property="IsEnabled" Value="False"/>
                                            </DataTrigger>
                                            <DataTrigger Binding="{Binding StampFilePath}" Value="">
                                                <Setter Property="IsEnabled" Value="False"/>
                                            </DataTrigger>
                                        </Style.Triggers>
                                    </Style>
                                </CheckBox.Style>
                            </CheckBox>

如果非圆形图像,旋转的时候需要计算旋转后的画布尺寸,不然的话会导致旋转后显示的图像不全,最后将将图像绘制在新的中心位置。

// 修改图片大小、旋转角度、透明度 (印章)(预览)
        public static BitmapSource ModifyImage(string imagePath, double newWidth, double newHeight, double rotationAngle, double stampTransparency)
        {
            // 加载图像
            BitmapImage bitmap = new BitmapImage(new Uri(imagePath));

            // 调整图像尺寸
            TransformedBitmap resizedBitmap = new TransformedBitmap(bitmap, new ScaleTransform(newWidth / bitmap.PixelWidth, newHeight / bitmap.PixelHeight));

            // 计算旋转后的画布尺寸
            double radians = rotationAngle * Math.PI / 180;
            double sin = Math.Abs(Math.Sin(radians));
            double cos = Math.Abs(Math.Cos(radians));

            double rotatedWidth = resizedBitmap.PixelWidth * cos + resizedBitmap.PixelHeight * sin;
            double rotatedHeight = resizedBitmap.PixelWidth * sin + resizedBitmap.PixelHeight * cos;

            // 创建一个新的 DrawingVisual
            DrawingVisual drawingVisual = new DrawingVisual();
            using (DrawingContext drawingContext = drawingVisual.RenderOpen())
            {
                // 计算新的中心点
                double centerX = rotatedWidth / 2;
                double centerY = rotatedHeight / 2;

                // 创建旋转变换
                RotateTransform rotateTransform = new RotateTransform(rotationAngle, centerX, centerY);

                // 设置透明度
                drawingContext.PushOpacity(stampTransparency);

                // 应用旋转并绘制图像
                drawingContext.PushTransform(rotateTransform);

                // 将图像绘制在新的中心位置
                drawingContext.DrawImage(resizedBitmap, new Rect((rotatedWidth - resizedBitmap.PixelWidth) / 2, (rotatedHeight - resizedBitmap.PixelHeight) / 2, resizedBitmap.PixelWidth, resizedBitmap.PixelHeight));

                // 弹出变换和透明度设置
                drawingContext.Pop();
                drawingContext.Pop();
            }

            // 将Visual渲染为BitmapSource,使用旋转后的画布尺寸
            RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap((int)Math.Ceiling(rotatedWidth), (int)Math.Ceiling(rotatedHeight), bitmap.DpiX, bitmap.DpiY, PixelFormats.Pbgra32);
            renderTargetBitmap.Render(drawingVisual);

            return renderTargetBitmap;
        }

        // 修改图片旋转角度、透明度(印章)(PDF)
        public static BitmapSource ModifyImage(string imagePath, double rotationAngle, double stampTransparency)
        {
            // 加载图像
            BitmapImage bitmap = new BitmapImage(new Uri(imagePath));

            // 计算旋转后的画布尺寸
            double radians = rotationAngle * Math.PI / 180;
            double sin = Math.Abs(Math.Sin(radians));
            double cos = Math.Abs(Math.Cos(radians));

            double newWidth = bitmap.PixelWidth * cos + bitmap.PixelHeight * sin;
            double newHeight = bitmap.PixelWidth * sin + bitmap.PixelHeight * cos;

            // 创建一个新的 DrawingVisual
            DrawingVisual drawingVisual = new DrawingVisual();
            using (DrawingContext drawingContext = drawingVisual.RenderOpen())
            {
                // 计算新的中心点
                double centerX = newWidth / 2;
                double centerY = newHeight / 2;

                // 创建旋转变换
                RotateTransform rotateTransform = new RotateTransform(rotationAngle, centerX, centerY);

                // 设置透明度
                drawingContext.PushOpacity(stampTransparency);

                // 应用旋转并绘制图像
                drawingContext.PushTransform(rotateTransform);

                // 将图像绘制在新的中心位置
                drawingContext.DrawImage(bitmap, new Rect((newWidth - bitmap.PixelWidth) / 2, (newHeight - bitmap.PixelHeight) / 2, bitmap.PixelWidth, bitmap.PixelHeight));

                // 弹出变换和透明度设置
                drawingContext.Pop();
                drawingContext.Pop();
            }

            // 将Visual渲染为BitmapSource
            RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap((int)Math.Ceiling(newWidth), (int)Math.Ceiling(newHeight), bitmap.DpiX, bitmap.DpiY, PixelFormats.Pbgra32);
            renderTargetBitmap.Render(drawingVisual);

            return renderTargetBitmap;
        }

1.使用 TransformedBitmap 类(System.Windows.Media.Imaging)可以对图片进行缩放操作。

var originalBitmap = new BitmapImage(new Uri("yourImagePath"));

// 缩放图片
var scaleTransform = new ScaleTransform(0.5, 0.5); // 缩放比例:50%
var scaledBitmap = new TransformedBitmap(originalBitmap, scaleTransform);

// 旋转图片
var rotateTransform = new RotateTransform(45); // 旋转45度
var transformedBitmap = new TransformedBitmap(scaledBitmap, rotateTransform);

// 设置图片源
imageControl.Source = transformedBitmap;

// 设置透明度
imageControl.Opacity = 0.5; // 透明度设置为50%

2.System.Drawing (GDI+)

public static Bitmap ModifyImage(string imagePath, double newWidth, double newHeight, double rotationAngle, double stampTransparency, bool isCircle)
{
    // 加载图像
    Bitmap image = new Bitmap(imagePath);

    // 修改图像大小
    Bitmap resizedImage = new Bitmap((int)Math.Round(newWidth), (int)Math.Round(newHeight));

    using (Graphics g = Graphics.FromImage(resizedImage))
    {
        // 设置高质量插值法和抗锯齿模式
        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
        g.SmoothingMode = SmoothingMode.AntiAlias;
        g.PixelOffsetMode = PixelOffsetMode.HighQuality;

        // 绘制缩放后的图像
        g.DrawImage(image, 0, 0, resizedImage.Width, resizedImage.Height);
    }

    Bitmap finalImage;

    // 仅保留圆形处理的代码
    if (isCircle)
    {
        finalImage = new Bitmap(resizedImage.Width, resizedImage.Height, PixelFormat.Format32bppArgb);

        using (Graphics g = Graphics.FromImage(finalImage))
        {
            // 清除背景(透明)
            g.Clear(Color.Transparent);

            // 设置旋转中心为图像的中心
            g.TranslateTransform((float)resizedImage.Width / 2, (float)resizedImage.Height / 2);

            // 旋转图像
            g.RotateTransform((float)-rotationAngle);

            // 重置变换矩阵回原点
            g.TranslateTransform(-(float)resizedImage.Width / 2, -(float)resizedImage.Height / 2);

            // 绘制图像
            g.DrawImage(resizedImage, new Point(0, 0));
        }
    }

    // 设置透明度
    if (stampTransparency >= 0)
    {
        // 创建一个新的位图,用于保存透明度应用后的图像
        Bitmap transparentImage = new Bitmap(finalImage.Width, finalImage.Height, PixelFormat.Format32bppArgb);

        using (Graphics g = Graphics.FromImage(transparentImage))
        {
            // 使用颜色矩阵应用透明度
            ColorMatrix colorMatrix = new ColorMatrix
            {
                Matrix33 = (float)(stampTransparency / 100.0f) // 设置Alpha值
            };
            ImageAttributes attributes = new ImageAttributes();
            attributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

            // 绘制图像,并应用透明度
            g.DrawImage(finalImage, new Rectangle(0, 0, finalImage.Width, finalImage.Height),
                        0, 0, finalImage.Width, finalImage.Height, GraphicsUnit.Pixel, attributes);
        }

        finalImage.Dispose(); // 释放旧的图像资源
        finalImage = transparentImage; // 用透明度应用后的图像替换
    }

    return finalImage;
}

样式:2024年08月06日 19:31:48

ffmpeg -i C:\Users\az102\Desktop\input.mp4 -vf "drawtext=fontfile='C\:/Windows/Fonts/simsun.ttc':text='%{pts\:localtime\:1722943908\:%Y年%m月%d日 %H\\\:%M\\\:%S}':x=100:y=100:fontsize=24:fontcolor=white:box=1:boxcolor=0x00000000" -codec:a copy C:\Users\az102\Desktop\output.mp4

样式:2024\12\19 08:40:05

ffmpeg -i C:\Users\az102\Desktop\input.mp4 -vf "drawtext=fontfile='C\:/Windows/Fonts/msyh.ttc':text='%{pts\:localtime\:1734568805\:%Y\\\\%m\\\\%d %H\\\:%M\\\:%S}':x=100:y=100:fontsize=19:fontcolor=white:box=1:boxcolor=0x00000000" -codec:a copy C:\Users\az102\Desktop\output.mp4

样式:2024/12/19 08:40:05

ffmpeg -i C:\Users\az102\Desktop\input.mp4 -vf "drawtext=fontfile='C\:/Windows/Fonts/msyhbd.ttc':text='%{pts\:localtime\:1734568805\:%Y/%m/%d %H\\\:%M\\\:%S}':x=100:y=100:fontsize=19:fontcolor=white:box=1:boxcolor=0x00000000" -codec:a copy C:\Users\az102\Desktop\output.mp4

样式:样式.png

ffmpeg -i C:\Users\az102\Desktop\video\input.mp4 -vf "drawtext=fontfile='C\:/Windows/Fonts/ARIALBD.TTF':text='%{pts\:localtime\:1734568805\:%Y/%m/%d %H\\\:%M\\\:%S}':x=100:y=100:fontsize=20.5:fontcolor=white:box=1:boxcolor=0x00000000, drawtext=fontfile='C\:/Windows/Fonts/ARIALBD.TTF':text='V800000_000000':x=100:y=125:fontsize=20.5:fontcolor=white:box=1:boxcolor=0x00000000" -codec:a copy C:\Users\az102\Desktop\output.mp4

            <Button Width="104.5" Command="{Binding StartCommand}" Content="开始" Margin="0,0,1,0" Foreground="White" Cursor="Hand">
                <Button.Template>
                    <ControlTemplate TargetType="Button">
                        <Border Background="#326CF3" CornerRadius="5,0,0,5">
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
                        </Border>
                    </ControlTemplate>
                </Button.Template>
            </Button>
            <Button Width="104.5" Command="{Binding ClearVideoDataListCommand}" Content="清空" Margin="0,0,0,0" Foreground="White" Cursor="Hand">
                <Button.Template>
                    <ControlTemplate TargetType="Button">
                        <Border Background="#326CF3" CornerRadius="0,5,5,0">
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
                        </Border>
                    </ControlTemplate>
                </Button.Template>
            </Button>

NuGet添加库引用: 确保项目中已经添加了 System.Windows.Interactivity 和 MvvmLightLibs

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

xmlns:command="http://www.galasoft.ch/mvvmlight"

AllowDrop="True"

<!-- 拖拽识别区域 -->
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="DragEnter">
            <command:EventToCommand Command="{Binding DragEnterAndOverCommand}" 
            PassEventArgsToCommand="True"/>
        </i:EventTrigger>
        <i:EventTrigger EventName="DragOver">
            <command:EventToCommand Command="{Binding DragEnterAndOverCommand}" 
            PassEventArgsToCommand="True"/>
        </i:EventTrigger>
        <i:EventTrigger EventName="Drop">
            <command:EventToCommand Command="{Binding DropCommand}" PassEventArgsToCommand="True"/>
        </i:EventTrigger>
        <i:EventTrigger EventName="DragLeave">
            <command:EventToCommand Command="{Binding DragLeaveCommand}" PassEventArgsToCommand="True"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>

        <!-- 透明遮罩层 -->
        <Border Grid.ColumnSpan="2" Background="#80808080" Visibility="{Binding IsImport}"/>

    // 是否正在拖放图片
    private string _isImport = "Collapsed";
    public string IsImport
    {
        get => _isImport;
        set => Set(ref _isImport, value, nameof(IsImport));
    }

        public RelayCommand<DragEventArgs> DragEnterAndOverCommand { get; private set; }
        public RelayCommand<DragEventArgs> DropCommand { get; private set; }
        public RelayCommand<DragEventArgs> DragLeaveCommand { get; private set; }

        // 拖拽进入、移动
        DragEnterAndOverCommand = new RelayCommand<DragEventArgs>(DragEnterAndOver);
        // 拖拽放入
        DropCommand = new RelayCommand<DragEventArgs>(Drop);
        // 拖拽离开
        DragLeaveCommand = new RelayCommand<DragEventArgs>(DragLeave);


        // 拖拽进入、移动
        private void DragEnterAndOver(DragEventArgs e)
        {
            // 检查拖入的数据是否为文件类型
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                IsImport = "Visible";
                e.Effects = DragDropEffects.Copy; // 显示复制的鼠标样式
            }
            else
            {
                IsImport = "Collapsed";
                e.Effects = DragDropEffects.None; // 显示禁止的鼠标样式
            }

            e.Handled = true;
        }

        // 拖拽放入
        private void Drop(DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                try
                {
                    // 获取拖放的所有文件路径
                    string[] selectFiles = (string[])e.Data.GetData(DataFormats.FileDrop);

                    // 定义支持的文件扩展名列表
                    string[] extensions = new string[] { ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff", ".webp", ".ico" };

                    List<string> imageFiles = new List<string>();
                    HashSet<string> existingFiles = new HashSet<string>(ImagePaths);

                    // 遍历所有拖放的文件和文件夹
                    foreach (var path in selectFiles)
                    {
                        if (Directory.Exists(path))
                        {
                            // 如果是文件夹,递归获取所有图片文件
                            Stack<string> dirs = new Stack<string>(new string[] { path });

                            while (dirs.Count > 0)
                            {
                                string currentDir = dirs.Pop();
                                try
                                {
                                    foreach (var file in Directory.GetFiles(currentDir))
                                    {
                                        if (extensions.Contains(Path.GetExtension(file).ToLower()) && !existingFiles.Contains(file))
                                        {
                                            imageFiles.Add(file);
                                            existingFiles.Add(file);
                                        }
                                    }

                                    foreach (var subDir in Directory.GetDirectories(currentDir))
                                    {
                                        dirs.Push(subDir);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    // 处理文件夹读取异常
                                    HandyControl.Controls.MessageBox.Show($"读取文件夹时出现错误:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                                }
                            }
                        }
                        else if (File.Exists(path))
                        {
                            // 如果是文件,检查扩展名并添加到图片列表中
                            if (extensions.Contains(Path.GetExtension(path).ToLower()) && !existingFiles.Contains(path))
                            {
                                imageFiles.Add(path);
                                existingFiles.Add(path);
                            }
                        }
                    }

                    if (SequentialTypesetting)
                    {
                        // 添加符合扩展名的文件到 ImagePaths 列表中
                        foreach (var file in imageFiles)
                        {
                            ImagePaths.Add(file);
                        }
                    }
                    else if (RandomTypesetting)
                    {
                        // 创建Random实例
                        var random = new Random();

                        // 打乱文件列表
                        var shuffledFiles = imageFiles.OrderBy(x => random.Next()).ToList();

                        // 将列表分割为两部分
                        int middle = shuffledFiles.Count / 2;
                        var firstHalf = shuffledFiles.Take(middle).ToList();
                        var secondHalf = shuffledFiles.Skip(middle).ToList();

                        // 交错合并两个列表
                        var mixedFiles = new List<string>();
                        int maxLength = Math.Max(firstHalf.Count, secondHalf.Count);
                        for (int i = 0; i < maxLength; i++)
                        {
                            if (i < secondHalf.Count)
                                mixedFiles.Add(secondHalf[i]);
                            if (i < firstHalf.Count)
                                mixedFiles.Add(firstHalf[i]);
                        }

                        // 保存文件路径
                        foreach (var file in mixedFiles)
                        {
                            ImagePaths.Add(file);
                        }
                    }

                    // 标记事件已处理
                    e.Handled = true;

                    // 导入图片数量
                    ImportedImagesCount = ImagePaths.Count;

                    if (StitchableImagesCount == 0 || StitchAfterNImages == 0)
                    {
                        // 拼接图片数量
                        StitchableImagesCount = 1;
                    }
                    else
                    {
                        // 可拼接图片数量
                        StitchableImagesCount = (int)Math.Ceiling((double)ImportedImagesCount / StitchAfterNImages);
                    }
                    // 显示返回按钮
                    BackVisible = "Visible";

                    // 检查是否有图片文件
                    if (ImagePaths.Any())
                    {
                        IsEnableParameter = true;

                        IsImageWatermarkSelected = false;
                        IsTextWatermarkSelected = false;

                        WatermarkImagePath = "";
                        WatermarkImageWidth = 0;
                        WatermarkImageHeight = 0;

                        WatermarkText = "";
                        FontType = "微软雅黑";
                        FontSize = 30;
                        TextColor = "#FFFFFF";

                        WatermarkRotationAngle = 0;
                        WatermarkOpacity = 100;
                        WatermarkPosition = "右下";
                        WatermarkSpacing = 200;

                        Preview();
                    }
                    else
                    {
                        IsEnableParameter = false;
                        HandyControl.Controls.MessageBox.Show("所选文件夹中没有找到任何图片文件!", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                        SelectedFolderPath = string.Empty;
                    }
                }
                catch (Exception ex)
                {
                    IsEnableParameter = false;
                    HandyControl.Controls.MessageBox.Show($"加载图片路径时出现错误:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                    // 标记事件已处理
                    e.Handled = true;
                }
                finally
                {
                    IsImport = "Collapsed";
                }
            }
        }

        // 拖拽离开
        private void DragLeave(DragEventArgs e)
        {
            IsImport = "Collapsed";
            e.Handled = true;
        }

<TextBox Text="{Binding SaveHeight, UpdateSourceTrigger=PropertyChanged}" 
         Width="70" 
         Grid.Column="1" 
         Margin="5 0 0 0" 
         Style="{StaticResource TextBoxExtend}" />

在同一页面中使用 System.Windows.Media 和 iTextSharp 绘制文本时出现位置不一致的问题,主要是因为两个库在处理文本的基线和坐标系统方面存在差异。要解决这个问题,我们需要了解这两个库在定位文本时的具体差异,并调整相应的代码以确保文本在视觉上的一致性。

  1. 坐标系统的差异
    System.Windows.Media: 通常使用的是一个基于屏幕左上角为原点的坐标系统,Y轴正方向向下。
    iTextSharp: 在PDF中,坐标系统的原点通常在页面左下角,Y轴正方向向上。
  2. 文本基线的处理
    System.Windows.Media: 文本的定位通常是基于左上角的边界框。
    iTextSharp: 文本的定位通常是基于文字的基线。

解决方案
要确保在使用 System.Windows.Media 和 iTextSharp 绘制相同大小和样式的文本时,文本的位置相匹配,您可以采取以下步骤:

A. 确定正确的文本位置
测量文本高度:

对于 iTextSharp,使用 BaseFont 的 GetAscentPoint 和 GetDescentPoint 方法来获取文本高度。
对于 System.Windows.Media,使用 FormattedText 类来计算文本的实际高度。
计算文本基线位置:

在 iTextSharp 中,使用 ascent 值来调整文本的 Y 坐标。
在 System.Windows.Media 中,需要计算文本框高度,并相应地调整 Y 坐标,使得文本的基线与 iTextSharp 生成的基线对齐。

1.Media 中的单位为px iTextSharp 单位为point
2.在 System.Windows.Media 中,文本的定位可能依赖于控件或具体的绘图命令,常常是以文本框的左上角为参考。在 iTextSharp 中,文本的定位通常是以文本的基线为参考。这意味着指定的Y坐标是文本基线的位置。
3.Media 坐标原点左上角 iTextSharp 坐标原点左下角

npm config set registry https://registry.npmmirror.com
npm config set registry http://mirrors.cloud.tencent.com/npm/

yarn config set registry https://registry.npmmirror.com
npm config set registry https://registry.npmmirror.com --global
npm config set disturl https://npmmirror.com/dist --global

1.创建 ViewModelLocator 类
右键点击 ViewModel 文件夹,选择 添加 > 类,命名为 ViewModelLocator.cs。
在 ViewModelLocator.cs 文件中,添加以下代码:

using CommonServiceLocator;
using GalaSoft.MvvmLight.Ioc;

namespace VideoWatermark_Premium.ViewModel
{
    public class ViewModelLocator
    {
        public ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            // Register ViewModels
            SimpleIoc.Default.Register<MainWindowViewModel>();
        }

        public MainWindowViewModel MainWindowViewModel
        {
            get { return ServiceLocator.Current.GetInstance<MainWindowViewModel>(); }
        }

        public static void Cleanup()
        {
            // TODO Clear the ViewModels
        }
    }
}

2.修改 App.xaml 文件
打开 App.xaml 文件。
修改 App.xaml 文件,添加 ViewModelLocator 资源:

<Application x:Class="VideoWatermark_Premium.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:vm="clr-namespace:VideoWatermark_Premium.ViewModel"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <!-- HandyControl 主题-->
                <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/>
                <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/>
            </ResourceDictionary.MergedDictionaries>
            <!-- ViewModelLocator -->
            <vm:ViewModelLocator x:Key="Locator" />
        </ResourceDictionary>
    </Application.Resources>
</Application>

3.设置 MainWindow 的 DataContext
打开 MainWindow.xaml 文件。
设置 DataContext,使其绑定到 ViewModelLocator 的 MainWindowViewModel 属性:

<Window x:Class="VideoWatermark_Premium.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        DataContext="{Binding Source={StaticResource Locator}, Path=MainWindowViewModel}"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock Text="{Binding WelcomeMessage}" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="24"/>
    </Grid>
</Window>

选择一个或者多个文件文件:Microsoft.WindowsAPICodePack.Dialogs.CommonOpenFileDialog
选择文件夹:Microsoft.WindowsAPICodePack.Dialogs.CommonOpenFileDialog
保存文件夹:Microsoft.WindowsAPICodePack.Dialogs.CommonSaveFileDialog

NuGet 包管理器安装安装 WindowsAPICodePack-Shell

选择一个或者多个文件: OpenFileDialog
保存文件夹:SaveFileDialog

Microsoft.Win32

选择一个或者多个文件:OpenFileDialog
选择文件夹:FolderBrowserDialog
保存文件夹:SaveFileDialog

System.Windows.Forms