Dynamic ViewModelBase<TContext, TEntity> for CRUD operations using RIA - silverlight-4.0

I am looking for an efficient way to create a dynamic CrudViewModelBase<TConext, TEntity> that will be used as a protortype for all the ViewModels in the application, that are going to perform CRUD operations.
I don't know where is the efficient way to instantiate the DomainContext, should be application-level? ViewModel-level? please share me with your experience.
I am pretty new to MVVM, and I want to create a reusable ViewModelBase to perform these operation.
Any links, code-samples, or recommendations will be really welcommed.
I start writing some stuff (I am new to RIA as well), I will be out for few hours sorry for delay in comments, and thanks for cooperating:
Imports System.ServiceModel.DomainServices.Client
Imports Microsoft.Practices.Prism.ViewModel
Imports Microsoft.Practices.Prism.Commands
Imports CompleteKitchens.Model
Namespace ViewModel
Public MustInherit Class CrudViewModel(Of TContext As DomainContext, TEntity As Entity)
Inherits notificationobject
Protected Sub New(context As DomainContext, query As EntityQuery(Of TEntity))
m_Context = context
m_Query = query
End Sub
Private ReadOnly m_Context As TContext
Protected ReadOnly Property Context() As TContext
Get
Return m_Context
End Get
End Property
Private ReadOnly m_Query As EntityQuery(Of TEntity)
Protected ReadOnly Property Query As EntityQuery(Of TEntity)
Get
Return m_Query
End Get
End Property
Private m_IsLoading As Boolean
Public Overridable Property IsLoading As Boolean
Get
Return m_IsLoading
End Get
Protected Set(value As Boolean)
m_IsLoading = value
RaisePropertyChanged(Function() IsLoading)
End Set
End Property
Private m_Items As IEnumerable(Of TEntity)
Public Property Items() As IEnumerable(Of TEntity)
Get
Return m_Items
End Get
Set(ByVal value As IEnumerable(Of TEntity))
m_Items = value
RaisePropertyChanged(Function() Items)
End Set
End Property
Private m_CanLoad As Func(Of Boolean)
Protected Overridable ReadOnly Property CanLoad As Func(Of Boolean)
Get
If m_CanLoad Is Nothing Then m_CanLoad = Function() True
Return m_CanLoad
End Get
End Property
Private m_LoadCommand As ICommand
Public ReadOnly Property LoadCommand() As ICommand
Get
If m_LoadCommand Is Nothing Then m_LoadCommand = New delegatecommand(AddressOf Load, CanLoad())
Return m_LoadCommand
End Get
End Property
Private Sub Load()
IsLoading = True
operation = Context.Load(Query, False)
End Sub
Private m_CanCancel As Func(Of Boolean) = Function() operation.CanCancel
Protected Overridable ReadOnly Property CanCancel As Func(Of Boolean)
Get
Return m_CanCancel
End Get
End Property
Private m_CancelCommand As ICommand
Public ReadOnly Property CancelCommand() As ICommand
Get
If m_CancelCommand Is Nothing Then m_CancelCommand = New DelegateCommand(AddressOf Cancel, CanCancel())
Return m_CancelCommand
End Get
End Property
Private Sub Cancel()
operation.Cancel()
End Sub
Private WithEvents operation As LoadOperation(Of TEntity)
Private Sub operation_Completed(sender As Object, e As EventArgs) Handles operation.Completed
If operation.IsComplete Then
Items = operation.AllEntities
ElseIf operation.IsCanceled Then
End If
End Sub
End Class
End Namespace

As giddy stated VM's and repositories are concerned with separate things. Just like with ASP.net MVC you wouldn't try and put that stuff in your controller. The ViewModel provides a model of the display and GUI things. Think of the ViewModel as the display. Take the view away and you should be able to test the functionality of the view by testing the ViewModel.
In my current project I'm making calls to my RIA domain services from the ViewModel and then mapping the results to my VM. If you want to use the repository pattern download the code from the silverlight firestarter event. http://channel9.msdn.com/Series/Silverlight-Firestarter/Silverlight-Firestarter-2010-Session-3-Building-Feature-Rich-Business-Apps-Today-with-RIA-Services session 3 Dan Wahlin, there is an example of this. The video is a good watch also.
This example by Shawn Wildermuth shows the client side model actually talks to RIA services. I haven't implemented it yet but it makes more sense to me as the model in his example feels more like a controller to me.
http://wildermuth.com/2010/04/16/Updated_RIA_Services_MVVM_Example
I personally don't like binding Data model entities directly to ViewModels. In my current project I don't have a choice because all access is done through procs so I map proc results to ViewModels. If I did have table access I would probably still map data model entities to ViewModels. I'm not sure that's "correct" in the mvvm pattern but it allows you to keep your data model entities clean of display/validation attributes.

