1.wpf笔记

1.ui线程和后台线程

**class Program
{
    static async Task Main()
    {
        Console.WriteLine("开始执行异步计算任务...");
        int result = await PerformCalculationAsync();
        Console.WriteLine($"计算结果是: {result}");
        Console.WriteLine("异步计算任务执行完毕。");
    }
    static async Task<int> PerformCalculationAsync()
    {
        return await Task.Run(() =>
        {
            // 模拟耗时计算
            int sum = 0;
            for (int i = 0; i < 1000000; i++)
            {
                sum += i;
            }
            return sum;
        });
    }
}**

大前提:主线程是程序启动时自动创建的第一个线程,
它是程序执行的入口点。
在 C# 控制台应用程序里,Main 方法就是在主线程中执行的;
在 Windows 窗体应用程序或者 WPF 应用程序中,主线程负责处理用户界面的渲染和交互。

对以上代码解释:主线程创建后 执行main函数 看到第一个await 主线程暂停执行main 等待PerformCalculationAsync 方法返回结果 这时候
主线程可以去执行其他的任务
在 Main 方法中:await 用于暂停 Main 方法的执行,等待 PerformCalculationAsync 方法返回结果。
这确保了在获取到异步计算的结果之前,Main 方法不会继续执行输出结果等后续操作,
保证了程序逻辑的正确性和顺序性。如果没有这个 await,
Main 方法会继续执行,可能在 PerformCalculationAsync 还未完成计算时就尝试输出结果,
得到的将是不正确或未完成的结果。
在 PerformCalculationAsync 方法中:await 用于暂停 PerformCalculationAsync 方法的执行,
等待 Task.Run 启动的异步计算任务完成。它使得该方法能够异步地获取计算结果,
避免了在当前线程(这里虽然不是主线程,但如果没有 await,也会影响方法执行流程)
上阻塞等待计算完成,从而提高了代码的异步性和效率。如果没有这个 await,
方法可能会在计算任务还未完成时就继续执行后续代码(如果有后续代码的话),
导致无法正确获取计算结果。

2. _dispatcher = unityContainer.Resolve()

using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;
using Unity;
using Zhaoxi.Controls;
using Zhaoxi.SmartParking.Client.Common;
using Zhaoxi.SmartParking.Client.Entity;
using Zhaoxi.SmartParking.Client.IBLL;
using Zhaoxi.SmartParking.Client.Models;
namespace Zhaoxi.SmartParking.Client.AutoModule.ViewModels
{
    public class AutoRegisterViewModel : PageViewModelBase
    {
        public PaginationModel PaginationModel { get; set; } = new PaginationModel();
        public ObservableCollection<AutoInfoModel> AutoList { get; set; } = new ObservableCollection<AutoInfoModel>();
        Dispatcher _dispatcher;
        IAutoRegisterBLL _autoRegisterBLL;
        public AutoRegisterViewModel(
            IRegionManager regionManager,
            IUnityContainer unityContainer,
            IEventAggregator ea,
            IAutoRegisterBLL autoRegisterBLL
            )
            : base(regionManager, unityContainer, ea)
        {
            this.PageTitle = "车辆登记管理";
            _dispatcher = unityContainer.Resolve<Dispatcher>();
            _autoRegisterBLL = autoRegisterBLL;
            // 中间的页码点击
            // 向前向后 也会触发
            PaginationModel.NavCommand = new DelegateCommand<object>(obj =>
            {
                Index = int.Parse(obj.ToString());
                this.Refresh();
            });
            // 改变每页条目数
            PaginationModel.CountPerPageChangeCommand = new DelegateCommand(() =>
            {
                this.Refresh();
            });
        }
        private int Index = 1;
        public override void Refresh()
        {
            this.ShowLoading();
            AutoList.Clear();
            ///回调  Thread   C#  
            Task.Run(async () =>
            {
                var result =await _autoRegisterBLL.GetAll(Index, PaginationModel.CountPerPage);
                if (result.State == 1)
                {
                    var datas = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AutoRegisterEntity>>(result.Data);
                    _dispatcher.Invoke(() =>
                    {
                        // 填充车辆信息
                        for (int i = 0; i < datas.Count; i++)
                        {
                            AutoList.Add(new AutoInfoModel
                            {
                                Num = (Index - 1) * PaginationModel.CountPerPage + i + 1,
                                AutoLicense = datas[i].AutoLicense,
                                LColorId = datas[i].LColorId,
                                LColorName = datas[i].LColorName,
                                AColorId = datas[i].AColorId,
                                AColorName = datas[i].AColorName,
                                FeeModelId = datas[i].FeeModelId,
                                FeeModelName = datas[i].FeeModelName,
                                Description = datas[i].Description
                            });
                        }
                        // 填充页码
                        PaginationModel.FillPages(result.PageInfo.RecordCount, result.PageInfo.PageIndex);
                    });
                }
                this.HideLoading();
            });
        }
        public override void AddItem()
        {
            base.AddItem();
        }
    }
}

