ericpap
ericpap

Reputation: 2937

Can I use MVVM Template on WPF to resolve this?

I have been reading about MVVM on WPF. As long as I understand right, in MVVM I should divide the Model (data to display) from the way to show it (the View) using ModelView to link both, right?

So what I want to do is use a DataSet as Model, with n number of fields coming from a database. The field names, type and order are variable (is a Select from a SQL Server View).

The view will be a WPF form with a Datagrid.

So I should build my modelview in a way that iterates on each field from the DataSet and depending on Field Type format the data to show it later on the grid.

It is possible to do this whith MVVM Templante on WPF?

Thanks in advance

UPDATE

I will try to clarify my scenario and what i try to do, based on LordTakkera comments. I'm bulding a Client-Server Layered application using .NET technologies. Client and server will be in different machines, comunicating with WCF. A few different clients will use this software, so suppose this scenario: Client 1, 2 and 3 need a sales report showed on a grid.

Client 1 need: Sales Date, Client Name and sale import.

Client 2 need: Sales Date, Vendor name and sales import.

Client 3 wants to add to his Client table a numeric field that represent espected sales per client and whants to show it in sales report.

If i use Strong data Types, i need one binary for each client, im i rigth? What i want is to use the same binaries for client 1, 2 and 3 changing the output from sales report based on database data.

Why? many reasons:

1) Eliminate Bugs: If i find a bug in some class i can correct it, recompile and give the corrected binary to all my clients.

2) Scalability: If i add some function to the system wich was asked by client 1, i can give that function to all my clients.

3) Flexibility: i can change the behavior of the software for each client with the same binary.

I understand the advantage of strong type, in fact i will use then in some cases. But in others flexibility is escencial to me. So, wich are my options?

Thanks!

UPDATE 2

With the help of @LordTakkera and many people in this page i manage to start the development of my application. Rigth now I have my model, my wcf service my client and my first ViewVodel and View. Now i'm trying to add more complexity to the app adding multiple XAML views for my project. If I keept following MVVM pattern the navigation between this pages and the main page where all others views are inserted should also be manage with a viewModel (Something call application viewModel for what i read). My idea is to have a container MainPage with an area where child views will appear. I also wanted to have the child views in separated XAML file because some views are very complex and i will have losts of views! The problem is a can't find a single sample code for WPF navigation on MVVM pattern with a master container page. All the sample code that i could find:

1) Use external toolkit like Prism or MVVM ligth and right now i don't want to mess arround with new thing!

2) All the controls for each view are created on a single XAML.

I need some help with some code to create the basic layout of my app and want to know if what i'm planning is even posible. Thanks!

Upvotes: 0

Views: 656

Answers (1)

BradleyDotNET
BradleyDotNET

Reputation: 61379

As HighCore noted, DataSet isn't a good choice of a Model, but otherwise that sounds about right, there are a couple of concerns I would have from your post though.

  1. You mention that you have variable "type" this is a large red flag. If you have variable types, how are you going to have consistent columns in your data grid? Now, if you mean that you are going to have a different data grid for each type (perhaps using typed Data Templates) then that would be ok.

  2. When you say "format the data" I hope you mean "store it in a data object". WPF binds to properties of objects, so your datagrid should look something like:

    <DataGrid ItemsSource={Binding DataItems}>
       <DataGrid.Columns>
          <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
          ...
       </DataGrid.Columns>
    </DataGrid>
    

Basically, make sure you bind to objects that are populated from your Model. The ViewModel is definitely the object that should be performing this translation.

Update

I apologize for not understanding the purpose of your application, in that specific application, what you are talking about makes more sense. That being said, I will try to address your concerns:

  1. In general, you should need to change your model/view/view model if the underlying data context or objects changes. C# is strongly typed, and the whole point of WPF is to have declarative, strongly typed UIs. I understand that you are trying to show "generic" data, but unless you are doing a "SELECT *" type query, you are going to need to change some code anyways. If you know what the view that you are displaying is, then changing all the code if a field is modified/added is perfectly acceptable (and even desirable, because it forces you to account for the change everywhere it affects).

  2. Variable, or "weak" types are a red-flag because, as noted above, C# is a strongly typed language. Strong typing has a lot of advantages, least among them good compile-time error checking. If you want to be in a weakly-typed environment, think twice about which language you are using.

  3. This goes back to the generic data. You can use typed Data Templates to accomplish some "formatting" changes based on type, but this is in a polymorphic (as opposed to weakly-typed) scenario. You could use a converter to perform the currency format you describe, but I would think about what you are trying to do and make sure that it is the direction you want to go.