Related

Binding Checkbox to a Shared Property in a custom class

So this should be simple I guess, but I have never done this.
Got a form on which I have a checkbox. I want this check box to be directly linked to a custom class's Boolean property, but somehow this does not work.
Public Class someClass
Private Shared _Filter_Neighbor_6X1 As Boolean = True
Shared Property Filter_Neighbor_6X1() As Boolean
Get
Return _Filter_Neighbor_6X1
End Get
Set(ByVal Value As Boolean)
_Filter_Neighbor_6X1 = Value
End Set
End Property
End Class
Public Class GameGUI
Private Sub GameGUI_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
chk_FilterAll.DataBindings.Add("Checked", someClass, "Filter_Neighbor_6X1")
end sub
End Class
The above does not work. It complains the "someClass" is a class.
I also tried:
chk_FilterAll.DataBindings.Add( _
New Binding("Checked", someClass, "Filter_Neighbor_6X1", _
False, DataSourceUpdateMode.OnPropertyChanged, False))
which hangs the app on start.
any help is appreciated.
Thanks!
You can't bind to a Shared property. You need to remove the Shared modifier from the property, create an instance of the class, and use that instance for the data binding. Your class would look something like this:
Public Class someClass
Private _Filter_Neighbor_6X1 As Boolean = True
Public Property Filter_Neighbor_6X1() As Boolean
Get
Return _Filter_Neighbor_6X1
End Get
Set(ByVal Value As Boolean)
_Filter_Neighbor_6X1 = Value
End Set
End Property
End Class
Then you can do something like:
Dim instanceOfSomeClass As New someClass()
chk_FilterAll.DataBindings.Add("Checked", instanceOfSomeClass, "Filter_Neighbor_6X1")
Note that if you don't have extra logic under the Get or Set of the property, you can get rid of the backing field and convert it to an Auto-Implemented (shorthand) property:*
Public Property Filter_Neighbor_6X1 As Boolean = true
Moreover, if you don't want to create an instance of the class each time, you can make it a Singleton:
Public Class someClass
Private Shared _instance As someClass
Private Sub New()
End Sub
Public Shared ReadOnly Property Instance As someClass
Get
If _instance Is Nothing Then _instance = New someClass()
Return _instance
End Get
End Property
Public Property Filter_Neighbor_6X1 As Boolean = True
End Class
Then, you can use it directly like this:
chk_FilterAll.DataBindings.Add("Checked", someClass.Instance, "Filter_Neighbor_6X1")
* You probably do need extra logic in this particular case in order to notify the change of the property so that the control can reflect that change. Check the other answer for more info.
If you don't want to get rid of the Shared modifier, you can add a read-only property which returns the value of the Shared one:
Public Class someClass
' ...
' ...
' TODO: Remember to use a different name.
Public ReadOnly Property MyNonSharedProperty As Boolean
Get
Return Filter_Neighbor_6X1
End Get
End Property
End Class
Then you can use it like this:
Dim instanceOfSomeClass As New someClass()
chk_FilterAll.DataBindings.Add("Checked", instanceOfSomeClass, "MyNonSharedProperty")
Or with the Singleton approach (check the other answer for details):
chk_FilterAll.DataBindings.Add("Checked", someClass.Instance, "MyNonSharedProperty")
However, please note that if you're implementing the INotifyPropertyChanged interface in your class*, you'll need to notify the change of the read-only property as well as the Shared one when the latter gets changed.
Full implementation:
Public Class someClass
Implements INotifyPropertyChanged
' ##################################
' Optional: Add Singleton logic here
' ##################################
Private _Filter_Neighbor_6X1 As Boolean = True
Public Property Filter_Neighbor_6X1() As Boolean
Get
Return _Filter_Neighbor_6X1
End Get
Set(ByVal Value As Boolean)
_Filter_Neighbor_6X1 = Value
NotifyPropertyChanged()
' TODO: Remember to change the name of the property.
NotifyPropertyChanged("MyNonSharedProperty")
End Set
End Property
' TODO: Remember to use a different name.
Public ReadOnly Property MyNonSharedProperty As Boolean
Get
Return Filter_Neighbor_6X1
End Get
End Property
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
* Which is something you should do when using the class as a DataBinding source.