_dispatcher = unityContainer.Resolve(); 含义
依赖注入容器:unityContainer 是使用 Unity(一种依赖注入容器 )创建的对象。
依赖注入是一种软件设计模式,通过将对象所依赖的其他对象传递给它,而不是让对象自己创建依赖项,
从而实现松耦合。
Resolve 方法:Resolve 是 Unity 容器的方法 ,作用是从容器中获取指定类型的实例。 表示期望获取的对象类型为 Dispatcher 。
在这里,_dispatcher = unityContainer.Resolve();
就是从 unityContainer 中获取一个 Dispatcher 实例,并将其赋值给 _dispatcher 字段 。

Dispatcher 常见于 Windows Presentation Foundation(WPF)等 UI 框架,是用于协调和管理线程工作的重要组件,主要作用如下:
确保 UI 线程安全更新
在 WPF 应用程序中,UI 元素只能在创建它们的线程(即 UI 线程 )上进行修改。当进行如异步操作(后台任务、网络请求 )、定时器操作等时,这些操作可能在非 UI 线程上执行。Dispatcher 提供了一种机制,允许在非 UI 线程上执行的代码能够安全地在 UI 线程上更新 UI 元素 。比如从后台线程获取数据后,需更新 UI 显示,就要通过 Dispatcher 来执行更新操作,防止跨线程访问 UI 引发的线程安全问题。

的 在这里插入图片描述
在这里注册了注册 Dispatcher
/// 全局对象注册
containerRegistry.Register(() => Application.Current.Dispatcher);
注意:由于 Prism 与 Unity 容器的集成以及依赖注入容器的类型注册和解析机制,_dispatcher = unityContainer.Resolve(); 能够取到通过 containerRegistry.Register(() => Application.Current.Dispatcher); 注册的 Dispatcher 实例。

Application.Current 用于获取当前应用程序实例,Application.Current.Dispatcher 则获取当前应用程序的 Dispatcher 实例。这行代码的作用就是将当前应用程序的 Dispatcher 实例注册到容器中,后续就可以从容器中解析获取该实例,用于在不同地方安全地进行 UI 线程相关操作 。

3. IRegionManager regionManager, IUnityContainer unityContainer, IEventAggregator ea,IAutoRegisterBLL autoRegisterBLL

