x<5CX6qf{$aZP@u`-IGotvg~>Gn>}xS7_mba42UBHo{NeRJ9NQ3vq87M
zZ=3r?KZchG`~Zj56|(b?L3|()_z&!;Z9Ud`wDj&nK#pU!D^+*ZqPwj87-qj-EdOm=
zU#mg5mZNZpkER$jJT!(S4=xSyWQx&eZCJv%ln5|+I>Tx_)wSPMxhL{
zhG4cNR1tlzm$aTwd}79YG{sfpYO_!-xgX)d6h`4^QwHy+*qTDo#}kY~c^u~`TeF)B
z`Rb@##X8Qzw{GcpFVmdU{P@=GJhQw<2JWZ$*zVtamAk30ao220u&ifj1cqt4a^JH<
zmxP<7p4hGh+M3Ik<+ORZ*=%f#waj^!zFiJZnyJWEi*V?V`^8JEN+YJKmm%FCB>&^x
zyBxx-v^Tc3I`ZeIQ-^V4swj5!Cwg^(IFW{lT^_fMhtq+TMVMIWTleY`34NO&Lpk+b
z2fTXELup7clsE3y1>(duQWS+I=YPV>Gd1f?068-(Jbl9|+1F$k!K-39URq>viEMkL
z9)t-lRunz^Q(e3mEN)gzEKJm0l&6Uox;3GftkS%QvYoG%3dNWbLMf)f%Nc+Pj;s-S
z|IVypf(c>{OF@Wh!LV%`{(~ul5M4(Mols0ltMCT?9}b%d_1(L7eGI%}r`C2;3sa%%
zq*9NfGTs&G(EvSRT9M*CyF4
zu9p_OSfiN5@H1O_IYDYSIZm}BK_Jz^`~~dufRISqR!w9dO>vq`XM>N`hs+I6wNGS(
zI;HXScjC_{%ru)eL$04VYrDA%<)&F2l(DeV?&g`QU>n1pGjm+bbLpiYt>*5ilAX5M
zl-ZCDuD42IwJ%LxTTgIj;K7`XS&tI^zP*%_ADcUyptmVPP$nMir$qm$3bo_7p7H47w66U;3mOW?-m_tO_C_pQf7CJ73{swmRB3c_(1&-4E*eMf@jgqP0GTUE>9ErPUCg+V${4w*m#Ik%dk2FDFU
zFG-TsYQ_HbywE-B`Mn}Wm>HWTw^dK!F?UB`snpiqAWOO?k|;eh&T>M&qFfbtW1{{}
ze0HTcY%~##`J@Pnv_sc*Dr0dRhaaGTa_*fUXsB^zN6!V!17}rOs%CF$Y!QBxf*+mVgDDupm>^8lim1pUgG&Q1#qH4Rnun|I7`2GrO6aNNQ=SxhQ)2asI
zd(JCwXHE7vy`UB1l_0RWTz&iMW(o)Dj`Xe$jkkFjQob>&irZRWUE}o*-emVG1g(6e
zLybb9mOABfVeW=XP=d4{@SqThm$x|>=@g?<4K&PU=GHc01g#1?Zb~^;kR~dGUy>Gq
z4&5aK1vD}DUy7Ec^`=eZ}L;%Ilt8+gh7Ye>lfhWruw=IQ5i1b#BaYk
z7GH5|!tGm>_JT(kl0&zragR0a3oVXmwW94%%XE0zcx*l*2f_jsP5!pNV_I<+UTFna
z5VaRPR?i3gk}tIaz|SMCdJcZ6dEH~CT0!BJFx}l)AeLQCkuiGdmRu;*n%@`8N@&{U~g}(w0FUz3>+6L
zsA`MntbJ7Zim!h}N`&w0R
zi$TwJ*$>97aJBucwBk0?78X|tv(sy8Fa+CQNdO;)g60j5HY2UVX08KVl`1{0xFc5}
zMremA&wQHuKXToeQ+%cHwc;Rk-PFg3w>qtEn&`aqP}~p|l6j6-u%L7Xv8d7RJVcf0
z@E-tB45Au6tt`|}dv0Juhp+Ep8?(fSl-lIA!rcOKK-`=byqc44B?${l5n*;xL6>`;vlGRu?^XuC%ZKWK=9ox<4I29=)&@_f!tVe8
literal 0
HcmV?d00001
diff --git a/CSharp/WPFTutorial/WPF-24-Controls/MainWindow.xaml b/CSharp/WPFTutorial/WPF-24-Controls/MainWindow.xaml
new file mode 100644
index 0000000..4a00bbb
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-24-Controls/MainWindow.xaml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-24-Controls/MainWindow.xaml.cs b/CSharp/WPFTutorial/WPF-24-Controls/MainWindow.xaml.cs
new file mode 100644
index 0000000..4ed29fb
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-24-Controls/MainWindow.xaml.cs
@@ -0,0 +1,35 @@
+using System.Windows;
+
+namespace WPF_24_Controls;
+
+///
+/// Interaction logic for MainWindow.xaml
+///
+public partial class MainWindow : Window
+{
+ public List Persons = [];
+
+ public MainWindow()
+ {
+ InitializeComponent();
+
+ Persons.Add(new Person { FirstName = "W1", LastName = "E1" });
+ Persons.Add(new Person { FirstName = "W2", LastName = "E2" });
+ Persons.Add(new Person { FirstName = "W3", LastName = "E3" });
+
+ ComboBox.ItemsSource = Persons;
+ }
+
+ private void SubmitButton_OnClick(object sender, RoutedEventArgs e)
+ {
+ MessageBox.Show($"Hello {FirstNameTextBlock.Text}");
+ }
+}
+
+public class Person
+{
+ public string? FirstName { get; set; }
+ public string? LastName { get; set; }
+
+ public string? FullName => $"{FirstName} {LastName}";
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-24-Controls/WPF-24-Controls.csproj b/CSharp/WPFTutorial/WPF-24-Controls/WPF-24-Controls.csproj
new file mode 100644
index 0000000..f951157
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-24-Controls/WPF-24-Controls.csproj
@@ -0,0 +1,19 @@
+
+
+
+ WinExe
+ net8.0-windows
+ WPF_24_Controls
+ enable
+ enable
+ true
+
+
+
+
+
+ Always
+
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-25-TreeView/App.xaml b/CSharp/WPFTutorial/WPF-25-TreeView/App.xaml
new file mode 100644
index 0000000..156235f
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-25-TreeView/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-25-TreeView/App.xaml.cs b/CSharp/WPFTutorial/WPF-25-TreeView/App.xaml.cs
new file mode 100644
index 0000000..a133c41
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-25-TreeView/App.xaml.cs
@@ -0,0 +1,128 @@
+using System.Diagnostics;
+using System.IO;
+using System.Windows;
+using System.Windows.Threading;
+
+namespace WPF_25_TreeView;
+
+///
+/// Interaction logic for App.xaml
+///
+public partial class App
+{
+ protected override void OnStartup(StartupEventArgs e)
+ {
+ // 全局未处理异常捕获(UI线程和非UI线程)
+ AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
+
+ // 专为WPF UI线程异常捕获(例如按钮点击事件中的异常)
+ DispatcherUnhandledException += OnDispatcherUnhandledException;
+
+ // 异步任务异常捕获
+ TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
+
+ base.OnStartup(e);
+ }
+
+ ///
+ /// 处理非UI线程异常
+ ///
+ private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
+ {
+ if (e.ExceptionObject is not Exception exception) return;
+ LogException(exception, "全局异常");
+
+ if (e.IsTerminating) // 如果是致命异常
+ {
+ ShowFatalError(exception);
+ Environment.Exit(1); // 确保应用退出
+ }
+ else
+ {
+ ShowUserFriendlyError(exception);
+ }
+ }
+
+ ///
+ /// 处理UI线程异常(可阻止应用崩溃)
+ ///
+ private static void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
+ {
+ LogException(e.Exception, "UI线程异常");
+ ShowUserFriendlyError(e.Exception);
+
+ // 标记为已处理,阻止应用崩溃(谨慎使用!)
+ e.Handled = true;
+ }
+
+ ///
+ /// 处理异步任务异常
+ ///
+ private static void OnUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
+ {
+ LogException(e.Exception, "异步任务异常");
+ e.SetObserved(); // 标记为已处理,避免进程崩溃
+ }
+
+ ///
+ /// 记录异常到日志文件
+ ///
+ private static void LogException(Exception ex, string category)
+ {
+ var logMessage = $"[{DateTime.Now}] [{category}]\n{ex}\n\n";
+
+ try
+ {
+ File.AppendAllText("app_errors.log", logMessage);
+ Debug.WriteLine(logMessage); // 输出到调试窗口
+ }
+ catch
+ {
+ /* 防止日志记录本身抛出异常 */
+ }
+ }
+
+ ///
+ /// 显示用户友好的错误提示
+ ///
+ private static void ShowUserFriendlyError(Exception ex)
+ {
+ var message = ex switch
+ {
+ UnauthorizedAccessException => $"权限不足: {ex.Message}\n请检查文件/文件夹权限。",
+ FileNotFoundException => $"文件未找到: {ex.Message}",
+ IOException => $"文件读写错误: {ex.Message}",
+ _ => $"发生错误: {(ex.InnerException ?? ex).Message}"
+ };
+
+ MessageBox.Show(
+ message,
+ "错误",
+ MessageBoxButton.OK,
+ MessageBoxImage.Error
+ );
+ }
+
+ ///
+ /// 显示致命错误并退出
+ ///
+ private static void ShowFatalError(Exception ex)
+ {
+ MessageBox.Show(
+ $"程序即将关闭,原因:\n{ex.Message}\n\n详细信息已记录到日志。",
+ "致命错误",
+ MessageBoxButton.OK,
+ MessageBoxImage.Stop
+ );
+ }
+
+ protected override void OnExit(ExitEventArgs e)
+ {
+ // 清理事件订阅
+ AppDomain.CurrentDomain.UnhandledException -= OnUnhandledException;
+ DispatcherUnhandledException -= OnDispatcherUnhandledException;
+ TaskScheduler.UnobservedTaskException -= OnUnobservedTaskException;
+
+ base.OnExit(e);
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-25-TreeView/AssemblyInfo.cs b/CSharp/WPFTutorial/WPF-25-TreeView/AssemblyInfo.cs
new file mode 100644
index 0000000..4a05c7d
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-25-TreeView/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-25-TreeView/Assets/code.ico b/CSharp/WPFTutorial/WPF-25-TreeView/Assets/code.ico
new file mode 100644
index 0000000000000000000000000000000000000000..17f9dd11abe93a4170a7879244d0fea91142ca9a
GIT binary patch
literal 67758
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
qfFZyTUd_qf*=C`
literal 0
HcmV?d00001
diff --git a/CSharp/WPFTutorial/WPF-25-TreeView/Assets/file.png b/CSharp/WPFTutorial/WPF-25-TreeView/Assets/file.png
new file mode 100644
index 0000000000000000000000000000000000000000..38b58c1b75989678d9209650e8c5570115d6f2b4
GIT binary patch
literal 404
zcmeAS@N?(olHy`uVBq!ia0vp^ZXnFT1|$ph9<=}|&H|6fVg?3oVGw3ym^DX&fq~J@
z)5S5QV$Rz;hF;8xB1b;jHp?B|{3PO$j^+{W4AqLR2V7Z86`B&3?&Yw)Il=$UWf#tT
zp?}Qr@^yR6`*Saqwg?DK`d3z2WY!~Idj9ieSL;`o79BLcyYuS4kA-$y9_wjpwOH0i
zJbSc4AnoJEtm*#2YJFUZZRbO)e@CT1S|Rc5Z}r^H#SAk%WLgg#d8omm#^s)9U}(YB
z(s>|I!^g6(DbcG?gfF;lv2DZ64&$Eh)_=9G&pVKF?Bg4S#C7wQmwn!KcX!>)sQMQM
zzuq$+JJ8W-xLU>P*p&6F^o7DtB5~IXqHy(5x$6Z`WCeG4vAOy5M5j|5)=e@_`1Q$t?~mWV|Gu?uR&1G&xBCx6fbZ7{Osno*1qL&Nr>mdK
II;Vst05AfuQUCw|
literal 0
HcmV?d00001
diff --git a/CSharp/WPFTutorial/WPF-25-TreeView/Assets/folder.png b/CSharp/WPFTutorial/WPF-25-TreeView/Assets/folder.png
new file mode 100644
index 0000000000000000000000000000000000000000..f09ddabdad175573f1f0ca36cd26adf289695410
GIT binary patch
literal 659
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9GG!XV7ZFl&wk0|S$*
zr;B4q#hkaZcIF8OinP^7$tgAIvHCk6_rCan%|nG%Xh-kI3U0wP{>TlJC)_P#T6*xe
zSbwthHbHxad_vgX&r9cCAsC)xiwE3QT8PHi_d?~-n@A8E#B>y1Wu}d;f}bqx7}l(_3zJGf&9yj
zs+Zh2_UWN4%cH_~dh?zHRa6yprZ4B2YV1Tnd
OjKR~@&t;ucLK6TO;xMWJ
literal 0
HcmV?d00001
diff --git a/CSharp/WPFTutorial/WPF-25-TreeView/Assets/jpg.png b/CSharp/WPFTutorial/WPF-25-TreeView/Assets/jpg.png
new file mode 100644
index 0000000000000000000000000000000000000000..cc38fdcbccc55adbd63585a7460f0688f1adda2a
GIT binary patch
literal 976
zcmV;>126oEP)b;R7gY
z)M%o?Lv3Qb(Q3p*g&G4i234v$`fJ+EO696&jGXR!@z$Qj7-L<9w*m}mG-xK5$0?`0~V_+VeTv0wD5Dfq@
z$5PnbHv{{FB+XGo@oW?&N8h3Na1f>KA7HvH
zv1@s;11;&0f467sUJ_k!wJ}W5@`VY0&ryZy8YQ?&bZs``;z|v%8!Roelmoj
z{Q(wJ<_@#RyrwhGVoHy^&wfv7dnl&{SZ)mG2Y|}Uu`~eBz@kO4_&^Zlr^2Z64rdFS
zwL5bRZVP0KqV;wHRX5_$AAOr&04m%O1|Zu87uf>8dh?6vYz?s98q2v>?hf-0piw!Z
z-k(6VH=b=@bq_wR7yyw03$z7bxk_Pwl!X1sXXuZ;;~zk6*9c2+p?_DL?Puru
z6$7Ba*3c{rXZ}0~RCmYu1<>?-3YHETm7XEk?u}|Ky48YR#`j&RBQo=8bC!6gy;fPv_XhDfQmr~
zViKfc6oxnpP;nT7CZ|EC20xbmTPydbIsiiP>R%_igkP!-z$v4eP<-TW^(n@;%dqIQ
yP^*OXYW`(rwN~z>Wf1E$NnS`uNJvPxcJv*>(8ss=9fZ;V0000
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-25-TreeView/MainWindow.xaml.cs b/CSharp/WPFTutorial/WPF-25-TreeView/MainWindow.xaml.cs
new file mode 100644
index 0000000..fc0382c
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-25-TreeView/MainWindow.xaml.cs
@@ -0,0 +1,100 @@
+using System.IO;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace WPF_25_TreeView;
+
+///
+/// Interaction logic for MainWindow.xaml
+///
+public partial class MainWindow
+{
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+
+ private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
+ {
+ // 初始化驱动器名称(文件夹)
+ foreach (var drive in Directory.GetLogicalDrives())
+ {
+ var treeView = new TreeViewItem
+ {
+ Header = drive, Tag = drive
+ };
+
+ treeView.Items.Add(null);
+ treeView.Expanded += FolderExpanded;
+ FolderView.Items.Add(treeView);
+ }
+ }
+
+ private static void FolderExpanded(object sender, RoutedEventArgs e)
+ {
+ var parentItem = (TreeViewItem)sender;
+
+ switch (parentItem.Items.Count)
+ {
+ // 改进的空检查逻辑
+ case 1 when parentItem.Items[0] == null:
+ parentItem.Items.Clear();
+ break;
+ case > 0:
+ return; // 已经加载过子项
+ }
+
+ var fullPath = parentItem.Tag?.ToString();
+ if (string.IsNullOrEmpty(fullPath) || !Directory.Exists(fullPath)) return;
+
+ // 添加搜索选项以包含隐藏文件夹(可选)
+ var directories = Directory.GetDirectories(fullPath, "*", SearchOption.TopDirectoryOnly);
+
+ foreach (var directoryPath in directories)
+ {
+ // 跳过无法访问的文件夹
+ if (!HasAccess(directoryPath)) continue;
+
+ var subViewItem = new TreeViewItem
+ {
+ Header = Path.GetFileName(directoryPath),
+ Tag = directoryPath
+ };
+
+ subViewItem.Items.Add(null); // 添加虚拟子项以显示展开箭头
+ subViewItem.Expanded += FolderExpanded;
+ parentItem.Items.Add(subViewItem);
+ }
+
+ // 添加文件
+ var files = Directory.GetFiles(fullPath);
+ foreach (var filePath in files)
+ {
+ var fileItem = new TreeViewItem
+ {
+ Header = Path.GetFileName(filePath),
+ Tag = filePath
+ };
+ // 文件没有子项,所以不需要添加虚拟项
+ parentItem.Items.Add(fileItem);
+ }
+ }
+
+ ///
+ /// 辅助方法检查目录访问权限
+ ///
+ /// 文件夹路径
+ ///
+ private static bool HasAccess(string folderPath)
+ {
+ try
+ {
+ Directory.GetFileSystemEntries(folderPath);
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-25-TreeView/WPF-25-TreeView.csproj b/CSharp/WPFTutorial/WPF-25-TreeView/WPF-25-TreeView.csproj
new file mode 100644
index 0000000..bac22e2
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-25-TreeView/WPF-25-TreeView.csproj
@@ -0,0 +1,39 @@
+
+
+
+ WinExe
+ net8.0-windows
+ WPF_25_TreeView
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
+ Always
+
+
+
+ Always
+
+
+
+
+
+ Always
+
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-26-MVVM/App.xaml b/CSharp/WPFTutorial/WPF-26-MVVM/App.xaml
new file mode 100644
index 0000000..5f8dcbf
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-26-MVVM/App.xaml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-26-MVVM/App.xaml.cs b/CSharp/WPFTutorial/WPF-26-MVVM/App.xaml.cs
new file mode 100644
index 0000000..e7fe641
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-26-MVVM/App.xaml.cs
@@ -0,0 +1,27 @@
+using System.Diagnostics;
+using System.Windows;
+using WPF_26_MVVM.Views;
+
+namespace WPF_26_MVVM;
+
+///
+/// Interaction logic for App.xaml
+///
+public partial class App : PrismApplication
+{
+ protected override void RegisterTypes(IContainerRegistry containerRegistry)
+ {
+ Debug.WriteLine("Registering views...");
+ // 不写名称就是默认的名称 ViewA
+ containerRegistry.RegisterForNavigation();
+ containerRegistry.RegisterForNavigation();
+ containerRegistry.RegisterForNavigation();
+ }
+
+ protected override Window CreateShell()
+ {
+ var mainView = Container.Resolve();
+ Debug.WriteLine("MainView resolved");
+ return mainView;
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-26-MVVM/AssemblyInfo.cs b/CSharp/WPFTutorial/WPF-26-MVVM/AssemblyInfo.cs
new file mode 100644
index 0000000..4a05c7d
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-26-MVVM/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-26-MVVM/ViewModels/MainViewModel.cs b/CSharp/WPFTutorial/WPF-26-MVVM/ViewModels/MainViewModel.cs
new file mode 100644
index 0000000..32e4386
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-26-MVVM/ViewModels/MainViewModel.cs
@@ -0,0 +1,20 @@
+namespace WPF_26_MVVM.ViewModels;
+
+public class MainViewModel : BindableBase
+{
+ private readonly IRegionManager _regionManager;
+
+ public MainViewModel(IRegionManager regionManager)
+ {
+ _regionManager = regionManager;
+ OpenCommand = new DelegateCommand(Open);
+ }
+
+ public DelegateCommand OpenCommand { get; private set; }
+
+ private void Open(string viewName)
+ {
+ // _regionManager.RequestNavigate("Body", viewName);
+ _regionManager.Regions["ContentRegion"].RequestNavigate(viewName);
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-26-MVVM/Views/MainView.xaml b/CSharp/WPFTutorial/WPF-26-MVVM/Views/MainView.xaml
new file mode 100644
index 0000000..16a1c91
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-26-MVVM/Views/MainView.xaml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-26-MVVM/Views/MainView.xaml.cs b/CSharp/WPFTutorial/WPF-26-MVVM/Views/MainView.xaml.cs
new file mode 100644
index 0000000..c2e0764
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-26-MVVM/Views/MainView.xaml.cs
@@ -0,0 +1,14 @@
+using System.Windows;
+
+namespace WPF_26_MVVM.Views;
+
+///
+/// Interaction logic for MainWindow.xaml
+///
+public partial class MainView : Window
+{
+ public MainView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewA.xaml b/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewA.xaml
new file mode 100644
index 0000000..2e19d45
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewA.xaml
@@ -0,0 +1,11 @@
+
+
+ AAAA
+
+
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewA.xaml.cs b/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewA.xaml.cs
new file mode 100644
index 0000000..9836a5b
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewA.xaml.cs
@@ -0,0 +1,11 @@
+using System.Windows.Controls;
+
+namespace WPF_26_MVVM.Views;
+
+public partial class ViewA : UserControl
+{
+ public ViewA()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewB.xaml b/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewB.xaml
new file mode 100644
index 0000000..0d6041b
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewB.xaml
@@ -0,0 +1,11 @@
+
+
+ BBBBBB
+
+
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewB.xaml.cs b/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewB.xaml.cs
new file mode 100644
index 0000000..65c8790
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewB.xaml.cs
@@ -0,0 +1,11 @@
+using System.Windows.Controls;
+
+namespace WPF_26_MVVM.Views;
+
+public partial class ViewB : UserControl
+{
+ public ViewB()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewC.xaml b/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewC.xaml
new file mode 100644
index 0000000..df3cd2e
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewC.xaml
@@ -0,0 +1,11 @@
+
+
+ CCCC
+
+
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewC.xaml.cs b/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewC.xaml.cs
new file mode 100644
index 0000000..df39fc2
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-26-MVVM/Views/ViewC.xaml.cs
@@ -0,0 +1,11 @@
+using System.Windows.Controls;
+
+namespace WPF_26_MVVM.Views;
+
+public partial class ViewC : UserControl
+{
+ public ViewC()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-26-MVVM/WPF-26-MVVM.csproj b/CSharp/WPFTutorial/WPF-26-MVVM/WPF-26-MVVM.csproj
new file mode 100644
index 0000000..5d2fb44
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-26-MVVM/WPF-26-MVVM.csproj
@@ -0,0 +1,29 @@
+
+
+
+ WinExe
+ net8.0-windows
+ WPF_26_MVVM
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MSBuild:Compile
+ Wpf
+ Designer
+
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/App.xaml b/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/App.xaml
new file mode 100644
index 0000000..ab8e57a
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/App.xaml.cs b/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/App.xaml.cs
new file mode 100644
index 0000000..a6dab3c
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/App.xaml.cs
@@ -0,0 +1,12 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace WPF_3_Grid_BasicResponsiveLayouts;
+
+///
+/// Interaction logic for App.xaml
+///
+public partial class App : Application
+{
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/AssemblyInfo.cs b/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/AssemblyInfo.cs
new file mode 100644
index 0000000..4a05c7d
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/MainWindow.xaml b/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/MainWindow.xaml
new file mode 100644
index 0000000..a3b9709
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/MainWindow.xaml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/MainWindow.xaml.cs b/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/MainWindow.xaml.cs
new file mode 100644
index 0000000..350e467
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/MainWindow.xaml.cs
@@ -0,0 +1,23 @@
+using System.Text;
+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.Navigation;
+using System.Windows.Shapes;
+
+namespace WPF_3_Grid_BasicResponsiveLayouts;
+
+///
+/// Interaction logic for MainWindow.xaml
+///
+public partial class MainWindow : Window
+{
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/WPF-3-Grid-BasicResponsiveLayouts.csproj b/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/WPF-3-Grid-BasicResponsiveLayouts.csproj
new file mode 100644
index 0000000..3311f8c
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Grid-BasicResponsiveLayouts/WPF-3-Grid-BasicResponsiveLayouts.csproj
@@ -0,0 +1,12 @@
+
+
+
+ WinExe
+ net8.0-windows
+ WPF_3_Grid_BasicResponsiveLayouts
+ enable
+ enable
+ true
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-3-Grid-Layout/App.xaml b/CSharp/WPFTutorial/WPF-3-Grid-Layout/App.xaml
new file mode 100644
index 0000000..abf6887
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Grid-Layout/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-3-Grid-Layout/App.xaml.cs b/CSharp/WPFTutorial/WPF-3-Grid-Layout/App.xaml.cs
new file mode 100644
index 0000000..b1de883
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Grid-Layout/App.xaml.cs
@@ -0,0 +1,12 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace WPF_3_Grid_Layout;
+
+///
+/// Interaction logic for App.xaml
+///
+public partial class App : Application
+{
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-Grid-Layout/AssemblyInfo.cs b/CSharp/WPFTutorial/WPF-3-Grid-Layout/AssemblyInfo.cs
new file mode 100644
index 0000000..4a05c7d
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Grid-Layout/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-Grid-Layout/MainWindow.xaml b/CSharp/WPFTutorial/WPF-3-Grid-Layout/MainWindow.xaml
new file mode 100644
index 0000000..d48da59
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Grid-Layout/MainWindow.xaml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-Grid-Layout/MainWindow.xaml.cs b/CSharp/WPFTutorial/WPF-3-Grid-Layout/MainWindow.xaml.cs
new file mode 100644
index 0000000..73d9f2e
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Grid-Layout/MainWindow.xaml.cs
@@ -0,0 +1,23 @@
+using System.Text;
+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.Navigation;
+using System.Windows.Shapes;
+
+namespace WPF_3_Grid_Layout;
+
+///
+/// Interaction logic for MainWindow.xaml
+///
+public partial class MainWindow : Window
+{
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-Grid-Layout/WPF-3-Grid-Layout.csproj b/CSharp/WPFTutorial/WPF-3-Grid-Layout/WPF-3-Grid-Layout.csproj
new file mode 100644
index 0000000..0ac0a16
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Grid-Layout/WPF-3-Grid-Layout.csproj
@@ -0,0 +1,12 @@
+
+
+
+ WinExe
+ net8.0-windows
+ WPF_3_Grid_Layout
+ enable
+ enable
+ true
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-3-GridSPan/App.xaml b/CSharp/WPFTutorial/WPF-3-GridSPan/App.xaml
new file mode 100644
index 0000000..02996ca
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-GridSPan/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-3-GridSPan/App.xaml.cs b/CSharp/WPFTutorial/WPF-3-GridSPan/App.xaml.cs
new file mode 100644
index 0000000..1f9dbe1
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-GridSPan/App.xaml.cs
@@ -0,0 +1,12 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace WPF_3_GridSPan;
+
+///
+/// Interaction logic for App.xaml
+///
+public partial class App : Application
+{
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-GridSPan/AssemblyInfo.cs b/CSharp/WPFTutorial/WPF-3-GridSPan/AssemblyInfo.cs
new file mode 100644
index 0000000..4a05c7d
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-GridSPan/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-GridSPan/MainWindow.xaml b/CSharp/WPFTutorial/WPF-3-GridSPan/MainWindow.xaml
new file mode 100644
index 0000000..4b2c267
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-GridSPan/MainWindow.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-GridSPan/MainWindow.xaml.cs b/CSharp/WPFTutorial/WPF-3-GridSPan/MainWindow.xaml.cs
new file mode 100644
index 0000000..503bc52
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-GridSPan/MainWindow.xaml.cs
@@ -0,0 +1,23 @@
+using System.Text;
+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.Navigation;
+using System.Windows.Shapes;
+
+namespace WPF_3_GridSPan;
+
+///
+/// Interaction logic for MainWindow.xaml
+///
+public partial class MainWindow : Window
+{
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-GridSPan/WPF-3-GridSPan.csproj b/CSharp/WPFTutorial/WPF-3-GridSPan/WPF-3-GridSPan.csproj
new file mode 100644
index 0000000..c676fb0
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-GridSPan/WPF-3-GridSPan.csproj
@@ -0,0 +1,12 @@
+
+
+
+ WinExe
+ net8.0-windows
+ WPF_3_GridSPan
+ enable
+ enable
+ true
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-3-Sample/App.xaml b/CSharp/WPFTutorial/WPF-3-Sample/App.xaml
new file mode 100644
index 0000000..6d6a056
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Sample/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-3-Sample/App.xaml.cs b/CSharp/WPFTutorial/WPF-3-Sample/App.xaml.cs
new file mode 100644
index 0000000..c28d00b
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Sample/App.xaml.cs
@@ -0,0 +1,12 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace WPF_3_Sample;
+
+///
+/// Interaction logic for App.xaml
+///
+public partial class App : Application
+{
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-Sample/AssemblyInfo.cs b/CSharp/WPFTutorial/WPF-3-Sample/AssemblyInfo.cs
new file mode 100644
index 0000000..4a05c7d
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Sample/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-Sample/MainWindow.xaml b/CSharp/WPFTutorial/WPF-3-Sample/MainWindow.xaml
new file mode 100644
index 0000000..8e2fe78
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Sample/MainWindow.xaml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-Sample/MainWindow.xaml.cs b/CSharp/WPFTutorial/WPF-3-Sample/MainWindow.xaml.cs
new file mode 100644
index 0000000..3c55290
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Sample/MainWindow.xaml.cs
@@ -0,0 +1,23 @@
+using System.Text;
+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.Navigation;
+using System.Windows.Shapes;
+
+namespace WPF_3_Sample;
+
+///
+/// Interaction logic for MainWindow.xaml
+///
+public partial class MainWindow : Window
+{
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-3-Sample/WPF-3-Sample.csproj b/CSharp/WPFTutorial/WPF-3-Sample/WPF-3-Sample.csproj
new file mode 100644
index 0000000..0b2f272
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-3-Sample/WPF-3-Sample.csproj
@@ -0,0 +1,12 @@
+
+
+
+ WinExe
+ net8.0-windows
+ WPF_3_Sample
+ enable
+ enable
+ true
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/App.xaml b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/App.xaml
new file mode 100644
index 0000000..4091b0d
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/App.xaml.cs b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/App.xaml.cs
new file mode 100644
index 0000000..384608e
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/App.xaml.cs
@@ -0,0 +1,12 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace WPF_4_Custom_User_Controls;
+
+///
+/// Interaction logic for App.xaml
+///
+public partial class App : Application
+{
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/AssemblyInfo.cs b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/AssemblyInfo.cs
new file mode 100644
index 0000000..4a05c7d
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/MainWindow.xaml b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/MainWindow.xaml
new file mode 100644
index 0000000..6ebe23c
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/MainWindow.xaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/MainWindow.xaml.cs b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/MainWindow.xaml.cs
new file mode 100644
index 0000000..5310550
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/MainWindow.xaml.cs
@@ -0,0 +1,23 @@
+using System.Text;
+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.Navigation;
+using System.Windows.Shapes;
+
+namespace WPF_4_Custom_User_Controls;
+
+///
+/// Interaction logic for MainWindow.xaml
+///
+public partial class MainWindow : Window
+{
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/View/UserController/MenuBar.xaml b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/View/UserController/MenuBar.xaml
new file mode 100644
index 0000000..f1c025d
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/View/UserController/MenuBar.xaml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/View/UserController/MenuBar.xaml.cs b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/View/UserController/MenuBar.xaml.cs
new file mode 100644
index 0000000..0664a07
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/View/UserController/MenuBar.xaml.cs
@@ -0,0 +1,11 @@
+using System.Windows.Controls;
+
+namespace WPF_4_Custom_User_Controls.View.UserController;
+
+public partial class MenuBar : UserControl
+{
+ public MenuBar()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/WPF-4-Custom-User-Controls.csproj b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/WPF-4-Custom-User-Controls.csproj
new file mode 100644
index 0000000..45a4fc8
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-Custom-User-Controls/WPF-4-Custom-User-Controls.csproj
@@ -0,0 +1,12 @@
+
+
+
+ WinExe
+ net8.0-windows
+ WPF_4_Custom_User_Controls
+ enable
+ enable
+ true
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-4-DockPanel/App.xaml b/CSharp/WPFTutorial/WPF-4-DockPanel/App.xaml
new file mode 100644
index 0000000..f7360ce
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-DockPanel/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-4-DockPanel/App.xaml.cs b/CSharp/WPFTutorial/WPF-4-DockPanel/App.xaml.cs
new file mode 100644
index 0000000..e127369
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-DockPanel/App.xaml.cs
@@ -0,0 +1,12 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace WPF_4_DockPanel;
+
+///
+/// Interaction logic for App.xaml
+///
+public partial class App : Application
+{
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-4-DockPanel/AssemblyInfo.cs b/CSharp/WPFTutorial/WPF-4-DockPanel/AssemblyInfo.cs
new file mode 100644
index 0000000..4a05c7d
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-DockPanel/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-4-DockPanel/MainWindow.xaml b/CSharp/WPFTutorial/WPF-4-DockPanel/MainWindow.xaml
new file mode 100644
index 0000000..3834181
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-DockPanel/MainWindow.xaml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-4-DockPanel/MainWindow.xaml.cs b/CSharp/WPFTutorial/WPF-4-DockPanel/MainWindow.xaml.cs
new file mode 100644
index 0000000..4ee149f
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-DockPanel/MainWindow.xaml.cs
@@ -0,0 +1,23 @@
+using System.Text;
+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.Navigation;
+using System.Windows.Shapes;
+
+namespace WPF_4_DockPanel;
+
+///
+/// Interaction logic for MainWindow.xaml
+///
+public partial class MainWindow : Window
+{
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-4-DockPanel/WPF-4-DockPanel.csproj b/CSharp/WPFTutorial/WPF-4-DockPanel/WPF-4-DockPanel.csproj
new file mode 100644
index 0000000..bf11f35
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-DockPanel/WPF-4-DockPanel.csproj
@@ -0,0 +1,12 @@
+
+
+
+ WinExe
+ net8.0-windows
+ WPF_4_DockPanel
+ enable
+ enable
+ true
+
+
+
diff --git a/CSharp/WPFTutorial/WPF-4-Prism/App.xaml b/CSharp/WPFTutorial/WPF-4-Prism/App.xaml
new file mode 100644
index 0000000..725c9dd
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-Prism/App.xaml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-4-Prism/App.xaml.cs b/CSharp/WPFTutorial/WPF-4-Prism/App.xaml.cs
new file mode 100644
index 0000000..5a1d7b9
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-Prism/App.xaml.cs
@@ -0,0 +1,18 @@
+using System.Windows;
+
+namespace WPF_4_Prism;
+
+///
+/// Interaction logic for App.xaml
+///
+public partial class App : PrismApplication
+{
+ protected override void RegisterTypes(IContainerRegistry containerRegistry)
+ {
+ }
+
+ protected override Window CreateShell()
+ {
+ return Container.Resolve();
+ }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-4-Prism/AssemblyInfo.cs b/CSharp/WPFTutorial/WPF-4-Prism/AssemblyInfo.cs
new file mode 100644
index 0000000..4a05c7d
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-Prism/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-4-Prism/Common/Model/MenuBar.cs b/CSharp/WPFTutorial/WPF-4-Prism/Common/Model/MenuBar.cs
new file mode 100644
index 0000000..56f6a8f
--- /dev/null
+++ b/CSharp/WPFTutorial/WPF-4-Prism/Common/Model/MenuBar.cs
@@ -0,0 +1,13 @@
+namespace WPF_4_Prism.Common.Model;
+
+///
+/// 系统导航栏菜单实体类
+///
+public class MenuBar : BindableBase
+{
+ public string Icon { get; set; }
+
+ public string Title { get; set; }
+
+ public string Namespace { get; set; }
+}
\ No newline at end of file
diff --git a/CSharp/WPFTutorial/WPF-4-Prism/Images/Avatar.jpg b/CSharp/WPFTutorial/WPF-4-Prism/Images/Avatar.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..a899a73a744962c4948eab3e2cede3fb3ccf68e8
GIT binary patch
literal 6923
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