Telerik DevCraft包含一個完整的產品棧來構建您下一個Web、移動和桌面應用程序。它使用HTML和每個.NET平臺的UI庫,加快開發速度。Telerik DevCraft提供完整的工具箱,用于構建現代和面向未來的業務應用程序,目前提供UI for ASP.NET MVC、Kendo UI、UI for ASP.NET AJAX、UI for WPF、UI for Xamarin、Reporting等眾多控件。
在這篇文章中,我們將演示如何在Telerik UI for WinForms應用程序中使用Kendo UI for Angular組件。您將了解其中的陷阱,以及如何從WinForms實現與Angular的通信,并從Angular獲取事件。
Telerik 2025 Q2最新正式版下載
有幾種情況可以應用此方法:
- 開始從傳統的WinForms應用程序遷移到Angular
- 本地資源集成(本地數據庫和其他WinForms資源)
- 在復雜的WinForms應用程序中構建輕量級UI應用程序
- 構建具有Web應用程序外觀和感覺的WinForms應用程序
- 執行在Docker、IIS或Cloud中運行的分布式UI
- 無需更新WinForms應用程序客戶端應用程序即可更新UI
這些來自遺留應用程序的轉換場景可以幫助您在開發新的服務/應用程序時使用激活的生產資源,混合解決方案可以保留當前的WinForms,同時授權開發人員構建客戶端應用程序。
在上文中(點擊這里回顧>>),我們為大家介紹了Kendo UI for Angular組件在WinForms應用中的深度嵌入的一些入門指南,本文將繼續介紹如何配置WinForms應用,請繼續關注喲~
配置WinForms應用
在WinForms應用程序中,我將主機組件WebView2隔離在一個用戶控件AngularWebControl上。因此,所有組件都具有相同的UserControl基礎并共享相同的操作。
WebView2是必需的,它可以從URL中保存Angular應用程序,并與WinForms交互。
這是C#項目中的解決方案文件,看起來像這樣:
AngularDefs.cs將Angular項目的定義放在一個地方。這也可以是環境變量,以避免硬編碼數據:
1. namespace app_winforsm;
2. internal static class AngularDefs
3. {
4. // URL of the Angular application
5. public const string Url = "https://aw.jsmotta.com/";
6.
7. // Route to the graph component
8. public const string RouteGraph = "graph-control";
9.
10. // Verb to receive data in the Angular component
11. public const string ChartVerb = "receiveData";
12. }
AngularWebControl.cs保存著接口的任務,我們在下面的代碼中添加了一些解釋。它定義組件的接口,讀取click事件,并將其傳遞給事件處理程序。
1. using Microsoft.Web.WebView2.Core;
2. using Microsoft.Web.WebView2.WinForms;
3. using System.Text.Json;
4. using Telerik.WinControls.UI;
5.
6. namespace app_winforsm;
7. internal partial class AngularWebControl : UserControl
8. {
9. // WebView Control
10. private WebView2? _webView;
11.
12. // Event to handle chart item click - it could be only OnItemClick
13. public event EventHandler? OnChartItemClick;
14.
15. // The data to be passed to the Angular component
16. private dynamic? Data { get; set; }
17.
18. // a label to show the title of the control
19. // in a real-world scenario, we can extend this component and add other controls
20. private RadLabel? Title { get; set; }
21.
22. public AngularWebControl()
23. {
24. InitializeComponent();
25. }
26. public async void LoadData(string title, dynamic data)
27. {
28. if (Title == null)
29. {
30. Title = new RadLabel
31. {
32. Text = title,
33. Dock = DockStyle.Top,
34. Width = this.Width,
35. AutoSize = true,
36. Font = new Font("Arial", 12, FontStyle.Bold),
37. ThemeName = "Windows11"
38. };
39.
40.
41. this.Controls.Add(Title);
42.
43. Title.MouseUp += Title_MouseUp;
44. }
45.
46. this.Title.Text = title;
47.
48. if (_webView == null)
49. {
50. _webView = new WebView2
51. {
52. Visible = true,
53. Dock = DockStyle.Fill
54. };
55.
56. this.Controls.Add(_webView);
57.
58. var userDataFolder1 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), $"AngularWinFormsApp_{this.Name}");
59.
60. var environment1 = await CoreWebView2Environment.CreateAsync(userDataFolder: userDataFolder1);
61.
62. // The environment is created to avoid loss of data in the session
63. await _webView.EnsureCoreWebView2Async(environment1);
64.
65.
66. _webView.CoreWebView2.NavigationCompleted += WebView_NavigationCompleted;
67.
68. // Event to receive data from Angular
69. _webView.CoreWebView2.WebMessageReceived += CoreWebView2_WebMessageReceived;
70.
71. _webView.CoreWebView2.Navigate($"{AngularDefs.Url}{AngularDefs.RouteGraph}");
72.
73. if (OnChartItemClick != null)
74. {
75. // This is the trick to receive data from the Angular component
76. await _webView.CoreWebView2.ExecuteScriptAsync(@"
77. window.addEventListener('MyClick', function(event) {
78. window.chrome.webview.postMessage(event.detail.message);
79. });
80. ");
81. }
82. }
83.
84. // Send the data to the Angular component
85. this.Data = data;
86. }
87.
88. private void Title_MouseUp(object? sender, MouseEventArgs e)
89. {
90. if (e.Button == MouseButtons.Right)
91. {
92. // An easter egg to show the WebView console
93. // when pressing right click on the RadLabel
94. ShowWebViewConsole();
95. }
96. }
97.
98. // Event handler to handle messages received from the WebView2
99. private void CoreWebView2_WebMessageReceived(object? sender, CoreWebView2WebMessageReceivedEventArgs e)
100. {
101. // Retrieve the message from the event
102. var message = e.TryGetWebMessageAsString();
103.
104. // Display the message or perform any action
105. OnChartItemClick?.Invoke(message, EventArgs.Empty);
106. }
107. private async void WebView_NavigationCompleted(object? sender, CoreWebView2NavigationCompletedEventArgs e)
108. {
109. if (_webView == null) return;
110.
111. _webView.Visible = true;
112.
113. if (!e.IsSuccess)
114. {
115. // Return a custom messsage based on the error to avoid default Webview error page
116. switch (e.WebErrorStatus)
117. {
118.
119. case CoreWebView2WebErrorStatus.ConnectionAborted:
120. ShowErrorMessage("Connection refused. Please make sure the server is running and try again.");
121. break;
122. case CoreWebView2WebErrorStatus.Unknown:
123. case CoreWebView2WebErrorStatus.CertificateCommonNameIsIncorrect:
124. case CoreWebView2WebErrorStatus.CertificateExpired:
125. case CoreWebView2WebErrorStatus.ClientCertificateContainsErrors:
126. case CoreWebView2WebErrorStatus.CertificateRevoked:
127. case CoreWebView2WebErrorStatus.CertificateIsInvalid:
128. case CoreWebView2WebErrorStatus.ServerUnreachable:
129. case CoreWebView2WebErrorStatus.Timeout:
130. case CoreWebView2WebErrorStatus.ErrorHttpInvalidServerResponse:
131. case CoreWebView2WebErrorStatus.ConnectionReset:
132. case CoreWebView2WebErrorStatus.Disconnected:
133. case CoreWebView2WebErrorStatus.CannotConnect:
134. case CoreWebView2WebErrorStatus.HostNameNotResolved:
135. case CoreWebView2WebErrorStatus.OperationCanceled:
136. case CoreWebView2WebErrorStatus.RedirectFailed:
137. case CoreWebView2WebErrorStatus.UnexpectedError:
138. case CoreWebView2WebErrorStatus.ValidAuthenticationCredentialsRequired:
139. case CoreWebView2WebErrorStatus.ValidProxyAuthenticationRequired:
140. default:
141. ShowErrorMessage("An error occurred while loading the page.");
142. break;
143. }
144. return;
145. }
146.
147. var jsonData = JsonSerializer.Serialize(Data);
148.
149. // Here is the connection with the interface (verb) defined in the Angular component
150. var script = $"window.{AngularDefs.ChartVerb}({jsonData});";
151.
152. await _webView.CoreWebView2.ExecuteScriptAsync(script);
153. }
154.
155. }
Message.cs是Angular應用中click事件交互的模型。
下面是FormMain.cs中控件的用例,我們動態地添加了一個控件,并使用工具箱中的拖放功能添加了另一個控件。需要注意的是,需要一個不同的屬性名來避免WebView2會話上的沖突,這是一個陷阱。
在這個示例中使用模擬數據,但您可能會在實際應用程序中從數據源讀取數據。
1. using System.Text.Json;
2. using Telerik.WinControls;
3. using Telerik.WinControls.UI;
4.
5. namespace app_winforsm;
6.
7. public partial class FormMain : RadForm
8. {
9. private readonly AngularWebControl? _angularWebControl;
10.
11. public FormMain()
12. {
13. InitializeComponent();
14.
15. // Load the AngularWebControl programatically
16.
17. _angularWebControl = new AngularWebControl { Name = "_angularWebControl" };
18. _angularWebControl.Dock = DockStyle.Fill;
19.
20. splitPanel1.Controls.Add(_angularWebControl);
21.
22. // Subscribe to the OnChartItemClick event
23. _angularWebControl.OnChartItemClick += AngularWebControl_OnChartItemClick;
24.
25. LoadData();
26. }
27.
28. private void AngularWebControl_OnChartItemClick(object? sender, EventArgs e)
29. {
30. if (sender is null)
31. return;
32.
33. var message =
34. JsonSerializer.Deserialize<Message>(sender.ToString() ?? throw new Exception("Data is not a json."));
35.
36. RadMessageBox.ThemeName = "Windows11";
37. RadMessageBox.Show($"You clicked on {message.Category} with value {message.Value}", "Chart Item Clicked",
38. MessageBoxButtons.OK, RadMessageIcon.Info);
39. }
40.
41. private void LoadData()
42. {
注意:在生產項目中,您將從存儲庫加載數據!
43.
44. var data = new[]
45. {
46. new { name = "Gastroenteritis", value = 40, color = "red" },
47. new { name = "Appendicitis", value = 25, color = "blue" },
48. new { name = "Cholecystitis", value = 15, color = "green" },
49. new { name = "Pancreatitis", value = 10, color = "yellow" },
50. new { name = "Diverticulitis", value = 10, color = "orange" }
51. };
52.
53. _angularWebControl?.LoadData("Common gastro deseases in hospitals", data);
54.
55. var dataAges = new[]
56. {
57. new { name = "0-10", value = 1, color = "red" },
58. new { name = "11-20", value = 10, color = "blue" },
59. new { name = "21-30", value = 20, color = "green" },
60. new { name = "31-40", value = 25, color = "yellow" },
61. new { name = "41-50", value = 15, color = "orange" },
62. new { name = "51-60", value = 20, color = "purple" },
63. new { name = "61-70", value = 8, color = "brown" },
64. new { name = "71+", value = 7, color = "pink" }
65. };
66.
67. this.angularWebControl1.LoadData("Patiant ages in gastro deseases", dataAges);
68. }
69. }
結果
這兩個圖表共享相同的界面和UserControl,它們處于不同的web會話中。會話被隔離是為了保存數據,并且出于安全考慮,同一個UserControl可以根據作為參數傳遞的URL使用不同的憑據。
本示例的工作流程
在下面的圖片中,我們可以“看到”編碼的流程和執行,直到回調時,最終用戶點擊圖表,從GitHub下載源代碼并嘗試。
關于慧都科技
慧都是?家?業數字化解決?案公司,專注于軟件、?油與?業領域,以深?的業務理解和?業經驗,幫助企業實現智能化轉型與持續競爭優勢。
慧都科技是Telerik的中國區的合作伙伴,Telerik作為用戶界面領域的優秀產品,通過全棧式開發工具套件(涵蓋Web、桌面、移動端及報表服務)提供160+高性能UI組件、低代碼平臺及實時調試工具,助力企業快速構建跨平臺業務應用(如ERP、數據分析儀表盤),顯著縮短開發周期(降本50%以上)并提升數據處理與界面交互效率。