3.1 IRegionManager regionManager:
IRegionManager 是 Prism 框架中的一个接口,用于管理应用程序中的区域(Region)。区域是一种在 WPF 应用中用于动态显示内容的容器机制。
**regionManager 实例可以用来注册区域、导航到不同的视图并将视图显示在指定的区域中。**通过它,开发者可以实现模块化的 UI 设计,不同的模块可以向特定区域提供和显示自己的视图,而无需紧密耦合。例如,可以在主窗口中定义多个区域,然后使用 regionManager 将不同功能模块的视图加载并显示到相应的区域中。
3.2 IUnityContainer unityContainer:
IUnityContainer 是 Unity 依赖注入容器的接口。依赖注入是一种软件设计模式,它允许将对象的依赖关系通过外部传递进来,而不是让对象自己创建依赖项。
unityContainer 实例提供了一系列方法,用于注册类型(将抽象类型与具体实现类型关联起来)、解析类型(从容器中获取已注册类型的实例)等操作。在应用程序中,通过 unityContainer 可以方便地管理对象的生命周期,实现依赖关系的解耦,提高代码的可维护性和可测试性。例如,可以将业务逻辑层的服务类注册到容器中,然后在视图模型中通过容器解析获取这些服务的实例来使用。
3.3 IEventAggregator ea:
IEventAggregator 是 Prism 框架中的一个接口,用于实现事件聚合模式。事件聚合模式提供了一种在不同模块、视图模型或其他组件之间进行通信的机制。
ea 实例允许发布者(Publisher)发布特定类型的事件,而订阅者(Subscriber)可以订阅这些事件并在事件发生时执行相应的处理逻辑。通过事件聚合器,不同组件之间可以实现松耦合的通信,无需直接引用对方。例如,一个模块中的视图模型可以发布一个 “数据更新完成” 的事件,其他模块中的视图模型如果对这个事件感兴趣,可以订阅该事件并在事件发生时更新自己的 UI 显示。

4.socket

using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace Zhaoxi.SocketServer
{
    class Program
    {
        static void Main(string[] args)
        {
            Socket socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socketServer.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9001));//设置对应的主机地址(IP、Port)
            socketServer.Listen(10);// 监听  表示等待连接对象只能有10个

            Console.WriteLine("服务启动。。。");

            var client = socketServer.Accept();

            Console.WriteLine("有客户端连接了。。。");

            Console.ReadLine();
        }
    }
}

Accept 方法是阻塞方法,用于在监听的端口上接受传入的客户端连接请求,接收到连接后返回代表该客户端连接的 Socket 对象,这是服务端用于与客户端建立通信链路的关键操作。
这是服务端 运行到accept方法时候阻塞然后等待客户端连接 后面代码暂时不执行

Listen 方法开始监听客户端连接请求,说明它在等待客户端连接

4.1

服务端代码

using System;
using System.Net;
using System.Net.Sockets;

namespace Zhaoxi.SocketServer
{
    class Program
    {
        static void Main(string[] args)
        {
            Socket socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socketServer.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9001));
            socketServer.Listen(10);

            Console.WriteLine("服务启动。。。");

            var client = socketServer.Accept();

            Console.WriteLine("有客户端连接了。。。");

            Console.ReadLine();
        }
    }
}

客户端代码

using System;
using System.Net;
using System.Net.Sockets;

namespace Zhaoxi.SocketClient
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Socket socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                socketClient.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9001));

                Console.WriteLine("连接成功");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.ReadLine();
        }
    }
}

在这里插入图片描述
这里用了一个监听listen(1)表示等待的对象只能有一个,这个是单线程,看图是连接两的第三个就会连接失败,虽然是连接两个,实际上有一个是等待状态不能进行通讯。其实都可以通讯

单线程
static void Main(string[] args)
{
Socket socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socketServer.Bind(new IPEndPoint(IPAddress.Parse(“127.0.0.1”), 9001));//设置对应的主机地址(IP、Port)
socketServer.Listen(1);// 监听 表示等待连接对象只能有1个

   Console.WriteLine("服务启动。。。。");


        //   await Task.Delay(200);
           var client = socketServer.Accept();
          
           Console.WriteLine("有客户端连接了111111");
       // 为每个客户端创建独立线程处理通信
       //new Thread(() => HandleClient(client)).Start();
       //client.Receive();
       //client.Send();

   Console.WriteLine("主线程1");
   Console.ReadLine();
   Console.WriteLine("主线程2");

}

