更新mvvm

This commit is contained in:
xiang 2025-01-11 21:43:03 +08:00
parent 29830df36c
commit cb7608ed7b
13 changed files with 518 additions and 49 deletions

View File

@ -7,7 +7,7 @@ namespace VideoConcat
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
public partial class App : System.Windows.Application
{
}

188
Common/Tools/LogUtils.cs Normal file
View File

@ -0,0 +1,188 @@
using log4net;
using log4net.Config;
using System.IO;
namespace VideoConcat.Common.Tools
{
class LogUtils
{
private static readonly ILog loginfo = LogManager.GetLogger("loginfo");
/// <summary>
/// 从缺省配置文件获取日志配置
/// </summary>
public static void SetConfig()
{
XmlConfigurator.Configure();
}
/// <summary>
/// 从指定配置文件获取日志配置
/// </summary>
/// <param name="configFile">指定的配置文件</param>
public static void SetConfig(FileInfo configFile)
{
XmlConfigurator.Configure(configFile);
}
/// <summary>
/// 生成分类日志
/// </summary>
/// <param name="info">日志信息</param>
/// <param name="dirName">保存目录名,形如d:\log\aaa</param>
private static void WriteSortLog(string info, string dirName)
{
try
{
if (false == Directory.Exists(dirName))
{
Directory.CreateDirectory(dirName);
}
string path = dirName + "\\" + DateTime.Now.ToString("yyyyMMdd") + ".log";
StreamWriter sw = new(path, true, System.Text.Encoding.Default);
sw.WriteLine(DateTime.Now.ToString("HH:mm:ss: ") + info);
sw.Close();
}
catch (Exception ex)
{
string expMsg = "WriteSortLog异常" + ex.Message + Environment.NewLine + ex.StackTrace;
if (ex.InnerException != null)
expMsg += Environment.NewLine + "InnerException:" + ex.InnerException.Message;
Error(expMsg, ex);
}
}
/// <summary>
/// Info级 常规日志
/// </summary>
/// <param name="info">日志信息</param>
public static void Info(string info)
{
if (loginfo.IsInfoEnabled)
{
loginfo.Info(info);
}
}
/// <summary>
/// Info 先生成常规日志,然后在指定目录另外创建一份日志
/// 主要用来需要对日志进行分类时使用
/// </summary>
/// <param name="info"></param>
/// <param name="dirName"></param>
public static void Info(string info, string dirName)
{
if (loginfo.IsInfoEnabled)
{
//生成常规日志
loginfo.Info(info);
//生成分类日志
WriteSortLog(info, dirName);
}
}
/// <summary>
/// Debug级 常规日志
/// </summary>
/// <param name="info">日志信息</param>
public static void Debug(string info)
{
if (loginfo.IsDebugEnabled)
{
loginfo.Debug(info);
}
}
/// <summary>
/// Debug级 异常日志
/// </summary>
/// <param name="info">日志信息</param>
/// <param name="exp">异常信息</param>
public static void Debug(string info, Exception exp)
{
if (loginfo.IsDebugEnabled)
{
loginfo.Debug(info, exp);
}
}
/// <summary>
/// Error级 常规的日志
/// </summary>
/// <param name="info">日志信息</param>
public static void Error(string info)
{
if (loginfo.IsErrorEnabled)
{
loginfo.Error(info);
}
}
/// <summary>
/// Error 异常日志
/// </summary>
/// <param name="info">日志信息</param>
/// <param name="exp">异常信息</param>
public static void Error(string info, Exception exp)
{
if (loginfo.IsErrorEnabled)
{
loginfo.Error(info, exp);
}
}
/// <summary>
/// Fatal级 常规日志
/// </summary>
/// <param name="info">日志信息</param>
public static void Fatal(string info)
{
if (loginfo.IsFatalEnabled)
{
loginfo.Fatal(info);
}
}
/// <summary>
/// Fatal级 异常日志
/// </summary>
/// <param name="info">日志信息</param>
/// <param name="exp">异常信息</param>
public static void Fatal(string info, Exception exp)
{
if (loginfo.IsFatalEnabled)
{
loginfo.Fatal(info, exp);
}
}
/// <summary>
/// Warn级 常规日志
/// </summary>
/// <param name="info">日志信息</param>
public static void Warn(string info)
{
if (loginfo.IsWarnEnabled)
{
loginfo.Warn(info);
}
}
/// <summary>
/// Warn级 异常日志
/// </summary>
/// <param name="info">日志</param>
/// <param name="exp">异常信息</param>
public static void Warn(string info, Exception exp)
{
if (loginfo.IsWarnEnabled)
{
loginfo.Warn(info, exp);
}
}
}
}