Update 2 Strong typing should be just fine for this scenario. In fact, you are communicating with a WCF service, which by definition is strongly typed (this is the whole point of DataContracts, if you aren't doing it this way, please fix it and save yourself a lot of trouble). So we know your model (the WCF service) has strongly typed data objects, with properties like "Sales Date", "Client Name", "Sale Import", "Vendor Name", and "Sales per client". Now we just need three views (or even one flexible view) to accomplish your three scenarios.

You certainly do not need three binaries, even with the three views approach (you just need a way to select which view is active). You could even have an app config that determines which "client" to use, or load your views through MEF. The one flexible view approach takes a lot more work, because you have to bind your column collection instead of having it statically defined (a problem, incidentally, I am currently working on for one of my projects).

In short, there are many ways to have different views appear. I would not recommend changing the view based on the data, because your user wouldn't expect it, and it will be extremely messy to implement. If you want "Client 1" to only have access to "View 1" I would set it in the app config or only distribute the "View 1" plugin and load it using MEF. If all clients should be able to see all views, some kind of combo box or navigation bar is in order.

Update 3 Having (potentially) multiple views for the same view model, and especially multiple view models for the same model, is one of the reasons to use MVVM! I'm glad you were able to discover this. On to your questions:

As to your first comment:

  1. Your model (on the WCF side) won't have any knowledge of user filters, unless your request includes them. There isn't a problem with including that information (in fact I would encourage it to keep network utilization down), but you need to be aware of that when designing your service contract.

  2. View models always (without exception to my knowledge) live on the client side. The client-side "model" becomes the WCF proxy in your scenario.

As to your second:

  1. There is absolutely a way of creating data model classes from your Database, in fact, I would encourage it. .NET has a library called Entity Framework (currently at version 6.02, available on Nuget) that will automatically generate database "objects" with automatic foreign-key navigation and a host of other features (MSDN). A word of warning, EF classes, in general, can not be sent directly via WCF (due to the navigation properties, the recursion breaks the serializer). So, anything you want to send to your clients should be sent as a manually created DataContract, and a class on the server translates between the two.

  2. I don't know about a link, but having multiple views is pretty simple, you just use a Content Presenter and set the backing UserControl property whenever you want to change. It can also be accomplished by using a tab control, and probably an infinite number of other ways.:

    <ContentPresenter Content="{Binding CurrentView}"/>
    
  3. See my note above on using EF classes with WCF. Even if you don't use EF, in general it is recommended to use custom built data objects as your contracts. That way, you are only sending the information that is needed, and your contracts library isn't cluttered with database/model objects.

Update 4 1. Remember, you don't want to expose your database objects directly to WCF, and you especially don't want to do this with EF objects (because of the navigation properties). So you could: (A) use EF for your DAL and translate to Data Contract objects for WCF (recommended) or (B) create your own model objects, that could potentially be the same as the data contract objects (though I would still keep them separate) and do the DAL through ADO.NET or something similar. If you use EF, the database CRUD operations are very easy to do, as you noted.

  1. You only need a different view model if the data is different. If your view model consists of (primarily) a large collection of objects that the different views just display differently, then I see no reason to duplicate the code in multiple view models. The rule-of-thumb is: The View Model should be independent of the view. As long as you don't have any view specific code in your VM, you can reuse it for as many views as you want.

  2. Your final question is huge, and while I am happy to give you my opinion, you will find that if you asked 100 engineers this question, they would all give you different answers (as it seems you have already found).

So, to start with, you are absolutely right. Using MVVM (or any design pattern) will increase the amount of code you have to write, sometimes dramatically (especially when you are just starting a MVVM project, the amount of boilerplate code seems absolutely ridiculous at times).

However, the point of design patterns is not to make our code size smaller, it is to make it more extensible, maintainable, and testable. Specific to MVVM, you have the ability to put multiple views on the same view model (as you have seen) and the ability to put multiple view models on the same model. This means if you want to add a view or view model, you don't have to rewrite a whole bunch of code. Additionally, both the view model and model are easily testable since they have no knowledge of the UI.

In general, my rule of good design is Use Common Sense!. If it is likely to be changed/extended in the future, using a design pattern is almost always worth the extra code. If I am just going to throw it away in an hour, who cares?

Like I said, the applicability of design patterns and when deviations are ok is a huge debate in software engineering. I would encourage you to just go with what makes sense (thinking about the future of course) and refactor when you are wrong.

Please let me know if that addresses your concerns, of if you have more questions.

Upvotes: 2

Related Questions