├── .gitignore ├── AvaloniaSamples.sln ├── Readme.md └── Samples ├── LineDemo ├── LineDemo.sln └── LineDemo │ ├── App.axaml │ ├── App.axaml.cs │ ├── Assets │ ├── aaa.png │ ├── avalonia-logo.ico │ └── avalonia.png │ ├── LineDemo.csproj │ ├── Program.cs │ ├── ViewLocator.cs │ ├── ViewModels │ ├── ChartViewModel.cs │ ├── MainWindowViewModel.cs │ └── ViewModelBase.cs │ ├── Views │ ├── ChartView.axaml │ ├── ChartView.axaml.cs │ ├── MainWindow.axaml │ └── MainWindow.axaml.cs │ └── app.manifest ├── MVSCameraDemo ├── CameraDemo.sln ├── CameraDemo │ ├── App.axaml │ ├── App.axaml.cs │ ├── Assets │ │ ├── avalonia-logo.ico │ │ └── msyh.ttc │ ├── CameraDemo.csproj │ ├── Controls │ │ └── HandleControl.cs │ ├── FontManager.cs │ ├── Program.cs │ ├── ViewLocator.cs │ ├── ViewModels │ │ ├── MainWindowViewModel.cs │ │ └── ViewModelBase.cs │ ├── Views │ │ ├── MainWindow.axaml │ │ └── MainWindow.axaml.cs │ └── app.manifest ├── HKSDK │ ├── Enums │ │ ├── DeviceLayerType.cs │ │ ├── ImageType.cs │ │ └── PixelFormatType.cs │ ├── HKCameraControl.cs │ ├── HKSDK.csproj │ ├── Lib │ │ ├── libFormatConversion.so │ │ ├── libMVGigEVisionSDK.so │ │ ├── libMVRender.so │ │ ├── libMediaProcess.so │ │ ├── libMvCameraControl.so │ │ ├── libMvCameraControlWrapper.so │ │ └── libMvUsb3vTL.so │ └── Models │ │ ├── DeviceInfo.cs │ │ ├── DeviceInfos.cs │ │ ├── FloatSettingModel.cs │ │ ├── FrameOutInfo.cs │ │ ├── GigeDeviceInfo.cs │ │ └── SaveImageParams.cs └── Readme.md └── OpcUADemo ├── OpcUAClient.Repository ├── IRepository.cs ├── Models │ └── HistoryDataModel.cs ├── OpcUAClient.Repository.csproj └── Services │ └── DapperRepository.cs ├── OpcUAClient ├── App.axaml ├── App.axaml.cs ├── Assets │ ├── avalonia-logo.ico │ └── msyh.ttc ├── FodyWeavers.xml ├── FodyWeavers.xsd ├── FontManager.cs ├── Models │ ├── DataRecordSettingModel.cs │ ├── NodeInfo.cs │ ├── NodeListenModel.cs │ └── NodeModel.cs ├── OPC │ └── pki │ │ ├── own │ │ ├── certs │ │ │ └── OpcUa Client [49AC5D9DC29D3C0AC0885E6B77901913BDB340CF].der │ │ └── private │ │ │ └── OpcUa Client [49AC5D9DC29D3C0AC0885E6B77901913BDB340CF].pfx │ │ └── trusted │ │ └── certs │ │ └── OPCUAServer@sii-ret [B2B70C26F4DEB5D7A4817E73F56DFC8D38EC107D].der ├── OpcUAClient.Config.xml ├── OpcUAClient.csproj ├── Program.cs ├── Readme.md ├── UAClient.cs ├── ViewLocator.cs ├── ViewModels │ ├── LineListenViewModel.cs │ ├── MainWindowViewModel.cs │ ├── SettingWindowViewModel.cs │ └── ViewModelBase.cs ├── Views │ ├── LineListenView.axaml │ ├── LineListenView.axaml.cs │ ├── MainWindow.axaml │ ├── MainWindow.axaml.cs │ ├── SettingWindowView.axaml │ └── SettingWindowView.axaml.cs ├── app.config └── app.manifest └── OpcUADemo.sln /.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /projectSettingsUpdater.xml 6 | /modules.xml 7 | /contentModel.xml 8 | /.idea.ZKSD.RTE.iml 9 | # Editor-based HTTP Client requests 10 | /httpRequests/ 11 | # Datasource local storage ignored files 12 | /dataSources/ 13 | /dataSources.local.xml 14 | 15 | .idea/ 16 | .vs/ 17 | 18 | 19 | *.suo 20 | *.user 21 | *.userosscache 22 | *.sln.docstates 23 | 24 | bin 25 | obj -------------------------------------------------------------------------------- /AvaloniaSamples.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{B93D2B5F-7D17-4919-B363-02E363AE408A}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MVSCameraDemo", "MVSCameraDemo", "{8382B803-6D74-40AA-A909-094028E06B26}" 9 | ProjectSection(SolutionItems) = preProject 10 | Samples\MVSCameraDemo\Readme.md = Samples\MVSCameraDemo\Readme.md 11 | EndProjectSection 12 | EndProject 13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CameraDemo", "Samples\MVSCameraDemo\CameraDemo\CameraDemo.csproj", "{7778DEF8-09B0-4B32-A714-AAB237793F75}" 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HKSDK", "Samples\MVSCameraDemo\HKSDK\HKSDK.csproj", "{1502CD99-72A4-4894-8981-834DD9FA3036}" 16 | EndProject 17 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LineDemo", "LineDemo", "{26EE2E3B-A005-42C6-AC79-4F09325E49E0}" 18 | EndProject 19 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LineDemo", "Samples\LineDemo\LineDemo\LineDemo.csproj", "{1F5D1719-65A4-48AB-BAA8-485EBB8AC4BA}" 20 | EndProject 21 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OpcUADemo", "OpcUADemo", "{06A3D0BE-7497-451E-AD92-F92F8B5557B7}" 22 | EndProject 23 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpcUAClient", "Samples\OpcUADemo\OpcUAClient\OpcUAClient.csproj", "{9EBC3A71-EA2E-4B2D-9A01-CF68E90F7078}" 24 | EndProject 25 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpcUAClient.Repository", "Samples\OpcUADemo\OpcUAClient.Repository\OpcUAClient.Repository.csproj", "{82FE4236-E9E2-4578-87A2-7B1BECED019D}" 26 | EndProject 27 | Global 28 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 29 | Debug|Any CPU = Debug|Any CPU 30 | Release|Any CPU = Release|Any CPU 31 | EndGlobalSection 32 | GlobalSection(SolutionProperties) = preSolution 33 | HideSolutionNode = FALSE 34 | EndGlobalSection 35 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 36 | {7778DEF8-09B0-4B32-A714-AAB237793F75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {7778DEF8-09B0-4B32-A714-AAB237793F75}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {7778DEF8-09B0-4B32-A714-AAB237793F75}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {7778DEF8-09B0-4B32-A714-AAB237793F75}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {1502CD99-72A4-4894-8981-834DD9FA3036}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {1502CD99-72A4-4894-8981-834DD9FA3036}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {1502CD99-72A4-4894-8981-834DD9FA3036}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {1502CD99-72A4-4894-8981-834DD9FA3036}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {1F5D1719-65A4-48AB-BAA8-485EBB8AC4BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {1F5D1719-65A4-48AB-BAA8-485EBB8AC4BA}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {1F5D1719-65A4-48AB-BAA8-485EBB8AC4BA}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {1F5D1719-65A4-48AB-BAA8-485EBB8AC4BA}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {259728FA-5373-4D95-94A2-3E40420EC291}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {259728FA-5373-4D95-94A2-3E40420EC291}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {259728FA-5373-4D95-94A2-3E40420EC291}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {259728FA-5373-4D95-94A2-3E40420EC291}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {9EBC3A71-EA2E-4B2D-9A01-CF68E90F7078}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {9EBC3A71-EA2E-4B2D-9A01-CF68E90F7078}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {9EBC3A71-EA2E-4B2D-9A01-CF68E90F7078}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {9EBC3A71-EA2E-4B2D-9A01-CF68E90F7078}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {82FE4236-E9E2-4578-87A2-7B1BECED019D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 57 | {82FE4236-E9E2-4578-87A2-7B1BECED019D}.Debug|Any CPU.Build.0 = Debug|Any CPU 58 | {82FE4236-E9E2-4578-87A2-7B1BECED019D}.Release|Any CPU.ActiveCfg = Release|Any CPU 59 | {82FE4236-E9E2-4578-87A2-7B1BECED019D}.Release|Any CPU.Build.0 = Release|Any CPU 60 | EndGlobalSection 61 | GlobalSection(NestedProjects) = preSolution 62 | {8382B803-6D74-40AA-A909-094028E06B26} = {B93D2B5F-7D17-4919-B363-02E363AE408A} 63 | {7778DEF8-09B0-4B32-A714-AAB237793F75} = {8382B803-6D74-40AA-A909-094028E06B26} 64 | {1502CD99-72A4-4894-8981-834DD9FA3036} = {8382B803-6D74-40AA-A909-094028E06B26} 65 | {26EE2E3B-A005-42C6-AC79-4F09325E49E0} = {B93D2B5F-7D17-4919-B363-02E363AE408A} 66 | {1F5D1719-65A4-48AB-BAA8-485EBB8AC4BA} = {26EE2E3B-A005-42C6-AC79-4F09325E49E0} 67 | {06A3D0BE-7497-451E-AD92-F92F8B5557B7} = {B93D2B5F-7D17-4919-B363-02E363AE408A} 68 | {9EBC3A71-EA2E-4B2D-9A01-CF68E90F7078} = {06A3D0BE-7497-451E-AD92-F92F8B5557B7} 69 | {82FE4236-E9E2-4578-87A2-7B1BECED019D} = {06A3D0BE-7497-451E-AD92-F92F8B5557B7} 70 | EndGlobalSection 71 | EndGlobal 72 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # 中科时代Avalonia开发样例 2 | 3 | ## 说明 4 | 此资料为中科时代(深圳)计算机系统有限公司提供,主要目的在于指导C#程序员进行跨平台桌面程序开发(主要为Linux),所涉及的主要技术为C#和[Avalonia](https://www.avaloniaui.net/),如有任何疑问请联系中科时代(深圳)计算机系统有限公司。 5 | 6 | ## 目录介绍 7 | 本资料包含两部分内容: 8 | * [Samples](./Samples):此目录下包含使用Avalonia开发的一些常用的Demo,可以下载进行参阅。 9 | 10 | 11 | ## Demo列表 12 | 13 | | 名称 | 介绍 | 14 | |---|---| 15 | |[LineDemo](./Samples/LineDemo)|曲线绘制相关Demo| 16 | |[MVSCameraDemo](./Samples/MVSCameraDemo)|海康工业相机连接Demo,提供C#调用海康C语言SDK示例以及调用海康相机显示实时视频流、存储图片的功能| 17 | |[OpcUADemo](./Samples/OpcUADemo/OpcUAClient)|连接OPC UA服务端的Demo,提供OPC UA客户端,具有曲线绘制等相关功能| 18 | ### 更多Avalonia开发资料及相应问题,请参阅[知识文档](https://sinsegye-csharp.github.io/avalonia-doc) 19 | -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33424.131 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LineDemo", "LineDemo\LineDemo.csproj", "{AF8156C7-D27B-4D2F-9BA8-DFF968E375AE}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {AF8156C7-D27B-4D2F-9BA8-DFF968E375AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {AF8156C7-D27B-4D2F-9BA8-DFF968E375AE}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {AF8156C7-D27B-4D2F-9BA8-DFF968E375AE}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {AF8156C7-D27B-4D2F-9BA8-DFF968E375AE}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {E8196FA2-733E-4561-AB23-8C13E978C077} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/App.axaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/App.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls.ApplicationLifetimes; 3 | using Avalonia.Markup.Xaml; 4 | using AvaloniaDemo.ViewModels; 5 | using AvaloniaDemo.Views; 6 | 7 | namespace AvaloniaDemo; 8 | 9 | public partial class App : Application 10 | { 11 | public override void Initialize() 12 | { 13 | AvaloniaXamlLoader.Load(this); 14 | } 15 | 16 | public override void OnFrameworkInitializationCompleted() 17 | { 18 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) 19 | { 20 | desktop.MainWindow = new MainWindow 21 | { 22 | DataContext = new MainWindowViewModel(), 23 | }; 24 | } 25 | 26 | base.OnFrameworkInitializationCompleted(); 27 | } 28 | } -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/Assets/aaa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinsegye-CSharp/AvaloniaSamples/57bdbf48c0eb86b05ae12e239984a27e9291b8c4/Samples/LineDemo/LineDemo/Assets/aaa.png -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/Assets/avalonia-logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinsegye-CSharp/AvaloniaSamples/57bdbf48c0eb86b05ae12e239984a27e9291b8c4/Samples/LineDemo/LineDemo/Assets/avalonia-logo.ico -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/Assets/avalonia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinsegye-CSharp/AvaloniaSamples/57bdbf48c0eb86b05ae12e239984a27e9291b8c4/Samples/LineDemo/LineDemo/Assets/avalonia.png -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/LineDemo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | WinExe 4 | net6.0 5 | enable 6 | true 7 | app.manifest 8 | AvaloniaDemo 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/Program.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.ReactiveUI; 3 | using System; 4 | 5 | namespace AvaloniaDemo; 6 | 7 | class Program 8 | { 9 | // Initialization code. Don't use any Avalonia, third-party APIs or any 10 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized 11 | // yet and stuff might break. 12 | [STAThread] 13 | public static void Main(string[] args) => BuildAvaloniaApp() 14 | .StartWithClassicDesktopLifetime(args); 15 | 16 | // Avalonia configuration, don't remove; also used by visual designer. 17 | public static AppBuilder BuildAvaloniaApp() 18 | => AppBuilder.Configure() 19 | .UsePlatformDetect() 20 | .LogToTrace() 21 | .UseReactiveUI(); 22 | } 23 | -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/ViewLocator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia.Controls; 3 | using Avalonia.Controls.Templates; 4 | using AvaloniaDemo.ViewModels; 5 | 6 | namespace AvaloniaDemo; 7 | 8 | public class ViewLocator : IDataTemplate 9 | { 10 | public IControl Build(object data) 11 | { 12 | var viewModelName = data.GetType().FullName; 13 | if (string.IsNullOrWhiteSpace(viewModelName)) 14 | { 15 | return new TextBlock { Text = "Not Found: " }; 16 | } 17 | 18 | var viewTypeName = viewModelName.TrimEnd("Model".ToCharArray()).Replace("ViewModels","Views"); 19 | var type = Type.GetType(viewTypeName); 20 | 21 | if (type != null) 22 | { 23 | return (Control)Activator.CreateInstance(type)!; 24 | } 25 | 26 | return new TextBlock { Text = "Not Found: " + viewTypeName }; 27 | } 28 | 29 | public bool Match(object data) 30 | { 31 | return data is ViewModelBase; 32 | } 33 | } -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/ViewModels/ChartViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.ObjectModel; 3 | using Avalonia.Threading; 4 | using LiveChartsCore; 5 | using LiveChartsCore.Defaults; 6 | using LiveChartsCore.SkiaSharpView; 7 | using LiveChartsCore.SkiaSharpView.Painting; 8 | using SkiaSharp; 9 | 10 | namespace AvaloniaDemo.ViewModels; 11 | 12 | public class ChartViewModel : ViewModelBase 13 | { 14 | #region Private Fileds 15 | 16 | // 动态折线1数据 17 | private readonly ObservableCollection _observableValues1; 18 | 19 | // 动态折线2数据 20 | private readonly ObservableCollection _observableValues2; 21 | 22 | // 生成随机数据的函数 23 | private readonly Random _random = new(); 24 | 25 | #endregion 26 | 27 | /// 28 | /// 构造函数 29 | /// 30 | public ChartViewModel() 31 | { 32 | _observableValues1 = new ObservableCollection 33 | { 34 | new(DateTime.Now.AddSeconds(-1), 0), 35 | }; 36 | _observableValues2 = new ObservableCollection 37 | { 38 | new(DateTime.Now.AddSeconds(-1), 0), 39 | }; 40 | 41 | CartesianLineChartXAxis = new[] 42 | { 43 | new Axis 44 | { 45 | MinLimit = DateTime.Now.Ticks, 46 | MinStep = TimeSpan.FromSeconds(1).Ticks, 47 | UnitWidth = TimeSpan.FromSeconds(1).Ticks, 48 | Labeler = value=>new DateTime((long)value).ToString("HH:mm:ss"), 49 | TicksPaint = new SolidColorPaint(SKColors.Black) 50 | } 51 | }; 52 | CartesianChartYAxis = new[] 53 | { 54 | new Axis 55 | { 56 | MinLimit = 0, 57 | MinStep = 1, 58 | } 59 | }; 60 | 61 | CartesianChartLineSeries = new ObservableCollection 62 | { 63 | new LineSeries 64 | { 65 | Name = "城市规模", 66 | Values = _observableValues1, 67 | }, 68 | new LineSeries 69 | { 70 | Name = "城市经济", 71 | Values = _observableValues2, 72 | }, 73 | }; 74 | 75 | UpdateLine(); 76 | } 77 | 78 | #region Public Properties 79 | 80 | /// 81 | /// 折线图X轴设置 82 | /// 83 | public Axis[] CartesianLineChartXAxis { get; set; } 84 | 85 | /// 86 | /// 折线图Y轴设置 87 | /// 88 | public Axis[] CartesianChartYAxis { get; set; } 89 | 90 | /// 91 | /// 折线图曲线 92 | /// 93 | public ObservableCollection CartesianChartLineSeries { get; set; } 94 | 95 | /// 96 | /// 提示框绘制设置 97 | /// 98 | public SolidColorPaint TooltipTextPaint { get; set; } = 99 | new() 100 | { 101 | Color = SKColors.Black, 102 | SKTypeface = SKFontManager.Default.MatchCharacter('汉'), 103 | }; 104 | 105 | #endregion 106 | 107 | #region Private Methods 108 | 109 | // 更新曲线 110 | private void UpdateLine() 111 | { 112 | var timer = new DispatcherTimer 113 | { 114 | Interval = TimeSpan.FromSeconds(1) 115 | }; 116 | timer.Tick += (_, _) => 117 | { 118 | if (_observableValues1.Count > 10) 119 | { 120 | CartesianLineChartXAxis[0].MinLimit = _observableValues1[^10].DateTime.Ticks; 121 | } 122 | _observableValues1.Add(new DateTimePoint(DateTime.Now, _random.Next(1, 10))); 123 | _observableValues2.Add(new DateTimePoint(DateTime.Now, _random.Next(1, 10))); 124 | }; 125 | timer.Start(); 126 | } 127 | 128 | #endregion 129 | } -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/ViewModels/MainWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | 3 | namespace AvaloniaDemo.ViewModels; 4 | 5 | public class MainWindowViewModel : ViewModelBase 6 | { 7 | private string _title = "曲线图演示Demo"; 8 | 9 | /// 10 | /// 程序标题 11 | /// 12 | public string Title 13 | { 14 | get => _title; 15 | set => this.RaiseAndSetIfChanged(ref _title, value); 16 | } 17 | 18 | private ChartViewModel _chartViewModel=new(); 19 | 20 | public ChartViewModel ChartViewModel 21 | { 22 | get => _chartViewModel; 23 | set => this.RaiseAndSetIfChanged(ref _chartViewModel, value); 24 | } 25 | } -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/ViewModels/ViewModelBase.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | 3 | namespace AvaloniaDemo.ViewModels; 4 | 5 | public class ViewModelBase : ReactiveObject 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/Views/ChartView.axaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/Views/ChartView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Markup.Xaml; 2 | using Avalonia.ReactiveUI; 3 | using AvaloniaDemo.ViewModels; 4 | using ReactiveUI; 5 | 6 | namespace AvaloniaDemo.Views; 7 | 8 | public partial class ChartView : ReactiveUserControl 9 | { 10 | public ChartView() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | private void InitializeComponent() 16 | { 17 | this.WhenActivated(disposable => 18 | { 19 | 20 | }); 21 | AvaloniaXamlLoader.Load(this); 22 | } 23 | } -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/Views/MainWindow.axaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/Views/MainWindow.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Markup.Xaml; 3 | using Avalonia.ReactiveUI; 4 | using AvaloniaDemo.ViewModels; 5 | using ReactiveUI; 6 | 7 | namespace AvaloniaDemo.Views; 8 | 9 | public partial class MainWindow : ReactiveWindow 10 | { 11 | public MainWindow() 12 | { 13 | this.WhenActivated(disposables => 14 | { 15 | }); 16 | AvaloniaXamlLoader.Load(this); 17 | 18 | #if DEBUG 19 | this.AttachDevTools(); 20 | #endif 21 | } 22 | } -------------------------------------------------------------------------------- /Samples/LineDemo/LineDemo/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Samples/MVSCameraDemo/CameraDemo.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CameraDemo", "CameraDemo\CameraDemo.csproj", "{82D7DB28-F1D0-400F-8CFC-7F8559444FC8}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HKSDK", "HKSDK\HKSDK.csproj", "{E0C3B0D0-085B-4F07-B162-80209B655640}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Release|Any CPU = Release|Any CPU 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {82D7DB28-F1D0-400F-8CFC-7F8559444FC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 14 | {82D7DB28-F1D0-400F-8CFC-7F8559444FC8}.Debug|Any CPU.Build.0 = Debug|Any CPU 15 | {82D7DB28-F1D0-400F-8CFC-7F8559444FC8}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | {82D7DB28-F1D0-400F-8CFC-7F8559444FC8}.Release|Any CPU.Build.0 = Release|Any CPU 17 | {E0C3B0D0-085B-4F07-B162-80209B655640}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {E0C3B0D0-085B-4F07-B162-80209B655640}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {E0C3B0D0-085B-4F07-B162-80209B655640}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {E0C3B0D0-085B-4F07-B162-80209B655640}.Release|Any CPU.Build.0 = Release|Any CPU 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /Samples/MVSCameraDemo/CameraDemo/App.axaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Samples/MVSCameraDemo/CameraDemo/App.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls.ApplicationLifetimes; 3 | using Avalonia.Markup.Xaml; 4 | using Avalonia.Platform; 5 | using CameraDemo.ViewModels; 6 | using CameraDemo.Views; 7 | 8 | namespace CameraDemo; 9 | 10 | public partial class App : Application 11 | { 12 | public override void Initialize() 13 | { 14 | AvaloniaXamlLoader.Load(this); 15 | } 16 | 17 | public override void OnFrameworkInitializationCompleted() 18 | { 19 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) 20 | { 21 | desktop.MainWindow = new MainWindow 22 | { 23 | DataContext = new MainWindowViewModel(), 24 | }; 25 | } 26 | 27 | base.OnFrameworkInitializationCompleted(); 28 | } 29 | 30 | public override void RegisterServices() 31 | { 32 | AvaloniaLocator.CurrentMutable.Bind().ToConstant(new FontManager()); 33 | base.RegisterServices(); 34 | } 35 | } -------------------------------------------------------------------------------- /Samples/MVSCameraDemo/CameraDemo/Assets/avalonia-logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinsegye-CSharp/AvaloniaSamples/57bdbf48c0eb86b05ae12e239984a27e9291b8c4/Samples/MVSCameraDemo/CameraDemo/Assets/avalonia-logo.ico -------------------------------------------------------------------------------- /Samples/MVSCameraDemo/CameraDemo/Assets/msyh.ttc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinsegye-CSharp/AvaloniaSamples/57bdbf48c0eb86b05ae12e239984a27e9291b8c4/Samples/MVSCameraDemo/CameraDemo/Assets/msyh.ttc -------------------------------------------------------------------------------- /Samples/MVSCameraDemo/CameraDemo/CameraDemo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | WinExe 4 | net6.0 5 | enable 6 | true 7 | app.manifest 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Samples/MVSCameraDemo/CameraDemo/Controls/HandleControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia; 3 | using Avalonia.Controls; 4 | using Avalonia.Data; 5 | using Avalonia.Platform; 6 | 7 | namespace CameraDemo.Controls; 8 | 9 | /// 10 | /// 海康相机控件 11 | /// 12 | public class HkCameraControl : NativeControlHost 13 | { 14 | public static readonly StyledProperty HandleProperty = AvaloniaProperty.Register( 15 | "Handle", default, false, BindingMode.OneWayToSource); 16 | 17 | /// 18 | /// 窗口句柄 19 | /// 20 | public IntPtr Handle 21 | { 22 | get => GetValue(HandleProperty); 23 | set => SetValue(HandleProperty, value); 24 | } 25 | 26 | protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle parent) 27 | { 28 | var handle = base.CreateNativeControlCore(parent); 29 | this.Handle = handle.Handle; 30 | return handle; 31 | } 32 | } -------------------------------------------------------------------------------- /Samples/MVSCameraDemo/CameraDemo/FontManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Globalization; 3 | using System.Linq; 4 | using Avalonia.Media; 5 | using Avalonia.Platform; 6 | using Avalonia.Skia; 7 | using SkiaSharp; 8 | 9 | namespace CameraDemo; 10 | 11 | public class FontManager : IFontManagerImpl 12 | { 13 | private readonly Typeface[] _customTypefaces; 14 | private readonly string _defaultFamilyName; 15 | 16 | private readonly Typeface _defaultTypeface = new("avares://CameraDemo/Assets/msyh.ttc#微软雅黑"); 17 | 18 | private readonly string[] _bcp47 = 19 | { CultureInfo.CurrentCulture.ThreeLetterISOLanguageName, CultureInfo.CurrentCulture.TwoLetterISOLanguageName }; 20 | 21 | public FontManager() 22 | { 23 | _customTypefaces = new[] { _defaultTypeface }; 24 | _defaultFamilyName = _defaultTypeface.FontFamily.FamilyNames.PrimaryFamilyName; 25 | } 26 | 27 | public string GetDefaultFontFamilyName() => _defaultFamilyName; 28 | 29 | public IEnumerable GetInstalledFontFamilyNames(bool checkForUpdates = false) => 30 | _customTypefaces.Select(x => x.FontFamily.Name); 31 | 32 | public bool TryMatchCharacter(int codepoint, FontStyle fontStyle, FontWeight fontWeight, FontFamily fontFamily, 33 | CultureInfo culture, out Typeface typeface) 34 | { 35 | foreach (var customTypeface in _customTypefaces) 36 | { 37 | if (customTypeface.GlyphTypeface.GetGlyph((uint)codepoint) == 0) 38 | { 39 | continue; 40 | } 41 | 42 | typeface = new Typeface(customTypeface.FontFamily.Name, fontStyle, fontWeight); 43 | 44 | return true; 45 | } 46 | 47 | var fallback = SKFontManager.Default.MatchCharacter(fontFamily?.Name, (SKFontStyleWeight)fontWeight, 48 | SKFontStyleWidth.Normal, (SKFontStyleSlant)fontStyle, _bcp47, codepoint); 49 | 50 | typeface = new Typeface(fallback?.FamilyName ?? _defaultFamilyName, fontStyle, fontWeight); 51 | 52 | return true; 53 | } 54 | 55 | public IGlyphTypefaceImpl CreateGlyphTypeface(Typeface typeface) 56 | { 57 | var skTypeface = typeface.FontFamily.Name switch 58 | { 59 | FontFamily.DefaultFontFamilyName => SKTypeface.FromFamilyName(_defaultTypeface.FontFamily.Name), 60 | "微软雅黑" => SKTypeface.FromFamilyName(_defaultTypeface.FontFamily.Name), 61 | _ => SKTypeface.FromFamilyName(typeface.FontFamily.Name, 62 | (SKFontStyleWeight)typeface.Weight, SKFontStyleWidth.Normal, (SKFontStyleSlant)typeface.Style) 63 | }; 64 | 65 | return new GlyphTypefaceImpl(skTypeface); 66 | } 67 | } -------------------------------------------------------------------------------- /Samples/MVSCameraDemo/CameraDemo/Program.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.ReactiveUI; 3 | using System; 4 | 5 | namespace CameraDemo; 6 | 7 | class Program 8 | { 9 | // Initialization code. Don't use any Avalonia, third-party APIs or any 10 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized 11 | // yet and stuff might break. 12 | [STAThread] 13 | public static void Main(string[] args) => BuildAvaloniaApp() 14 | .StartWithClassicDesktopLifetime(args); 15 | 16 | // Avalonia configuration, don't remove; also used by visual designer. 17 | public static AppBuilder BuildAvaloniaApp() 18 | => AppBuilder.Configure() 19 | .UsePlatformDetect() 20 | .LogToTrace() 21 | .UseReactiveUI(); 22 | } -------------------------------------------------------------------------------- /Samples/MVSCameraDemo/CameraDemo/ViewLocator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia.Controls; 3 | using Avalonia.Controls.Templates; 4 | using CameraDemo.ViewModels; 5 | 6 | namespace CameraDemo; 7 | 8 | public class ViewLocator : IDataTemplate 9 | { 10 | public IControl Build(object data) 11 | { 12 | var name = data.GetType().FullName!.Replace("ViewModel", "View"); 13 | var type = Type.GetType(name); 14 | 15 | if (type != null) 16 | { 17 | return (Control)Activator.CreateInstance(type)!; 18 | } 19 | 20 | return new TextBlock { Text = "Not Found: " + name }; 21 | } 22 | 23 | public bool Match(object data) 24 | { 25 | return data is ViewModelBase; 26 | } 27 | } -------------------------------------------------------------------------------- /Samples/MVSCameraDemo/CameraDemo/ViewModels/MainWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Drawing.Imaging; 5 | using System.IO; 6 | using System.Runtime.InteropServices; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using Avalonia.Controls; 10 | using Avalonia.Controls.ApplicationLifetimes; 11 | using Avalonia.Metadata; 12 | using HKSDK; 13 | using HKSDK.Enums; 14 | using HKSDK.Models; 15 | using ReactiveUI; 16 | using Image = System.Drawing.Image; 17 | 18 | namespace CameraDemo.ViewModels; 19 | 20 | public class MainWindowViewModel : ViewModelBase 21 | { 22 | #region Private Fields 23 | 24 | // 图像接收回调函数 25 | private readonly ReceiveImageDataDelegate _receiveImageData; 26 | 27 | // 相机句柄 28 | private IntPtr _cameraHandel; 29 | 30 | // 是否保存图片 31 | private bool _isSaveImage; 32 | 33 | private readonly IDictionary _cameraIntPtrDictionary; 34 | 35 | #endregion 36 | 37 | #region Public Properties 38 | 39 | private IntPtr _handle; 40 | 41 | /// 42 | /// 播放视频的窗口句柄 43 | /// 44 | public IntPtr Handle 45 | { 46 | get => _handle; 47 | set => this.RaiseAndSetIfChanged(ref _handle, value); 48 | } 49 | 50 | /// 51 | /// 相机列表 52 | /// 53 | public ObservableCollection CameraList { get; } 54 | 55 | private string _selectedCamera = ""; 56 | 57 | /// 58 | /// 选中的相机 59 | /// 60 | public string SelectedCamera 61 | { 62 | get => _selectedCamera; 63 | set => this.RaiseAndSetIfChanged(ref _selectedCamera, value); 64 | } 65 | 66 | private string _currentFps = ""; 67 | 68 | /// 69 | /// 当前帧率 70 | /// 71 | public string CurrentFps 72 | { 73 | get => _currentFps; 74 | set => this.RaiseAndSetIfChanged(ref _currentFps, value); 75 | } 76 | 77 | private string _resultingFrameRate = ""; 78 | 79 | /// 80 | /// 实际帧速率帧率 81 | /// 82 | public string ResultingFrameRate 83 | { 84 | get => _resultingFrameRate; 85 | set => this.RaiseAndSetIfChanged(ref _resultingFrameRate, value); 86 | } 87 | 88 | private string _settingFps = ""; 89 | 90 | /// 91 | /// 要设置的帧率 92 | /// 93 | public string SettingFps 94 | { 95 | get => _settingFps; 96 | set => this.RaiseAndSetIfChanged(ref _settingFps, value); 97 | } 98 | 99 | private bool _isPlaying; 100 | 101 | /// 102 | /// 是否正在播放 103 | /// 104 | public bool IsPlaying 105 | { 106 | get => _isPlaying; 107 | set => this.RaiseAndSetIfChanged(ref _isPlaying, value); 108 | } 109 | 110 | private string _imageSavePath = 111 | Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "CameraTest"); 112 | 113 | /// 114 | /// 图片保存路径 115 | /// 116 | public string ImageSavePath 117 | { 118 | get => _imageSavePath; 119 | set => this.RaiseAndSetIfChanged(ref _imageSavePath, value); 120 | } 121 | 122 | #endregion 123 | 124 | #region Ctor 125 | 126 | /// 127 | /// 构造函数 128 | /// 129 | public MainWindowViewModel() 130 | { 131 | _receiveImageData = OnReceiveImage; 132 | CameraList = new ObservableCollection(); 133 | _cameraIntPtrDictionary = new Dictionary(); 134 | 135 | Init(); 136 | } 137 | 138 | #endregion 139 | 140 | #region Public Methods 141 | 142 | /// 143 | /// 开始播放 144 | /// 145 | public void StartPlay() 146 | { 147 | var isOk = HkCameraControl.MV_CC_CreateHandle(out _cameraHandel, _cameraIntPtrDictionary[SelectedCamera]); 148 | Console.WriteLine($"创建句柄{isOk:x8}"); 149 | 150 | isOk = HkCameraControl.MV_CC_OpenDevice(_cameraHandel, 1, 0); 151 | Console.WriteLine($"打开设备{isOk:x8}"); 152 | 153 | isOk = HkCameraControl.MV_CC_RegisterImageCallBackEx(_cameraHandel, _receiveImageData, new IntPtr()); 154 | Console.WriteLine($"注册取图回调{isOk:x8}"); 155 | 156 | isOk = HkCameraControl.MV_CC_StartGrabbing(_cameraHandel); 157 | Console.WriteLine($"开始采集{isOk:x8}"); 158 | 159 | isOk = HkCameraControl.MV_CC_Display(_cameraHandel, Handle); 160 | Console.WriteLine($"开始播放{isOk:x8}"); 161 | 162 | this.IsPlaying = true; 163 | 164 | GetFpsValue(); 165 | } 166 | 167 | /// 168 | /// 是否可以开始播放 169 | /// 170 | /// 171 | [DependsOn(nameof(SelectedCamera))] 172 | public bool CanStartPlay(object _) => !string.IsNullOrWhiteSpace(SelectedCamera); 173 | 174 | /// 175 | /// 停止播放 176 | /// 177 | public void Stop() 178 | { 179 | var b = HkCameraControl.MV_CC_StopGrabbing(_cameraHandel); 180 | Console.WriteLine($"停止采集{b:x8}"); 181 | 182 | b = HkCameraControl.MV_CC_CloseDevice(_cameraHandel); 183 | Console.WriteLine($"关闭设备{b:x8}"); 184 | 185 | b = HkCameraControl.MV_CC_DestroyHandle(_cameraHandel); 186 | Console.WriteLine($"释放句柄{b:x8}"); 187 | 188 | this.IsPlaying = false; 189 | this.CurrentFps = ""; 190 | this.SettingFps = ""; 191 | this.ResultingFrameRate = ""; 192 | } 193 | 194 | /// 195 | /// 抓取图片 196 | /// 197 | public void GrabPicture() 198 | { 199 | _isSaveImage = true; 200 | } 201 | 202 | /// 203 | /// 修改帧率 204 | /// 205 | public void ModifyFps() 206 | { 207 | var isOk = HkCameraControl.MV_CC_SetFloatValue(_cameraHandel, "AcquisitionFrameRate", float.Parse(SettingFps)); 208 | if (isOk != 0) 209 | { 210 | Console.WriteLine($"设置帧率失败,错误码{isOk:x8}"); 211 | return; 212 | } 213 | 214 | GetFpsValue(); 215 | } 216 | 217 | [DependsOn(nameof(SettingFps))] 218 | public bool CanModifyFps(object _) 219 | { 220 | if (SettingFps == CurrentFps) return false; 221 | return float.TryParse(SettingFps, out var _); 222 | } 223 | 224 | /// 225 | /// 更改保存位置 226 | /// 227 | public async Task ChangeSavePath(Window window) 228 | { 229 | OpenFolderDialog dialog = new OpenFolderDialog(); 230 | var result = await dialog.ShowAsync(window); 231 | if(string.IsNullOrWhiteSpace(result)) return; 232 | 233 | this.ImageSavePath = result; 234 | } 235 | 236 | #endregion 237 | 238 | #region Private Methods 239 | 240 | // 初始化,获取相机列表等 241 | private void Init() 242 | { 243 | var isOk = HkCameraControl.MV_CC_EnumDevices((uint)DeviceLayerType.Gige, out var deviceList); 244 | 245 | if (isOk != 0) 246 | { 247 | Console.WriteLine($"请求出错,错误码{isOk:x8}"); 248 | return; 249 | } 250 | 251 | if (deviceList.DeviceNumber == 0) 252 | { 253 | Console.WriteLine($"没有可用设备"); 254 | return; 255 | } 256 | 257 | Console.WriteLine($"获取到{deviceList.DeviceNumber}个设备"); 258 | for (var i = 0; i < deviceList.DeviceNumber; i++) 259 | { 260 | Console.WriteLine($" 设备{i + 1}:"); 261 | 262 | var devicePtr = deviceList.DeviceInfos[i]; 263 | var device = Marshal.PtrToStructure(devicePtr); 264 | 265 | var deviceModel = Encoding.UTF8.GetString(device.GigEInfo.ModelName).Trim('\0'); 266 | Console.WriteLine($" 名称:{deviceModel}"); 267 | 268 | var deviceSerialNumber = Encoding.UTF8.GetString(device.GigEInfo.SerialNumber).Trim('\0'); 269 | Console.WriteLine($" 序列号:{deviceSerialNumber}"); 270 | 271 | var deviceVersion = Encoding.UTF8.GetString(device.GigEInfo.DeviceVersion); 272 | Console.WriteLine($" 版本:{deviceVersion}"); 273 | 274 | var ip1 = (device.GigEInfo.CurrentIp & 0xff000000) >> 24; 275 | var ip2 = (device.GigEInfo.CurrentIp & 0x00ff0000) >> 16; 276 | var ip3 = (device.GigEInfo.CurrentIp & 0x0000ff00) >> 8; 277 | var ip4 = device.GigEInfo.CurrentIp & 0x000000ff; 278 | Console.WriteLine($" 设备IP:{ip1}:{ip2}:{ip3}:{ip4}"); 279 | 280 | _cameraIntPtrDictionary.Add($"{deviceModel}({deviceSerialNumber})", devicePtr); 281 | CameraList.Add($"{deviceModel}({deviceSerialNumber})"); 282 | } 283 | 284 | // ReSharper disable once AccessToStaticMemberViaDerivedType 285 | if (App.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime) 286 | { 287 | lifetime.Exit += (_, _) => { Stop(); }; 288 | } 289 | } 290 | 291 | // 接收到图片,进行处理,保存 292 | private void OnReceiveImage(IntPtr dataPtr, IntPtr imageFrameInfoPtr, IntPtr userCustom) 293 | { 294 | if (!_isSaveImage) return; 295 | var frameInfo = Marshal.PtrToStructure(imageFrameInfoPtr); 296 | Console.WriteLine( 297 | $"{frameInfo.HostTimeStamp}获取到图像:{frameInfo.Width}x{frameInfo.Height},格式:{frameInfo.PixelFormatType}"); 298 | _isSaveImage = false; 299 | 300 | var bufferSize = frameInfo.Width * frameInfo.Height * 4 + 2048; 301 | 302 | // 创建Byte数组内存指针,用于接收图片数据 303 | var imageDataPtr = Marshal.AllocHGlobal(bufferSize); 304 | Marshal.WriteByte(imageDataPtr, 0); 305 | 306 | // 调用SDK进行图片转换 307 | var saveImageParams = new SaveImageParams 308 | { 309 | ImageData = dataPtr, 310 | DataLength = frameInfo.FrameLength, 311 | PixelFormatType = frameInfo.PixelFormatType, 312 | Width = frameInfo.Width, 313 | Height = frameInfo.Height, 314 | ImageType = ImageType.Jpeg, 315 | BufferSize = (uint)bufferSize, 316 | JpgQuality = 80, 317 | ImageBuffer = imageDataPtr 318 | }; 319 | var b = HkCameraControl.MV_CC_SaveImageEx2(_cameraHandel, ref saveImageParams); 320 | Console.WriteLine($"图片转换{b:x8}"); 321 | 322 | // 将内存指针中的图片数据拷贝到托管数组中 323 | var imageBytes = new byte[bufferSize]; 324 | Marshal.Copy(imageDataPtr, imageBytes, 0, bufferSize); 325 | 326 | // 释放自己创建的内存指针 327 | Marshal.FreeHGlobal(imageDataPtr); 328 | 329 | // 保存图片 330 | using var stream = new MemoryStream(imageBytes); 331 | var bitmap = Image.FromStream(stream); 332 | 333 | try 334 | { 335 | if (!Directory.Exists(ImageSavePath)) 336 | { 337 | Directory.CreateDirectory(ImageSavePath); 338 | } 339 | 340 | var dateTime = DateTimeOffset.FromUnixTimeMilliseconds(frameInfo.HostTimeStamp).LocalDateTime; 341 | bitmap?.Save(Path.Combine(ImageSavePath, $"{dateTime:yyyy-MM-dd HH:mm:ss}.jpg"), ImageFormat.Jpeg); 342 | 343 | Console.WriteLine($"保存完成"); 344 | } 345 | catch (Exception e) 346 | { 347 | Console.WriteLine(e); 348 | } 349 | } 350 | 351 | // 获取当前帧率 352 | private void GetFpsValue() 353 | { 354 | var isOk = HkCameraControl.MV_CC_GetFloatValue(_cameraHandel, "AcquisitionFrameRate", out var fpsSetting); 355 | if (isOk != 0) 356 | { 357 | Console.WriteLine($"获取失败,错误码{isOk:x8}"); 358 | return; 359 | } 360 | 361 | isOk = HkCameraControl.MV_CC_GetFloatValue(_cameraHandel, "ResultingFrameRate", out var resultingFrameRate); 362 | if (isOk != 0) 363 | { 364 | Console.WriteLine($"获取失败,错误码{isOk:x8}"); 365 | return; 366 | } 367 | 368 | this.CurrentFps = fpsSetting.CurrentValue.ToString("0.00"); 369 | this.SettingFps = fpsSetting.CurrentValue.ToString("0.00"); 370 | this.ResultingFrameRate = resultingFrameRate.CurrentValue.ToString("0.00"); 371 | } 372 | 373 | #endregion 374 | } -------------------------------------------------------------------------------- /Samples/MVSCameraDemo/CameraDemo/ViewModels/ViewModelBase.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | 3 | namespace CameraDemo.ViewModels; 4 | 5 | public class ViewModelBase : ReactiveObject 6 | { 7 | } -------------------------------------------------------------------------------- /Samples/MVSCameraDemo/CameraDemo/Views/MainWindow.axaml: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 |