View File

@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VideoConcat.Models
{
internal class MainWindowModel
{
public string? UserName { get; set; }
public string? PassWord { get; set; }
}
}

112
Models/VideoModel.cs Normal file
View File

@ -0,0 +1,112 @@
using Standard;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Xml.Linq;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Header;
namespace VideoConcat.Models
{
public class VideoModel : INotifyPropertyChanged
{
private int _num;
private string _folderPath = "";
private bool _canStart = false;
private ObservableCollection<FolderInfo> _FolderInfos = [];
public int Num
{
get { return _num; }
set
{
_num = value;
OnPropertyChanged();
}
}
public struct FolderInfo
{
public DirectoryInfo DirectoryInfo{set;get;}
public int Num { set; get; }
}
public ObservableCollection<FolderInfo> FolderInfos
{
get { return _FolderInfos; }
set
{
if (_FolderInfos != null)
{
_FolderInfos.CollectionChanged -= ItemList_CollectionChanged;
}
_FolderInfos = value;
if (_FolderInfos != null)
{
_FolderInfos.CollectionChanged += ItemList_CollectionChanged;
}
OnPropertyChanged();
UpdateSum();
}
}
public string FolderPath
{
get { return _folderPath; }
set
{
_folderPath = value;
OnPropertyChanged(nameof(FolderPath));
}
}
public bool CanStart
{
get { return _canStart; }
set
{
_canStart = value;
OnPropertyChanged(nameof(CanStart));
}
}
public ICommand? BtnOpenFolderCommand { get; set; }
public ICommand? BtnStartVideoConcatCommand { get; set; }
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void ItemList_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
UpdateSum();
}
public void UpdateSum()
{
int _temp = 1;
foreach (var item in FolderInfos)
{
if (item.Num > 0)
{
_temp *= item.Num;
}
}
Num = _temp;
if(Num > 0){
CanStart = true;
}
}
}
}

View File

@ -7,6 +7,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>

View File

@ -5,8 +5,6 @@ VisualStudioVersion = 17.11.35327.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VideoConcat", "VideoConcat.csproj", "{2FF5691C-3184-4B68-944B-C704E64C4E4E}"
EndProject
Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "Setup", "..\Setup\Setup.vdproj", "{7EE4FDA6-076F-494D-89C5-B3735A89875F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -17,8 +15,6 @@ Global
{2FF5691C-3184-4B68-944B-C704E64C4E4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2FF5691C-3184-4B68-944B-C704E64C4E4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2FF5691C-3184-4B68-944B-C704E64C4E4E}.Release|Any CPU.Build.0 = Release|Any CPU
{7EE4FDA6-076F-494D-89C5-B3735A89875F}.Debug|Any CPU.ActiveCfg = Debug
{7EE4FDA6-076F-494D-89C5-B3735A89875F}.Release|Any CPU.ActiveCfg = Release
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VideoConcat.Models;
namespace VideoConcat.ViewModels
{
internal class MainWindowViewModel
{
public MainWindowModel MainWindowsModel { get; set; } = new MainWindowModel();
public void Login()
{
string userName = MainWindowsModel.UserName;
string passWord = MainWindowsModel.PassWord;
}
}
}

View File

