Visual Studio is an integrated development environment (IDE) developed by Microsoft that supports multiple programming languages such as C++, C#, VB.NET, Python, JavaScript, etc. Suitable for developing desktop applications, websites, cloud services and mobile applications.
Visual Studio supports Windows operating systems, and Visual Studio for Mac is designed for macOS.
[*.cs] indent_style = space indent_size = 43. After the file is saved, the formatting will automatically follow these rules.
You can check the .NET SDK version installed on your computer via the command line tool:
dotnet --list-sdks
If a result similar to the following appears, it indicates the installed SDK version:
8.0.100 [C:\Program Files\dotnet\sdk] 9.0.100-preview.3.24172.9 [C:\Program Files\dotnet\sdk]
If the version you want to use does not appear, it means that it is not installed yet.
dotnetOrderIf you don't see this option, you can also use the Windows Start menu to search for "Developer Command Prompt for VS" to open it.
Ctrl + `dotnetCommand to check or operate SDKusing System;
class Program {
static void Main() {
string name = "world";
Console.WriteLine($"Hello, {name}!");
}
}
(x, y) => x + yvar q = list.Where(x => x > 10);await Task.Delay(1000);CS8618 means: at the end of the constructor,Not Nullable's properties are not initialized, so the C# compiler warns that it might benull。
public class Product {
public string Name { get; set; } // Warning CS8618
}
public class Product {
public string Name { get; set; }
public Product(string name) {
Name = name;
}
}
public class Product {
public string Name { get; set; } = string.Empty;
}
public class Product {
public string? Name { get; set; }
}
→ Applicable toNamereasonably allowed to benullsituation.
requiredModifiers (supported by C# 11+)public class Product {
public required string Name { get; set; }
}
// The caller must be initialized
var p = new Product { Name = "Mobile phone" }; // OK
null:useConstructororrequired。null:Change tostring?。string.Empty)。floatandSystem::StringAdd together, for example:
System::String^ tmpStr = "Value: " + someFloat;
whensomeFloatWhen very large or very small, it may be automatically displayed in scientific notation (e.g. 1.23E+05).System::String::FormatorToStringUse a format string to specify the number of decimal places and avoid scientific notation.using namespace System;
float value = 123456.789f;
// Method 1: String::Format
String^ tmpStr1 = String::Format("Value: {0:F2}", value); // F2 represents 2 digits after the decimal point
Console::WriteLine(tmpStr1);
// Method 2: ToString matching format
String^ tmpStr2 = "Value: " + value.ToString("F2");
Console::WriteLine(tmpStr2);
//Method 3: More digits
String^ tmpStr3 = "Value: " + value.ToString("F6");
Console::WriteLine(tmpStr3);
F2: Fixed decimal point format, 2 digits after the decimal pointF6: Fixed decimal point format, 6 digits after the decimal pointF{digits}In .NET C++, you can useSystem::IONamespaces provide functions for manipulating files and directories.
Obtaining the latest files in the directory can be achieved by reading all file information and comparing the last modification date.
Here is a complete example showing how to get the latest file in a specified directory:
#include "stdafx.h"
#include <iostream>
#include <cliext/vector>
#include <System.IO>
using namespace System;
using namespace System::IO;
using namespace cliext;
int main()
{
try
{
//Specify directory path
String^ directoryPath = "C:\\Your\\Directory\\Path";
// Check if the directory exists
if (!Directory::Exists(directoryPath))
{
Console::WriteLine("Directory does not exist: {0}", directoryPath);
return -1;
}
// Get all files in the directory
array^ files = Directory::GetFiles(directoryPath);
// If there are no files in the directory
if (files->Length == 0)
{
Console::WriteLine("There is no file in the directory.");
return 0;
}
// Find the latest file
String^ newestFile = nullptr;
DateTime newestTime = DateTime::MinValue;
for each (String^ file in files)
{
// Get the last modification time of the file
DateTime lastWriteTime = File::GetLastWriteTime(file);
// Compare time and update latest file information
if (lastWriteTime > newestTime)
{
newestTime = lastWriteTime;
newestFile = file;
}
}
// Output the latest file information
Console::WriteLine("Latest file: {0}", newestFile);
Console::WriteLine("Last modified time: {0}", newestTime);
}
catch (Exception^ ex)
{
Console::WriteLine("An error occurred: {0}", ex->Message);
}
return 0;
}
Directory::GetFilesMethod to get all archive paths in the specified directory.File::GetLastWriteTimeMethod to get the last modification time of each file.try-catchThe block catches potential exceptions, such as a directory that does not exist or is inaccessible.System.ReflectionIt is a namespace in the .NET framework that provides tools for inspecting and manipulating metadata, allowing developers to dynamically inspect types, methods, properties, etc. at runtime, and dynamically create and manipulate objects.
Assembly: Represents a loaded assembly and provides methods for loading, exploring, and reflecting assemblies.Type: Represents a type, including categories, structures, interfaces, etc., and provides the function of obtaining type information.MethodInfo: Represents method information, allowing developers to inspect method properties and call them dynamically.PropertyInfo: Represents attribute information and provides access to attribute metadata.FieldInfo: Represents field information and can be used to access fields of type.The following is a useSystem.ReflectionA sample program that shows how to dynamically check types and methods and call methods.
//Define a simple example class
public class SampleClass {
public string SayHello(string name) {
return $"Hello, {name}!";
}
}
// Use Reflection to dynamically call methods
using System;
using System.Reflection;
class Program {
static void Main() {
//Create an instance of the SampleClass class
Type sampleType = typeof(SampleClass);
object sampleInstance = Activator.CreateInstance(sampleType);
// Get SayHello method information
MethodInfo methodInfo = sampleType.GetMethod("SayHello");
// Dynamically call the SayHello method
object result = methodInfo.Invoke(sampleInstance, new object[] { "World" });
Console.WriteLine(result); // Output: Hello, World!
}
}
In the above example, we useActivator.CreateInstanceto create an instance of the category and useMethodInfo.Invoketo call methodSayHello。
System::Management::ManagementClassIs one of the classes in the .NET Framework that provides for working with Windows Management Instrumentation (WMI). It allows developers to read, manipulate and manage system information, such as hardware, operating system, network settings, etc.
System::Managementis locatedSystem.Management.dllIn the namespace, you need to add a reference before using this function.
// C++/CLI writing method
using namespace System;
using namespace System::Management;
int main() {
try {
ManagementClass^ mc = gcnew ManagementClass("Win32_OperatingSystem");
for each (ManagementObject^ mo in mc->GetInstances()) {
Console::WriteLine("OS Name: {0}", mo["Caption"]);
}
}
catch (Exception^ ex) {
Console::WriteLine("Error: {0}", ex->Message);
}
return 0;
}
System.Management.dllreference.ManagementException。ManagementObjectManagementObjectSearcherManagementBaseObjectnet stop winmgmt winmgmt /resetrepository net start winmgmt
Get-WmiObject Win32_NetworkAdapterConfigurationMethod 2: WMI test tool (wbemtest)
wbemtestroot\cimv2and connectSELECT * FROM Win32_NetworkAdapterConfigurationDISM /Online /Cleanup-Image /RestoreHealthRepair system imageMost modern Chromebooks support running Linux applications through the Crostini project.
Settings > Advanced > Developer > Enable Linux (Beta)。sudo apt update
sudo apt install -y dotnet-sdk-7.0
You can use the cloud platform to run .NET programs on your Chromebook without installing any software locally.
Chromebooks support the use of containers to run applications, and you can start a .NET environment through Docker.
docker pull mcr.microsoft.com/dotnet/runtime:7.0
Starting with .NET 6, applications can run across multiple platforms, including Linux. Compile your app into a cross-platform format and deploy to Chromebooks.
dotnet publish -c Release -r linux-x64 --self-contained
using System;
using System.Windows.Forms;
public class MyForm : Form {
public MyForm() {
Button btn = new Button();
btn.Text = "Click me";
btn.Click += (s, e) => MessageBox.Show("You clicked the button!");
Controls.Add(btn);
}
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.Run(new MyForm());
}
}
// MainWindow.xaml
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="WPF Example" Height="200" Width="300">
<StackPanel>
<Button Content="Click me" Click="Button_Click"/>
</StackPanel>
</Window>
// MainWindow.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e) {
MessageBox.Show("You clicked the button!");
}
// MainPage.xaml
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
x:Class="MyApp.MainPage">
<VerticalStackLayout Spacing="25" Padding="30">
<Button Text="Click me" Clicked="OnButtonClicked"/>
</VerticalStackLayout>
</ContentPage>
// MainPage.xaml.cs
private void OnButtonClicked(object sender, EventArgs e) {
await DisplayAlert("Notification", "You clicked the button!", "OK");
}
| technology | use | platform |
|---|---|---|
| WinForms | Rapidly develop desktop applications | Windows |
| WPF | Complex desktop applications, MVVM pattern | Windows |
| MAUI | Cross-platform application | Windows、macOS、Android、iOS |
| Blazor | Web front-end development | Cross-platform (Web) |
The following examples show how to useControls->GetEnumerator()Method to iterate through all child controls in a .NET form one by one and modify their properties in batches.
using System;
using System.Drawing;
using System.Windows.Forms;
public class FormExample : Form
{
public FormExample()
{
//Initialize some controls
Button button1 = new Button { Text = "Button 1", Location = new Point(10, 10) };
TextBox textBox1 = new TextBox { Location = new Point(10, 50) };
Controls.Add(button1);
Controls.Add(textBox1);
// Use GetEnumerator() to traverse and modify the control properties
ModifyControls();
}
private void ModifyControls()
{
var enumerator = Controls.GetEnumerator();
while (enumerator.MoveNext())
{
Control control = (Control)enumerator.Current;
// Setting example: Set the background color of all controls to light blue
control.BackColor = Color.LightBlue;
// If the control item is a TextBox, make it non-editable
if (control is TextBox)
{
control.Enabled = false;
}
}
}
//Start the application
public static void Main()
{
Application.Run(new FormExample());
}
}
**GetEnumerator()**: Use the `Controls.GetEnumerator()` method to get the enumerator of the control item, so that all child controls can be traversed.
**Conditional modification**: In the `while` loop, modify the properties of each `Control` object, such as setting the background color to light blue, and make specific modifications based on the control type, such as setting the `TextBox` to non-editable.
**Use**: This method is very effective when you need to modify properties in batches, such as adjusting UI style or disabling multiple controls under specific circumstances.
After execution, the background color of all controls will change to light blue, and all `TextBox` controls will be set to non-editable.
When the following error message appears in the stack trace, developers may need to checkMessageThe contents of the object:
at ....MainForm.Dispose(Boolean A_0)
at System.Windows.Forms.Form.WmClose(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
...
At this time, it is necessary to overwrite or detectWndProcin methodMessage mto check its details.
Here are several ways to check or recordMessageThe contents of the object.
If you have access to the source code of the form or control, it is recommended to overwriteWndProcmethod, directly record or checkMessage mcontent.
protected override void WndProc(ref Message m)
{
try
{
//Record the content of Message
Console.WriteLine($"Message Details: hWnd={m.HWnd}, Msg={m.Msg}, WParam={m.WParam}, LParam={m.LParam}");
base.WndProc(ref m);
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex}");
throw; // Keep the original exception behavior
}
}
This code will log relevant information each time a message is received and allow the developer to analyze it further.
If the error occurs inDisposeIn the method, you can add exception handling within the method to check relevant information.
protected override void Dispose(bool disposing)
{
try
{
if (disposing)
{
// Release resources
}
base.Dispose(disposing);
}
catch (Exception ex)
{
Console.WriteLine($"Exception in Dispose: {ex}");
throw;
}
}
This ensures that important error information is not ignored when releasing resources.
If you cannot determine where the error occurred, you can use global exception handling to record stack traces and related information.
AppDomain.CurrentDomain.UnhandledException += (sender, args) =>
{
Exception ex = (Exception)args.ExceptionObject;
Console.WriteLine($"Unhandled Exception: {ex}");
Environment.Exit(1);
};
You can use Visual Studio to set breakpoints atWndProcorDisposemethod and checkMessageThe contents of the object.
HWnd: The handle of the window that receives the message.Msg: ID of the message.WParam: Additional message information (word parameter).LParam: Additional message information (long parameter).WndProcOr be careful when modifying the code to avoid affecting existing behavior.MessageThe coordinates or ID are not fixed, you can consider adding conditional judgment to filter the required information.In .NET C++/CLI,WmClose(Message& m)yesSystem.Windows.Forms.FormThe internal protection method cannot be directly overwritten. However, it is possible to overrideWndProcmethod to intercept and processWM_CLOSEmessage to achieve a similar overrideWmCloseeffect.
#include <Windows.h>
#include <System.Windows.Forms.h>
using namespace System;
using namespace System::Windows::Forms;
public ref class CustomForm : public Form
{
protected:
// Simulate override of WmClose behavior
void WmClose(Message% m)
{
//Add custom WM_CLOSE behavior here
if (MessageBox::Show("Are you sure you want to close the window?", "Confirm", MessageBoxButtons::YesNo) == DialogResult::Yes)
{
// Continue calling the base behavior for graceful shutdown
this->Form::WndProc(m);
}
else
{
// Prevent window from closing
return;
}
}
// Override WndProc, intercept the WM_CLOSE message and call WmClose
virtual void WndProc(Message% m) override
{
const int WM_CLOSE = 0x0010;
if (m.Msg == WM_CLOSE)
{
WmClose(m); // Call the custom WmClose method
}
else
{
// Process other messages
Form::WndProc(m);
}
}
};
[STAThread]
int main(array<String^>^ args)
{
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
CustomForm^ form = gcnew CustomForm();
form->Text = "Override WmClose behavior example";
Application::Run(form);
return 0;
}
simulate overwriteWmCloseMethod to customize the window closing behavior here. Use a confirmation dialog box to ask the user if they want to close the window.
overwriteWndProcmethod to interceptWM_CLOSEmessage and delegate it to a customWmClosemethod.
without interceptionWM_CLOSEIn the case of calling the base classWndProcMethod to handle other messages.
WmCloseThe method only simulates overwriting, but actually processes the message by intercepting it.Form::WndProcto ensure that the base behavior is functioning properly.InvokeRequiredyesSystem::Windows::Forms::ControlThe attribute is used to determine whether the current execution thread is the UI execution thread to which the control item belongs. When accessing UI controls from a background thread, you should useInvokeMarshal the operation back to the UI thread.using namespace System;
using namespace System::Windows::Forms;
using namespace System::Drawing;
ref class ImageHelper {
public:
static void SetImageSafe(PictureBox^ pPictureBox, Bitmap^ b) {
if (pPictureBox == nullptr)
return;
if (pPictureBox->InvokeRequired) {
// Use MethodInvoker to call the same function, but execute it in the UI thread
pPictureBox->Invoke(
gcnew MethodInvoker(gcnew Action
InvokeRequiredCan only be used for inheritanceControlObject (such as PictureBox).true, which means that the current execution thread is not the UI execution thread and must be usedInvoke。TupleEncapsulate multiple parameters and pass them into the static proxy function for processing.try-catchCatching exceptions avoids program crashes.
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Drawing;
void SetImageSafe(PictureBox^ pPictureBox, Bitmap^ b) {
if (pPictureBox->InvokeRequired) {
pPictureBox->Invoke(gcnew MethodInvoker(
gcnew EventHandler(nullptr, &SetImageInvoker)
), gcnew array
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Drawing;
void SafeAssignImage(PictureBox^ pPictureBox, Bitmap^ b) {
if (pPictureBox->InvokeRequired) {
pPictureBox->Invoke(gcnew MethodInvoker(gcnew delegate {
try {
if (b != nullptr) {
if (pPictureBox->Image != nullptr)
delete pPictureBox->Image;
pPictureBox->Image = b;
}
} catch (System::Exception^ ex) {
Console::WriteLine("Failed to set image: " + ex->Message);
}
}));
} else {
try {
if (b != nullptr) {
if (pPictureBox->Image != nullptr)
delete pPictureBox->Image;
pPictureBox->Image = b;
}
} catch (System::Exception^ ex) {
Console::WriteLine("Failed to set image: " + ex->Message);
}
}
}
gcnew MethodInvoker(...)Must be a legal delegation, C++11 lambda (such as [=]()) syntax is not supported.BeginInvokematchObject^Array and parse.Blazor is a front-end framework launched by Microsoft that allows developers to use C# and Razor syntax to create interactive web applications. C# code can be executed in the browser without using JavaScript.
Blazor seamlessly integrates ASP.NET Core, can be combined with existing .NET applications, and supports dependency injection, routing, component architecture and other functions.
For developers whose main technology is .NET, Blazor provides a solution corresponding to the unified JavaScript language of Node.js, allowing both the front and back ends to use C#, creating a more consistent development experience.
.NET MAUI (Multi-platform App UI) is a cross-platform application framework launched by Microsoft. You can use C# and XAML to write once code and deploy it to Windows, Android, iOS and even macOS.
Blazor Hybrid mode of .NET MAUI can be used to embed Web UI in native applications, allowing developers to use Razor components to develop cross-platform user interfaces while still accessing native APIs.
.NET MAUI is currently the most complete .NET cross-platform solution. It can be combined with Blazor to achieve unified application development for web, desktop and mobile platforms, providing .NET developers with a full-end experience that is consistent in language and technology.
.NET MAUI can be integrated with the back-end services created by ASP.NET Core through API calls to form a complete "front-end App + back-end API" architecture.
ASP.NET Core solves the problems of "back-end services" and "Web applications", while .NET MAUI focuses on "client-side cross-platform apps". The two are not mutually exclusive, but are often used together to form a complete solution.
Below is an example of a cross-platform application built using .NET MAUI that displays a button on the screen that updates the text count when clicked.
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiApp.MainPage">
<VerticalStackLayout Spacing="25" Padding="30">
<Label x:Name="counterLabel"
Text="You haven't clicked the button yet"
FontSize="24"
HorizontalOptions="Center" />
<Button Text="Click me"
Clicked="OnCounterClicked"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ContentPage>
namespaceMauiApp;
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
}
private void OnCounterClicked(object sender, EventArgs e)
{
count++;
counterLabel.Text = $"You have clicked {count} times";
}
}
This simple example demonstrates the cross-platform capabilities of .NET MAUI. Developers only need to write XAML and C# code once to run it on multiple platforms at the same time.
MainPage.xaml: Define UI interface (using XAML)MainPage.xaml.cs: Backend code (C#) handles eventsMauiProgram.cs: Application startup and service registration pointPlatformsFolders: Native settings for each platform (Android, iOS, Windows, MacCatalyst)It only takes a few steps to create a .NET MAUI project using Visual Studio, and one set of code can be deployed to multiple platforms at the same time, making it an ideal choice for modern C# full-end developers.
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyMauiApp.MainPage">
<VerticalStackLayout Spacing="25" Padding="30"
VerticalOptions="Center">
<Label
Text="Welcome to .NET MAUI!"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center" />
<Button
x:Name="counterBtn"
Text="Click me!"
Clicked="OnCounterClicked"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ContentPage>
using System;
namespace MyMauiApp;
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
}
private void OnCounterClicked(object sender, EventArgs e)
{
count++;
counterBtn.Text = $"You have clicked {count} times";
}
}
Spacing(spacing) andPadding(inner distance).x:Namefor access by the C# backend,ClickedThe attribute specifies the click event handling method.InitializeComponent(): Initialize the UI structure defined in XAML.OnCounterClicked: Click event processing method, update the button text every time the button is clicked.counterBtn.Text: Control the properties of the button through the name specified in XAML.After execution, a welcome message and a button will be displayed in the center of the screen. Each time you click the button, the text on the button will update to "You have clicked X times."
using Microsoft.Extensions.Logging;
namespace MyMauiApp;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp() //Specify the entry point of the application
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
}
}
MauiAppExample.App.xaml.csApp category), this will be the root component of the application.builder.Services.AddSingleton<MainPage>();This allows MainPage to be loaded using dependency injection, for example in the App class
serviceProvider.GetService<MainPage>()。
builder.Services.AddTransient<MyViewModel>();
builder.Services.AddSingleton<IMyService, MyService>();
MauiProgram.csJust like ASP.NET Core'sStartup.csorProgram.cs, is the main setting center for application startup and service registration. When developing large MAUI applications, it is very common to extend this file to add DI, logging, component settings, etc.
email: [email protected]