Problems with Custom DataGridViewRowCollection

I am currently working on a multi thread project. The idea is to implement the threat security into my own custom controls. Now I want to override properties of the DataGridViewRowCollection such as the DataGridView.Rows.Add() and DataGridView.Rows.Remove(row as DataGridViewRow) with my code for the threat security.
My idea was to use an own DataGridViewRowCollection XRowCollection instead of the basic DataGridViewRowCollection. When I try to override the Rows property, I get the compiler message:
"Public Overrides ReadOnly Property Rows As XRowCollection" and
"Public Shadows Property Rows As
System.Windows.Forms.DataGridViewRowCollection" cannot overload each
other because they differ only by return types
I would be thankful for any solution or any alternate ideas to implement the threat secure code directly in my cutsom contorl.
Public Class XDataGridView
Inherits System.Windows.Forms.DataGridView
Private _Rows As XRowCollection
Public Overrides ReadOnly Property Rows As XRowCollection
Get
If _Rows Is Nothing Then
_Rows = New NoxRowCollection(Me)
End If
Return _Rows
End Get
End Property
End Class
Public Class XRowCollection
Inherits DataGridViewRowCollection
Public Sub New(dataGridView As XDataGridView)
MyBase.New(CType(dataGridView, DataGridView))
End Sub
Private Delegate Sub RowsRemoveCallback(DataGridViewRow As System.Windows.Forms.DataGridViewRow)
Public Shadows Sub Remove(DataGridViewRow As System.Windows.Forms.DataGridViewRow)
If MyBase.DataGridView.InvokeRequired Then
Dim d As New RowsRemoveCallback(AddressOf Remove)
MyBase.DataGridView.Invoke(d, New Object() {DataGridViewRow})
Else
Me.DataGridView.Rows.Remove(DataGridViewRow)
End If
End Sub
End Class

Is there a Singleton that raises events?

I have a singleton class, but I want its object to be able to raise events.
My current singleton code is as follows:
Private Shared ReadOnly _instance As New Lazy(Of WorkerAgent)(Function() New _
WorkerAgent(), LazyThreadSafetyMode.ExecutionAndPublication)
Private Sub New()
End Sub
Public Shared ReadOnly Property Instance() As WorkerAgent
Get
Return _instance.Value
End Get
End Property
Whenever I change ReadOnly _instance As New.. into ReadOnly WithEvents _instance As New...
I get an error saying ReadOnly is not valid on a WithEvents deceleration
Although I can create the instance in the property itself, but I liked the above code because it is using .NET Lazy keyword which probably have great multithreading benefits.
This isn't an answer to your question as asked but it demonstrates why that question doesn't make sense. It also requires a fair chunk of code so posting in a comment wasn't really an option. This is how your singleton class would raise events, i.e. just like any other class, and how a consumer would handle those events, i.e. just like for any other type.
Singleton:
Public Class WorkerAgent
Private Shared ReadOnly _instance As New Lazy(Of WorkerAgent)
Private _text As String
Public Shared ReadOnly Property Instance As WorkerAgent
Get
Return _instance.Value
End Get
End Property
Public Property Text As String
Get
Return _text
End Get
Set
If _text <> Value Then
_text = Value
OnTextChanged(EventArgs.Empty)
End If
End Set
End Property
Public Event TextChanged As EventHandler
Private Sub New()
End Sub
Protected Overridable Sub OnTextChanged(e As EventArgs)
RaiseEvent TextChanged(Me, e)
End Sub
End Class
Note that the instance event is raised when the instance property changes, just as for any other type, singleton or not.
Consumer:
Public Class Form1
Private WithEvents agent As WorkerAgent = WorkerAgent.Instance
Private Sub agent_TextChanged(sender As Object, e As EventArgs) Handles agent.TextChanged
'...
End Sub
End Class
The field that the single instance is assigned to is where WithEvents gets used. As your error message states, that field cannot be declared ReadOnly too. If they want a ReadOnly field then they need to use AddHandler to handle events.

MVVM Webservice not holding data returned