@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using VideoConcat.Models;
using System.Windows;
using System.Windows.Forms;
using MessageBox = System.Windows.MessageBox;
using System.ComponentModel;
using VideoConcat.Common.Tools;
using System.IO;
using static VideoConcat.Models.VideoModel;
namespace VideoConcat.ViewModels
{
public class VideoViewModel
{
private VideoModel _videoModel;
public VideoModel VideoModel
{
get { return _videoModel; }
set
{
_videoModel = value;
}
}
public VideoViewModel()
{
VideoModel = new VideoModel();
VideoModel.BtnOpenFolderCommand = new BtnOpenFolderCommand()
{
DoExcue = obj =>
{
FolderBrowserDialog folderBrowserDialog = new();
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
{
VideoModel.FolderPath = folderBrowserDialog.SelectedPath;
LogUtils.Info($"获取视频文件夹,视频路径:{VideoModel.FolderPath}");
ListFolder(VideoModel.FolderPath);
}
}
};
VideoModel.BtnStartVideoConcatCommand = new BtnStartVideoConcatCommand()
{
DoExcue = obj =>
{
LogUtils.Info("开始合并视频");
}
};
}
private void ListFolder(string path)
{
DirectoryInfo dir = new(path);
try
{
DirectoryInfo dirD = dir as DirectoryInfo;
DirectoryInfo[] folders = dirD.GetDirectories();
VideoModel.FolderInfos.Clear();
//获取文件夹下所有视频文件
foreach (DirectoryInfo Folder in folders)
{
string[] files = Directory.GetFiles(Folder.FullName, "*.mp4");
LogUtils.Info($"{Folder.Name}下有{files.Length}个视频文件");
VideoModel.FolderInfos.Add(new FolderInfo { DirectoryInfo = Folder, Num = files.Length });
}
VideoModel.UpdateSum();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
}
}
class BtnOpenFolderCommand : ICommand
{
public event EventHandler? CanExecuteChanged;
public bool CanExecute(object? parameter) => true;
public void Execute(object? parameter)
{
DoExcue?.Invoke(parameter);
}
public Action<Object?>? DoExcue { get; set; }
}
class BtnStartVideoConcatCommand : ICommand
{
public event EventHandler? CanExecuteChanged;
public bool CanExecute(object? parameter) => true;
public void Execute(object? parameter)
{
DoExcue?.Invoke(parameter);
}
public Action<Object?>? DoExcue { get; set; }
}
}

View File

@ -33,7 +33,7 @@
<materialDesign:PackIcon
Width="30" Height="30"
Kind="User" Margin="10,0,10,0"/>
<TextBox Text="{Binding MainWindowModel.UserName}" Width="400"
<TextBox x:Name="Username" Width="400"
Margin="10,0" BorderBrush="White"
CaretBrush="#FFD94448"
SelectionBrush="#FFD94448"
@ -49,13 +49,13 @@
CaretBrush="#FFD94448"
SelectionBrush="#FFD94448"
materialDesign:HintAssist.Hint="输入 密码"
local:MainWindowModel="{Binding MainWindowModel.Password}"
>
</PasswordBox>
x:Name="Password"
/>
</StackPanel>
<StackPanel Margin="10" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="btnLogin" Width="100" Height="40"
materialDesign:ButtonAssist.CornerRadius="5"
materialDesign:ButtonAssist.CornerRadius="2"
Background="#40568D" BorderBrush="#7F7F7F" BorderThickness="2"
Content="登录" ToolTip="登录"
Style="{StaticResource MaterialDesignRaisedButton}" Click="BtnLogin_Click"/>

View File

@ -1,6 +1,4 @@
using System.Windows;
using System.Windows.Input;
using VideoConcat.Models;
namespace VideoConcat.Views
{
@ -12,7 +10,6 @@ namespace VideoConcat.Views
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowModel();
}
private void BtnExit_Click(object sender, RoutedEventArgs e)
@ -22,6 +19,11 @@ namespace VideoConcat.Views
private void BtnLogin_Click(object sender, RoutedEventArgs e)
{
if (Username.Text == "admin" && Password.Password == "123456")
{
}
new Video().Show();
}
}
}

55
Views/Video.xaml Normal file
View File

