Traduction▲
Cet article est la traduction la plus fidèle possible de l'article original de Brad Abrams, Business Apps Example for Silverlight 3 RTM and .NET RIA Services July Update: Part 14: Visual Basic (VB) and WPF Support.
Support de Visual Basic (VB) et de WPF▲
Certains ont dit qu'ils aimeraient voir quelque chose dans ma série mettant à jour ma session Mix09 de « building business applications with Silverlight 3 » en Visual Basic. VB est « super » important dans le champ des applications métier, je n'ai donc aucun problème à satisfaire cette demande. Pendant que j'étais occupé à cela, j'ai pensé que je montrerais également un client WPF pour RIA Services au travers du très sympa support d'ADO.NET Data Services que nous avons. Ça ressemble plus au support WinForms que j'ai montré plutôt.
Cette démo nécessite (tout est 100% gratuit et pour toujours) :
- VS2008 SP1
- Silverlight 3 RTM
- .NET RIA Services July '09 Preview <--- N'est en réalité pas nécessaire pour cette démo ! Mais c'est néanmoins bien de le savoir ;-)
Téléchargez ensuite l'ensemble des fichiers des démos (lien sur le site original - lien sur developpez.com).
Vous pouvez voir la série complète ici.
Dans la partie 1 : Les bases de la navigation, il n'y a absolument aucun code, donc la version VB ressemble exactement à ce que j'ai posté.
Dans la partie 2 : Righ Data Query, il y a quelques brides de code supplémentaires intéressantes. Premièrement, regardons au DomainService.
<
EnableClientAccess
(
)>
_
2
:
Public
Class
SuperEmployeeDomainService
3
:
Inherits LinqToEntitiesDomainService
(
Of NORTHWNDEntities)
4
:
5
:
Public
Function
GetSuperEmployees
(
) As
IQueryable
(
Of SuperEmployee)
6
:
Dim
q =
From emp In
Me.Context.SuperEmployeeSet
_
7
:
Where emp.Issues
>
100
_
8
:
Order By emp.EmployeeID
9
:
Return q
10
:
End
Function
11
:
12
:
13
:
Public
Sub
UpdateSuperEmployee
(
ByVal
currentSuperEmployee As
SuperEmployee)
14
:
Me.Context.AttachAsModified
(
currentSuperEmployee, Me.ChangeSet.GetOriginal
(
currentSuperEmployee))
15
:
End
Sub
16
:
Public
Sub
InsertSuperEmployee
(
ByVal
superEmployee As
SuperEmployee)
17
:
Me.Context.AddToSuperEmployeeSet
(
superEmployee)
18
:
End
Sub
Ici, nous définissons les méthodes de requêtes, mise à jour et insertion.
Après pour mettre en valeur certains de nos supports POCO, j'ai créé une méthode qui retourne les comptes originaux
Public
Function
GetOrigins
(
) As
IQueryable
(
Of Origin)
Dim
q =
(
From emp In
Context.SuperEmployeeSet
_
Select
emp.Origin
).Distinct
(
).Select
(
Function
(
name) New
Origin With
{.Name
=
name, .Count
=
Context.SuperEmployeeSet.Count
(
Function
(
emp) emp.Origin.Trim
(
) =
name.Trim
(
))})
q =
q.Where
(
Function
(
emp) emp.Name
IsNot Nothing
)
Return q
End
Function
Et j'ai défini une classe POCO pour retourner ces données au client dans ma fenêtre AutoComplete
Public
Class
Origin
Public
Sub
New
(
)
End
Sub
Private
_Name As
String
<
Key
(
)>
_
Public
Property
Name
(
) As
String
Get
Return _Name
End
Get
Set
(
ByVal
value As
String
)
_Name =
value
End
Set
End
Property
Private
_Count As
Integer
Public
Property
Count
(
) As
Integer
Get
Return _Count
End
Get
Set
(
ByVal
value As
Integer
)
_Count =
value
End
Set
End
Property
End
Class
Du côté client dans le projet Silverlight, je finis par faire la plupart des choses au travers de liaisons dans Xaml, donc celles-ci sont exactement les mêmes en VB. Mais j'ai créé un AddNewEmployee ChildWindow.
Partial Public
Class
AddNewWindow
Inherits ChildWindow
Private
_NewEmployee As
SuperEmployee
Public
Property
NewEmployee
(
) As
SuperEmployee
Get
Return _NewEmployee
End
Get
Set
(
ByVal
value As
SuperEmployee)
_NewEmployee =
value
End
Set
End
Property
Public
Sub
New
(
)
InitializeComponent
(
)
NewEmployee =
New
SuperEmployee
(
)
NewEmployee.LastEdit
=
DateTime.Now.
[Date
]
Me.newEmployeeForm.CurrentItem
=
NewEmployee
End
Sub
Private
Sub
OKButton_Click
(
ByVal
sender As
Object, ByVal
e As
RoutedEventArgs)
newEmployeeForm.CommitEdit
(
)
Me.DialogResult
=
True
End
Sub
Private
Sub
CancelButton_Click
(
ByVal
sender As
Object, ByVal
e As
RoutedEventArgs)
Me.DialogResult
=
False
End
Sub
End
Class
Et ensuite nous lançons juste cet évènement
Private
Sub
AddNew_Click
(
ByVal
sender As
System.Object
, ByVal
e As
System.Windows.RoutedEventArgs
)
Dim
w =
New
AddNewWindow
(
)
AddHandler w.Closed
, AddressOf addNewWindow_Closed
w.Show
(
)
End
Sub
Private
Sub
addNewWindow_Closed
(
ByVal
sender As
Object, ByVal
e As
EventArgs)
Dim
win =
TryCast
(
sender, AddNewWindow)
Dim
context =
TryCast
(
dds.DomainContext
, SuperEmployeeDomainContext)
If
win.DialogResult
=
True
Then
context.SuperEmployees.Add
(
win.NewEmployee
)
End
If
End
Sub
Partie 3 : Authentification - absolument aucun code ici… C'est exactement pareil entre VB et C#.
Partie 4 : SEO, export vers Excel et prise en charge hors navigateur
Pour SEO, nous avons activé un lien en profondeur en maintenant plusieurs évènements…
'Executes when the user navigates to this page.
Protected
Overrides Sub
OnNavigatedTo
(
ByVal
e As
System.Windows.Navigation.NavigationEventArgs
)
Dim
qs =
NavigationContext.QueryString
If
qs.ContainsKey
(
"EmpId"
) Then
dds.FilterDescriptors.Add
(
New
FilterDescriptor
(
"EmployeeID"
, FilterOperator.IsEqualTo
, qs
(
"EmpId"
)))
End
If
End
Sub
Et
Private
Sub
dataGrid1_SelectionChanged
(
ByVal
sender As
System.Object
, ByVal
e As
System.Windows.Controls.SelectionChangedEventArgs
)
Dim
emp =
TryCast
(
dataGrid1.SelectedItem
, SuperEmployee)
If
emp IsNot Nothing
Then
PermalinkTextBox.Text
=
(
Application.Current.Host.Source.ToString
(
).Replace
(
"ClientBin/MyApp.xap"
, ""
) &
"#/Home?EmpId="
) &
emp.EmployeeID
End
If
End
Sub
Le code côté serveur pour Sitemap.aspx et le contenu alternatif dans default.aspx est identique.. Excepté pour une petite partie du code de réécriture d'URL dans default.aspx to s'assurer que le serveur et le client ont tous les deux accès au lien.
Protected
Sub
Page_Load
(
ByVal
sender As
Object, ByVal
e As
System.EventArgs
) Handles Me.Load
Dim
empId As
String
=
Request
.QueryString
(
"EmpId"
)
Dim
deepLink =
"/Home?EmpId="
&
empId
If
empId IsNot Nothing
Then
Response
.Write
(
"<script type=text/javascript>window.location.hash='#"
&
deepLink &
"';</script>"
)
End
If
End
Sub
La partie sur l'export vers Excel est super facile également..
Private
Sub
ExportToExcel_Click
(
ByVal
sender As
System.Object
, ByVal
e As
System.Windows.RoutedEventArgs
)
Dim
context =
TryCast
(
dds.DomainContext
, SuperEmployeeDomainContext)
Dim
s =
Application.GetResourceStream
(
New
Uri
(
"excelTemplate.txt"
, UriKind.Relative
))
Dim
dialog =
New
SaveFileDialog
(
)
dialog.DefaultExt
=
"*.xml"
dialog.Filter
=
"Excel Xml (*.xml)|*.xml|All files (*.*)|*.*"
If
dialog.ShowDialog
(
) =
False
Then
Exit
Sub
End
If
Using sw =
New
StreamWriter
(
dialog.OpenFile
(
))
Dim
sr =
New
StreamReader
(
s.Stream
)
While
Not
sr.EndOfStream
Dim
line =
sr.ReadLine
(
)
If
line =
"***"
Then
Exit
While
End
If
sw.WriteLine
(
line)
End
While
For
Each
emp In
context.SuperEmployees
sw.WriteLine
(
"<Row>"
)
sw.WriteLine
(
"<Cell><Data ss:Type=""String"">{0}</Data></Cell>"
, emp.Name
)
sw.WriteLine
(
"<Cell><Data ss:Type=""String"">{0}</Data></Cell>"
, emp.Origin
)
sw.WriteLine
(
"<Cell><Data ss:Type=""String"">{0}</Data></Cell>"
, emp.Publishers
)
sw.WriteLine
(
"<Cell><Data ss:Type=""Number"">{0}</Data></Cell>"
, emp.Issues
)
sw.WriteLine
(
"</Row>"
)
Next
While
Not
sr.EndOfStream
sw.WriteLine
(
sr.ReadLine
(
))
End
While
End
Using
End
Sub
Après un petit peu de formatage… nous obtenons :
Pour finir, dans la partie 5 : Astoria, Ajouter une référence Service et WinForms… Définir l'ADO.NET Data Services dans le projet web ressemble à :
Public
Class
SuperEmployeeWebDataService
Inherits DataService
(
Of [SuperEmployeeDomainService])
Implements IServiceProvider
' This method is called only once to initialize service-wide policies.
Public
Shared Sub
InitializeService
(
ByVal
config As
IDataServiceConfiguration)
' TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
' Examples:
config.SetEntitySetAccessRule
(
"*"
, EntitySetRights.All
)
config.SetServiceOperationAccessRule
(
"*"
, ServiceOperationRights.All
)
End
Sub
Après pour d'autres cas, j'ai créé un client WPF pour ce service. J'ai également utilisé le contrôle DataGrid du très chouette WPF Control Toolkit.
Tout d'abord, je charge les données…
Private
Sub
LoadButton_Click
(
ByVal
sender As
System.Object
, ByVal
e As
System.Windows.RoutedEventArgs
) Handles LoadButton.Click
Context =
New
SuperEmployeeDomainService
(
_
New
Uri
(
"http://localhost:4558/SuperEmployeeWebDataService.svc/"
))
Context.MergeOption
=
MergeOption.AppendOnly
Dim
q =
From emp In
Context.SuperEmployee
_
Where emp.Issues
>
10
_
Order By emp.Name
_
Select
emp
Dim
savedCursor =
Cursor
Cursor =
Cursors.Wait
Me.DataGrid1.ItemsSource
=
q.ToList
(
)
Cursor =
savedCursor
End
Sub
Ensuite, je mets à jour à chaque fois qu'il y a un changement.
Private Sub DataGrid1_CurrentCellChanged
(
ByVal sender As System.
Object,
ByVal e As System.
EventArgs)
Dim selectedItem As SuperEmployee =
Me.
DataGrid1.
CurrentItem
If selectedItem Is Nothing Then
Return
End If
Dim q =
From emp In Context.
SuperEmployee _
Where emp.
EmployeeID =
selectedItem.
EmployeeID _
Select emp
Dim employee =
q.
FirstOrDefault
(
)
employee.
Gender =
selectedItem.
Gender
employee.
Issues =
selectedItem.
Issues
employee.
LastEdit =
selectedItem.
LastEdit
employee.
Name =
selectedItem.
Name
employee.
Origin =
selectedItem.
Origin
employee.
Publishers =
selectedItem.
Publishers
employee.
Sites =
selectedItem.
Sites
Context.
UpdateObject
(
employee)
Dim savedCursor =
Cursor
Cursor =
Cursors.
Wait
Context.
SaveChanges
(
)
Cursor =
savedCursor
End Sub
Conclusion▲
Cet article conclut la partie sur les sources de données basées sur WCF. La quinzième partie de cette série d'articles sera consacrée à ASP.NET MVC.
Remerciements▲
Je tiens ici à remercier Brad Abrams de nous avoir autorisés à traduire son article.