这里连到第三个客户端会失败 因为lisent(1)规定队列里面有一个连接等待 第一个连接被accept调用 第二个等待 第三个失败 这时候加上循环当有连接的时候不断调用 accept 就不会连接失败
单线程加循环

   static void Main(string[] args)
   {
       Socket socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
       socketServer.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9001));//设置对应的主机地址(IP、Port)
       socketServer.Listen(1);// 监听    表示等待连接对象只能有1个  

       Console.WriteLine("服务启动。。。。");

    
           while (true)
           {
            //   await Task.Delay(200);
               var client = socketServer.Accept();
              
               Console.WriteLine("有客户端连接了111111");
           // 为每个客户端创建独立线程处理通信
           //new Thread(() => HandleClient(client)).Start();
           //client.Receive();
           //client.Send();
       }
      

       Console.WriteLine("主线程1");
       Console.ReadLine();
       Console.WriteLine("主线程2");
   }

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
Socket socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socketServer.Bind(new IPEndPoint(IPAddress.Parse(“127.0.0.1”), 9001));
socketServer.Listen(1); // 监听,表示等待连接对象只能有1个(此处注释说明有误,1是等待连接队列长度)
Console.WriteLine(“服务启动。。。”);

        Task.Run(async () =>
        {
            while (true)
            {
                await Task.Delay(200);
                var client = socketServer.Accept();
                client.Receive(buffer) 
                Console.WriteLine("有客户端连接了。。。");
            }
        });

        Console.ReadLine();
    }
}

}

单线程阻塞:这段代码确实没有显式创建新线程,所有操作都在主线程中完成。
问题所在:client.Receive(buffer) 是同步阻塞调用。如果当前客户端不发送数据,Receive 会一直阻塞主线程,导致服务器无法调用 Accept() 接受新客户端连接。
结果:服务器同一时间只能处理一个客户端,其他客户端必须等待当前客户端完成数据传输。
多线程

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Socket socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socketServer.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9001));
            socketServer.Listen(1); // 监听,表示等待连接对象只能有1个(此处注释说明有误,1是等待连接队列长度)
            Console.WriteLine("服务启动。。。");

            Task.Run(async () =>
            {
                while (true)
                {
                    await Task.Delay(200);
                    var client = socketServer.Accept();
                    Console.WriteLine("有客户端连接了。。。");
                }
            });

            Console.ReadLine();
        }
    }
}

这个好处就是不阻塞主线程

真正异步阻塞

Task.Run(async () =>
{
    while (true)
    {
    //注意:accept()是同步方法不能用await 所以改成 acceptAsync
        var client = await socketServer.AcceptAsync(); // 异步非阻塞!
        Console.WriteLine("有客户端连接了。。。");
        
        // 异步处理客户端(不阻塞接受新连接的循环)
        _ = HandleClientAsync(client);
    }
});
static async Task HandleClientAsync(Socket client)
{
    try
    {
        byte[] buffer = new byte[1024];
        // 异步接收数据
        await client.ReceiveAsync(buffer, SocketFlags.None);
        // 处理数据...
    }
    finally
    {
        client.Dispose();
    }
}

注意:accept()是同步方法不能用await 所以改成 acceptAsync
遇到 await 时:
当前线程被释放:执行 AcceptAsync() 的线程(假设为线程 T)会立即返回线程池,不再被阻塞。
注册回调:系统会在 AcceptAsync() 完成(即有新连接到达)时,自动触发后续代码的执行。
异步操作完成后:
调度恢复执行:当新连接到达时,线程池会调度另一个线程(或复用线程 T)来执行 await 之后的代码(如 Console.WriteLine)。
延续执行:后续代码(如处理客户端逻辑)会在这个新线程上继续执行。

时间线:
[步骤1] 线程T开始执行循环 -> 调用 AcceptAsync()
[步骤2] AcceptAsync() 返回一个未完成的 Task -> 线程T被释放回线程池
[步骤3] 主线程继续执行其他任务(或空闲)
[步骤4] 新客户端连接到达 -> AcceptAsync() 完成
[步骤5] 线程池调度线程S(可能是T或其他线程)执行:
Console.WriteLine(“有客户端连接了。。。”);
// 继续执行后续代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值