I would like to create an application that is gong to connect to a web service and return some data. I have been following a few tutorials and have the following code:
Public Class ItemViewModel
Implements INotifyPropertyChanged
Private _Name As String
Public Property Name() As String
Get
Return _Name
End Get
Set(ByVal value As String)
If Not value.Equals(_Name) Then
_Name = value
NotifyPropertyChanged("Name")
End If
End Set
End Property
..... along with other properties resembling the table from my database.
I then have a MainViewModel
Private _Customer As New CustomerService.Customer
Public Sub LoadData()
Dim myService As New CustomerService.CustomerClient
myService.GetCustomerByNameAsync("Andy")
AddHandler myService.GetCustomerByNameCompleted, AddressOf CustomerByName
Items.Add(NewItemViewModel With {.Name = _Customer.Name})
End Sub
Private Sub CustomerByName(sender As Object, e As CustomerService.GetCustomerByNameCompletedEventArgs)
_Customer = e.Result
End Sub
The problem i have is the service returns data when i check with WCF test tool but on this occasion when running the app i keep getting an empty object for _Customer. I have tried making it into a shared variable but nothing seems to hold the data i get from the service.
How i could hold the data in my MainViewModel?
Thanks
The problem is that GetCustomerByNameAsync execute asynchronously so Items.Add(NewItemViewModel With {.Name = _Customer.Name}) execute before the service respon and the code inside CustomerByName execute. If you move the Add code inside the event handler (CustomerByName) it should work like you want.

Multi web services so multi singleton

well hello everybody
i have one project with multiples web services so i created various singleton class thinking in performance. now i think create one singleton class and that have the instances of my webservices
example
public static WebServiceMaster
{
internal ServiceX WebX;
internal ServiceY WebY;
......
public static WEbServiceMaster GetInstance()
.....
}
what think about that?
is that bad?
Well, finally that is done. I know that is not perfect
Public NotInheritable Class ServiceProxySingleton
Private _services As IDictionary(Of ProxyServicesEnum, IServiceDispatcher) = New Dictionary(Of ProxyServicesEnum, IServiceDispatcher)
Private _dbRepository As IDACommon
Private Sub New()
_dbRepository = New DACommon()
LoadServices()
End Sub
Private Sub LoadServices()
_services.Add(ProxyServicesEnum.eActivity, New ActivityServiceImp(_dbRepository))
_services.Add(ProxyServicesEnum.eAvailability, New AvailabilityServiceImp(_dbRepository))
_services.Add(ProxyServicesEnum.eBrochure, New BrochureServiceImp(_dbRepository))
_services.Add(ProxyServicesEnum.eInformation, New InformationServiceImp(_dbRepository))
_services.Add(ProxyServicesEnum.eMeetingRoom, New MeetingRoomServiceImp(_dbRepository))
_services.Add(ProxyServicesEnum.eMembership, New MembershipServiceImp(_dbRepository))
_services.Add(ProxyServicesEnum.eName, New NameServiceImp(_dbRepository))
_services.Add(ProxyServicesEnum.eReservation, New ReservationServiceImp(_dbRepository))
_services.Add(ProxyServicesEnum.eResvAdvanced, New ResvAdvancedServiceImp(_dbRepository))
_services.Add(ProxyServicesEnum.eSecurity, New SecurityServiceImp(_dbRepository))
_services.Add(ProxyServicesEnum.eStayHistory, New StayHistoryServiceImp(_dbRepository))
_services.Add(ProxyServicesEnum.ePostXml, New PostXmlServiceImp(_dbRepository, ConfigurationServiceSingleton.GetInstance.GetPostXmlConfig))
_services.Add(ProxyServicesEnum.eOxiHttp, New OxiServiceImp(_dbRepository))
End Sub
Public ReadOnly Property Service(ByVal serviceEnum As ProxyServicesEnum) As Object
Get
If _services.ContainsKey(serviceEnum) Then
Return _services.Item(serviceEnum)
End If
Return Nothing
End Get
End Property
Public ReadOnly Property GetMeta(ByVal serviceEnum As ProxyServicesEnum) As IDictionary(Of String, MethodIdentityAttribute)
Get
If _services.ContainsKey(serviceEnum) Then
Return _services.Item(serviceEnum).MetaInfo
End If
Return Nothing
End Get
End Property
Public Shared Function GetInstance() As ServiceProxySingleton
Return NestedPrWireService._instance
End Function
Class NestedPrWireService
Friend Shared ReadOnly _instance As ServiceProxySingleton = New ServiceProxySingleton()
Shared Sub New()
End Sub
End Class
End Class
comments and criticisms are welcome
Very good approach is to use Dependency Injection. For example Unity.