-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdescription.html
454 lines (431 loc) · 26.7 KB
/
description.html
1
2
3
4
5
6
7
8
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head><link rel="stylesheet" type="text/css" href="description/Combined.css,0:HeaderFooterSprite,0:Header.NonMtps,1:LinkList;/Areas/Centers/Themes/StandardDevCenter/Content:0,/Areas/Epx/Themes/Base/Content:1&amp;hashKey=EC831D2F780A53CF4C404B53E768954F" xmlns="http://www.w3.org/1999/xhtml" />
<link type="text/css" rel="stylesheet" xmlns="http://www.w3.org/1999/xhtml" />
<link rel="stylesheet" type="text/css" href="description/f44a91af-115c-4857-966c-8e008bf674fdCombined.css,0:HeaderFooterSprite,0:Footer.NonMtps,1:LinkList;/Areas/Centers/Themes/StandardDevCenter/Content:0,/Areas/Epx/Themes/Base/Content:1&amp;hashKey=DF234F4FF3DA5D35A03D2829D4F99E0D" xmlns="http://www.w3.org/1999/xhtml" />
<link type="text/css" rel="stylesheet" xmlns="http://www.w3.org/1999/xhtml" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Using SignalR in WinForms and WPF</title>
<link href="description/Galleries.css" type="text/css" rel="Stylesheet" /><link href="description/Layout.css" type="text/css" rel="Stylesheet" /><link href="description/Brand.css" type="text/css" rel="Stylesheet" />
<link href="description/iframedescription.css" rel="Stylesheet" type="text/css" />
<script src="description/offline.js" type="text/javascript"></script>
<style type="text/css">
#projectInfo {
overflow: auto;
}
#longDesc {
clear:both;
margin: 25px 0 10px 0;
}
#SampleIndexList{
margin-left: 15px;
}
</style>
</head>
<body>
<div id="offlineDescription">
<h1>Using SignalR in WinForms and WPF</h1>
<br/>
<div id="projectInfo">
<div class="section">
<div class="itemBarLong tagsContainer">
<label for="Technologies">Technologies</label>
<div id="Technologies">
WPF, WinForms, ASP.NET SignalR
</div>
</div>
<div class="itemBarLong tagsContainer">
<label for="Topics">Topics</label>
<div id="Topics">
SignalR clients and servers in WinForms and WPF
</div>
</div>
<div class="itemBarLong">
<label for="Platforms">Platforms</label>
<div id="Platforms">
Desktop, Web
</div>
</div>
<div class="itemBarLong">
<label for="Requirements">Requirements</label>
<div id="Requirements">
</div>
</div>
<div class="itemBar">
<label for="LastUpdated">Primary language</label>
<div id="LastUpdated">en-US</div>
</div>
<div class="itemBar">
<label for="LastUpdated">Updated</label>
<div id="LastUpdated">7/11/2014</div>
</div>
<div class="itemBarLong">
<label for="License">License</label>
<div id="License">
<a href="license.rtf">Apache License, Version 2.0</a></div>
</div>
<div class="itemBar">
<div class="viewonlinecont">
<a data-link="online" href="http://code.msdn.microsoft.com/Using-SignalR-in-WinForms-f1ec847b">View this sample online</a>
</div>
</div>
</div>
</div>
<script type="text/javascript">
function initializePage() {
var otherTabClass = 'otherTab';
var hiddenPreClass = 'hidden';
var htmlDecode = function(encodedData) {
var decodedData = "";
if (encodedData) {
var div = document.createElement('div');
div.innerHTML = encodedData;
decodedData = div.firstChild.nodeValue.replace( /\\r\\n/ig , '\r\n');
}
return decodedData;
};
Galleries.iterateElem(Galleries.findElem(null, 'div', 'scriptcode'), function (index, scriptBlock) {
var titleElem = Galleries.findElem(scriptBlock, 'div', 'title')[0];
var labelElems = Galleries.findElem(titleElem, 'span');
if (labelElems.length == 0) {
labelElems = titleElem;
}
var languageSpans = Galleries.findElem(scriptBlock, 'span', 'hidden');
var pres = Galleries.findElem(scriptBlock, 'pre');
if (languageSpans.length > 0 && pres.length > 1) {
Galleries.iterateElem(labelElems, function(index, elem) {
var codePre = pres[index];
var labelSpan = elem;
var languageSpan = languageSpans[index];
elem.code = codePre.innerHTML.replace( /(\r(\n)?)|((\r)?\n)/ig , '\\r\\n');
codePre.className = codePre.className.replace(hiddenPreClass, '');
languageSpan.parentNode.removeChild(languageSpan);
});
pres = Galleries.findElem(scriptBlock, 'pre');
Galleries.iterateElem(labelElems, function(index, elem) {
var codePre = pres[index];
var labelSpan = elem;
if (index == 0) {
scriptBlock.activeTab = 0;
}
else {
labelSpan.className += otherTabClass;
codePre.className += hiddenPreClass;
}
Galleries.attachEventHandler(labelSpan, 'click', function(e) {
var activeTab = scriptBlock.activeTab;
labelElems[activeTab].className += otherTabClass;
pres[activeTab].className += hiddenPreClass;
codePre.className = codePre.className.replace(hiddenPreClass, '');
labelSpan.className = labelSpan.className.replace(otherTabClass, '');
scriptBlock.activeTab = index;
});
});
var preview = Galleries.findElem(scriptBlock, 'div', 'preview');
if (preview.length == 0) {
preview.push(pres[pres.length - 1]);
}
Galleries.iterateElem(preview, function(index, elem) {
elem.parentNode.removeChild(elem);
});
if (window.clipboardData && clipboardData.setData) {
var copyLink = document.createElement('a');
copyLink.href = 'javascript:void(0);';
copyLink.className = 'copyCode';
copyLink.innerHTML = 'Copy code';
Galleries.attachEventHandler(copyLink, 'click', function (e) {
clipboardData.setData("Text", htmlDecode(labelElems[scriptBlock.activeTab].code));
return false;
});
scriptBlock.insertBefore(copyLink, scriptBlock.childNodes[0]);
}
}
});
}
Galleries.onWindowLoad(function(){
initializePage();
});
</script>
<div id="longDesc">
<h1>Introduction</h1>
<p><em>This sample shows how to create a SignalR server and client in WinForms and WPF. A Web client is also included. The application shows how to start and connect to the SignalR service without blocking the UI thread, and how to update the UI in response
to messages and connection events.</em></p>
<h1><span>Building the Sample</span></h1>
<ul>
<li><em>Build the application (Ctrl+Shift+B). The package manager will add the SignalR self-host package to the server projects, the SignalR JavaScript client package (in the Scripts directory) to the web client project, and the SignalR .NET client package
to the WinForms and WPF client projects. The solution may prompt you to download the missing NuGet packages.</em>
</li></ul>
<ul>
<li><em>Run the application. In either the WinForms or WPF server, click <strong>
Start</strong> to start the SignalR service (Starting both servers will throw an error). After the server starts (in about 10 seconds), enter a username in the WinForms and WPF clients and click Connect, and refresh the page in the JavaScript client (and
provide a user name when prompted) to connect. </em> </li><li><em>Once servers are started and clients are connected, messages sent from one client will appear in all connected clients.</em>
</li></ul>
<p><span style="font-size:20px; font-weight:bold">Description</span></p>
<p><span style="font-size:20px; font-weight:bold"> </span><em>This sample contains five projects: Two server projects (WinForms and WPF), and three client projects (WinForms, WPF, and a JavaScript web client.)</em></p>
<p><em>The following code sample shows how to start a server asynchronously in WinForms and WPF: </em></p>
<div class="scriptcode">
<div class="pluginEditHolder" pluginCommand="mceScriptCode">
<div class="title"><span>C#</span></div>
<div class="pluginLinkHolder"><span class="pluginEditHolderLink">Edit</span>|<span class="pluginRemoveHolderLink">Remove</span></div>
<span class="hidden">csharp</span>
<pre class="hidden">/// <summary>
/// Calls the StartServer method with Task.Run to
/// not block the UI thread.
/// </summary>
private void ButtonStart_Click(object sender, EventArgs e)
{
WriteToConsole("Starting server...");
ButtonStart.Enabled = false;
Task.Run(() => StartServer());
}
/// <summary>
/// Starts the server and checks for error thrown
/// when another server is already
/// running. This method is called asynchronously
/// from Button_Start.
/// </summary>
private void StartServer()
{
try
{
SignalR = WebApp.Start(ServerURI);
}
catch (TargetInvocationException)
{
WriteToConsole("Server failed to start. A server is already running on " + ServerURI);
//Re-enable button to let user try
//to start server again
this.Invoke((Action)(() => ButtonStart.Enabled = true));
return;
}
this.Invoke((Action)(() => ButtonStop.Enabled = true));
WriteToConsole("Server started at " + ServerURI);
}</pre>
<div class="preview">
<pre class="csharp"><span class="cs__com">/// <summary></span>
<span class="cs__com">/// Calls the StartServer method with Task.Run to </span>
<span class="cs__com">/// not block the UI thread. </span>
<span class="cs__com">/// </summary></span>
<span class="cs__keyword">private</span> <span class="cs__keyword">void</span> ButtonStart_Click(<span class="cs__keyword">object</span> sender, EventArgs e)
{
WriteToConsole(<span class="cs__string">"Starting server..."</span>);
ButtonStart.Enabled = <span class="cs__keyword">false</span>;
Task.Run(() => StartServer());
}
<span class="cs__com">/// <summary></span>
<span class="cs__com">/// Starts the server and checks for error thrown </span>
<span class="cs__com">/// when another server is already </span>
<span class="cs__com">/// running. This method is called asynchronously </span>
<span class="cs__com">/// from Button_Start.</span>
<span class="cs__com">/// </summary></span>
<span class="cs__keyword">private</span> <span class="cs__keyword">void</span> StartServer()
{
<span class="cs__keyword">try</span>
{
SignalR = WebApp.Start(ServerURI);
}
<span class="cs__keyword">catch</span> (TargetInvocationException)
{
WriteToConsole(<span class="cs__string">"Server failed to start. A server is already running on "</span> + ServerURI);
<span class="cs__com">//Re-enable button to let user try </span>
<span class="cs__com">//to start server again</span>
<span class="cs__keyword">this</span>.Invoke((Action)(() => ButtonStart.Enabled = <span class="cs__keyword">true</span>));
<span class="cs__keyword">return</span>;
}
<span class="cs__keyword">this</span>.Invoke((Action)(() => ButtonStop.Enabled = <span class="cs__keyword">true</span>));
WriteToConsole(<span class="cs__string">"Server started at "</span> + ServerURI);
}</pre>
</div>
</div>
</div>
<p><em>The following code sample shows how to handle server events in WinForms:</em><em> </em><em> </em></p>
<div class="scriptcode">
<div class="pluginEditHolder" pluginCommand="mceScriptCode">
<div class="title"><span>C#</span></div>
<div class="pluginLinkHolder"><span class="pluginEditHolderLink">Edit</span>|<span class="pluginRemoveHolderLink">Remove</span></div>
<span class="hidden">csharp</span>
<pre class="hidden">/// <summary>
/// Echoes messages sent using the Send message by calling the
/// addMessage method on the client. Also reports to the console
/// when clients connect and disconnect.
/// </summary>
public class MyHub : Hub
{
public void Send(string name, string message)
{
Clients.All.addMessage(name, message);
}
public override Task OnConnected()
{
Program.MainForm.WriteToConsole("Client connected: " + Context.ConnectionId);
return base.OnConnected();
}
public override Task OnDisconnected()
{
Program.MainForm.WriteToConsole("Client disconnected: " + Context.ConnectionId);
return base.OnDisconnected();
}
}</pre>
<div class="preview">
<pre class="csharp"><span class="cs__com">/// <summary></span>
<span class="cs__com">/// Echoes messages sent using the Send message by calling the</span>
<span class="cs__com">/// addMessage method on the client. Also reports to the console</span>
<span class="cs__com">/// when clients connect and disconnect.</span>
<span class="cs__com">/// </summary></span>
<span class="cs__keyword">public</span> <span class="cs__keyword">class</span> MyHub : Hub
{
<span class="cs__keyword">public</span> <span class="cs__keyword">void</span> Send(<span class="cs__keyword">string</span> name, <span class="cs__keyword">string</span> message)
{
Clients.All.addMessage(name, message);
}
<span class="cs__keyword">public</span> <span class="cs__keyword">override</span> Task OnConnected()
{
Program.MainForm.WriteToConsole(<span class="cs__string">"Client connected: "</span> + Context.ConnectionId);
<span class="cs__keyword">return</span> <span class="cs__keyword">base</span>.OnConnected();
}
<span class="cs__keyword">public</span> <span class="cs__keyword">override</span> Task OnDisconnected()
{
Program.MainForm.WriteToConsole(<span class="cs__string">"Client disconnected: "</span> + Context.ConnectionId);
<span class="cs__keyword">return</span> <span class="cs__keyword">base</span>.OnDisconnected();
}
}</pre>
</div>
</div>
</div>
<p><em> </em><em>The following code sample shows how to handle server events in WPF:</em><em> </em><em> </em></p>
<div class="scriptcode">
<div class="pluginEditHolder" pluginCommand="mceScriptCode">
<div class="title"><span>C#</span></div>
<div class="pluginLinkHolder"><span class="pluginEditHolderLink">Edit</span>|<span class="pluginRemoveHolderLink">Remove</span></div>
<span class="hidden">csharp</span>
<pre class="hidden">/// <summary>
/// Echoes messages sent using the Send message by calling the
/// addMessage method on the client. Also reports to the console
/// when clients connect and disconnect.
/// </summary>
public class MyHub : Hub
{
public void Send(string name, string message)
{
Clients.All.addMessage(name, message);
}
public override Task OnConnected()
{
//Use Application.Current.Dispatcher to access UI thread from outside the MainWindow class
Application.Current.Dispatcher.Invoke(() =>
((MainWindow)Application.Current.MainWindow).WriteToConsole(
"Client connected: " + Context.ConnectionId));
return base.OnConnected();
}
public override Task OnDisconnected()
{
//Use Application.Current.Dispatcher to access UI thread from outside the MainWindow class
Application.Current.Dispatcher.Invoke(() =>
((MainWindow)Application.Current.MainWindow).WriteToConsole(
"Client disconnected: " + Context.ConnectionId));
return base.OnDisconnected();
}
}</pre>
<div class="preview">
<pre class="csharp"><span class="cs__com">/// <summary></span>
<span class="cs__com">/// Echoes messages sent using the Send message by calling the</span>
<span class="cs__com">/// addMessage method on the client. Also reports to the console</span>
<span class="cs__com">/// when clients connect and disconnect.</span>
<span class="cs__com">/// </summary></span>
<span class="cs__keyword">public</span> <span class="cs__keyword">class</span> MyHub : Hub
{
<span class="cs__keyword">public</span> <span class="cs__keyword">void</span> Send(<span class="cs__keyword">string</span> name, <span class="cs__keyword">string</span> message)
{
Clients.All.addMessage(name, message);
}
<span class="cs__keyword">public</span> <span class="cs__keyword">override</span> Task OnConnected()
{
<span class="cs__com">//Use Application.Current.Dispatcher to access UI thread from outside the MainWindow class</span>
Application.Current.Dispatcher.Invoke(() =>
((MainWindow)Application.Current.MainWindow).WriteToConsole(
<span class="cs__string">"Client connected: "</span> + Context.ConnectionId));
<span class="cs__keyword">return</span> <span class="cs__keyword">base</span>.OnConnected();
}
<span class="cs__keyword">public</span> <span class="cs__keyword">override</span> Task OnDisconnected()
{
<span class="cs__com">//Use Application.Current.Dispatcher to access UI thread from outside the MainWindow class</span>
Application.Current.Dispatcher.Invoke(() =>
((MainWindow)Application.Current.MainWindow).WriteToConsole(
<span class="cs__string">"Client disconnected: "</span> + Context.ConnectionId));
<span class="cs__keyword">return</span> <span class="cs__keyword">base</span>.OnDisconnected();
}
}</pre>
</div>
</div>
</div>
<p><em> </em><em>The following code sample shows how to handle incoming messages in a SignalR client in WinForms:</em></p>
<div class="endscriptcode">
<div class="scriptcode">
<div class="pluginEditHolder" pluginCommand="mceScriptCode">
<div class="title">C#</div>
<div class="pluginLinkHolder"><span class="pluginEditHolderLink">Edit</span>|<span class="pluginRemoveHolderLink">Remove</span></div>
<span class="hidden">csharp</span>
<pre class="hidden">//Handle incoming event from server: use Invoke to write to console from SignalR's thread
HubProxy.On<string, string>("AddMessage", (name, message) =>
this.Invoke((Action)(() =>
RichTextBoxConsole.AppendText(
String.Format({0}: {1}" + Environment.NewLine, name, message))
))
);</pre>
<div class="preview">
<pre class="csharp"><span class="cs__com">//Handle incoming event from server: use Invoke to write to console from SignalR's thread</span>
HubProxy.On<<span class="cs__keyword">string</span>, <span class="cs__keyword">string</span>>(<span class="cs__string">"AddMessage"</span>, (name, message) =>
<span class="cs__keyword">this</span>.Invoke((Action)(() =>
RichTextBoxConsole.AppendText(
String.Format({<span class="cs__number">0</span>}: {<span class="cs__number">1</span>}" + Environment.NewLine, name, message))
))
);</pre>
</div>
</div>
</div>
<div class="endscriptcode"> <em>The following code sample shows how to handle incoming messages in a SignalR client in WPF</em>:</div>
<div class="endscriptcode">
<div class="scriptcode">
<div class="pluginEditHolder" pluginCommand="mceScriptCode">
<div class="title">C#</div>
<div class="pluginLinkHolder"><span class="pluginEditHolderLink">Edit</span>|<span class="pluginRemoveHolderLink">Remove</span></div>
<span class="hidden">csharp</span>
<pre class="hidden">//Handle incoming event from server: use Invoke to write to console from SignalR's thread
HubProxy.On<string, string>("AddMessage", (name, message) =>
this.Dispatcher.Invoke(() =>
RichTextBoxConsole.AppendText(String.Format("{0}: {1}\r", name, message))
)
);</pre>
<div class="preview">
<pre class="csharp"><span class="cs__com">//Handle incoming event from server: use Invoke to write to console from SignalR's thread</span>
HubProxy.On<<span class="cs__keyword">string</span>, <span class="cs__keyword">string</span>>(<span class="cs__string">"AddMessage"</span>, (name, message) =>
<span class="cs__keyword">this</span>.Dispatcher.Invoke(() =>
RichTextBoxConsole.AppendText(String.Format(<span class="cs__string">"{0}: {1}\r"</span>, name, message))
)
);</pre>
</div>
</div>
</div>
</div>
<div class="endscriptcode">
<div class="endscriptcode"></div>
</div>
<em>
<div class="endscriptcode">
<div class="endscriptcode"><span style="font-size:2em">Source Code Files</span></div>
</div>
</em></div>
<ul>
<li><em>WebClient/Default.html: The web client (this is the same client as is used in the Getting Started tutorial). </em>
</li><li><em>WinFormsClient/WinFormsClient.cs: The WinForms client, showing how to connect to a SignalR service asynchronously, and how to access UI controls from SignalR events.</em>
</li><li><em>WinFormsServer/WinFormsServer.cs: The WinForms server, showing how to start a SignalR service asynchronously, and how to access UI controls when SignalR messages arrive.</em>
</li><li><em>WPFClient/MainWindow.xaml.cs: The WPF client, <em>showing how to connect to a SignalR service asynchronously, and how to access UI controls from SignalR events.</em></em>
</li><li><em><em>WPFServer/MainWindow.xaml.cs: <em>The WPF server, showing how to start a SignalR service asynchronously, and how to access UI controls when SignalR messages arrive.</em></em></em>
</li></ul>
</div>
</div>
</body>
</html>