@ -0,0 +1,55 @@
<Window x:Name="视频拼接" x:Class="VideoConcat.Views.Video"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:local="clr-namespace:VideoConcat.Views"
mc:Ignorable="d"
Title="视频拼接" Height="600" Width="800" WindowStartupLocation="CenterScreen" ResizeMode="NoResize">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml"/>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.Red.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<StackPanel>
<StackPanel>
<Grid VerticalAlignment="Center" Margin="10,10">
<Grid.RowDefinitions>
<RowDefinition Height="35"></RowDefinition>
<RowDefinition Height="35"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="120"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label VerticalAlignment="Center" FontSize="16" Margin="5,0" BorderBrush="#7F7F7F" BorderThickness="2" Style="{StaticResource MaterialDesignLabel}" VerticalContentAlignment="Stretch">视频文件夹:</Label>
<TextBox Grid.Column="1" Name="FoldPath" Text="{Binding VideoModel.FolderPath,Mode=TwoWay}" IsReadOnly="True" Margin="5,0" BorderBrush="#7F7F7F" BorderThickness="2" FontSize="16" VerticalContentAlignment="Center" materialDesign:HintAssist.Hint="选择视频主文件夹"/>
<Button Grid.Column="2" Content="选择" FontSize="16" Command="{Binding VideoModel.BtnOpenFolderCommand}" Background="#40568D" BorderBrush="#7F7F7F" BorderThickness="2" ToolTip="选择含有视频的主文件夹" Style="{StaticResource MaterialDesignRaisedButton}" Margin="5,0" />
<Label Grid.Row="1" VerticalAlignment="Center" FontSize="16" Margin="5,0" BorderBrush="#7F7F7F" BorderThickness="2" Style="{StaticResource MaterialDesignLabel}" VerticalContentAlignment="Stretch">视频个数:</Label>
<TextBox Grid.Row="1" Grid.Column="1" Name="Num" Text="{Binding VideoModel.Num,Mode=TwoWay}" Margin="5,0" BorderBrush="#7F7F7F" BorderThickness="2" FontSize="16" VerticalContentAlignment="Center" ToolTip="请输入合成视频个数" materialDesign:HintAssist.Hint="请输入拼接视频数目"/>
<Button Grid.Row="1" Grid.Column="2" Content="开始拼接" FontSize="16" Command="{Binding VideoModel.BtnStartVideoConcatCommand}" Background="#E54858" BorderBrush="#7F7F7F" BorderThickness="2" ToolTip="开始拼接视频" Style="{StaticResource MaterialDesignRaisedButton}" Margin="5,0" IsEnabled="{Binding VideoModel.CanStart}" Cursor="Hand"/>
</Grid>
</StackPanel>
<StackPanel >
<DataGrid ItemsSource="{Binding VideoModel.FolderInfos}" AutoGenerateColumns="False">
<DataGrid.Columns >
<DataGridTextColumn Header="子文件夹" Binding="{Binding DirectoryInfo.Name,Mode=OneWay}" IsReadOnly="True" CanUserSort="False" CanUserReorder="False"/>
<DataGridTextColumn Header="视频个数" Binding="{Binding Num}" IsReadOnly="True" CanUserReorder="False" CanUserSort="False"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
<StackPanel>
</StackPanel>
</StackPanel>
</Grid>
</Window>

30
Views/Video.xaml.cs Normal file
View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using VideoConcat.Models;
using VideoConcat.ViewModels;
namespace VideoConcat.Views
{
/// <summary>
/// Video.xaml 的交互逻辑
/// </summary>
public partial class Video : Window
{
public Video()
{
InitializeComponent();
this.DataContext=new VideoViewModel();
}
}
}

View File

@ -16,7 +16,17 @@
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<!--布局(向用户显示最后经过格式化的输出信息)-->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="日志级别:%-5level,时间:%date,描述:%message,线程ID:%thread%newline"/>
<!--<conversionPattern value="日志级别:%-5level,时间:%date,描述:%message,线程ID:%thread%newline"/>-->
<conversionPattern value="================================================================
%n【日志级别】%-5level
%n【记录时间】%date
%n【线程编号】[%thread]
%n【执行时间】[%r]毫秒
%n【文 件】%F
%n【行 号】%L
%n【类 名】%logger 属性[%property{NDC}]
%n【描 述】%message
%n【详 情】%newline%n"/>
</layout>
</appender>
<root>