I implemented a file input mask as a user control that I want to re-use in my WPF application in two different contexts.
While the view (in the two cases) is actually pretty much the same, the ViewModel and the logic I implemented there is quite different.
I have already tried to inherit from a common AbstractFileInputView together with an abstract ViewModel, but that seems to break as soon as I put it in XAML.
Since I wasn't able to find some actual documentation about how to build re-usable (abstract) user controls, I am wondering if somebody has any hints on how to solve this?
Or do I really just have to go on a copy-and-paste spree here?
Related
I'm working on a WPF project using the MVVM pattern and I was wondering if I can improve the internal structure of my ViewModel by abstracting its exposed properties into separate classes.
It's common practice for VMs to contain lots of properties laying around in the same class: Some are used to retrieved user inputs, some are used to expose commands, others to expose the models, and probably some other properties for the view model's own business logic. Not to mention that these properties often have set and get bodies that adds some bulk to the package. This can quickly become messy inside a VM class and finding one's way there can become challenging.
As a way to solve this issue, I am exploring with my team the idea of grouping properties inside my VM into different categories. As a first approach, I chose to group them this way:
ViewData, UserInputs and Commands, each one represented by its own class. Then I referenced them as properties inside my VM class.
My intention is that these classes will only act as placeholders to free up the bloat in my VM and keep it clean and focused only on interaction logic for handling user events.
It's a simple refactoring, but I get the following pros:
Cleaner and readable VM.
Easier binding from the XAML because you know what the entry point is/should be.
Let me elaborate on the latter one: If I want to bind a text box to a property of my VM, I know the binding expression should start with Userinput.MyVMProperty. If I need to show a value from my VM, I know my binding's entry point is going to be ViewData.MyOtherVMProperty. Binding intellisense will also become better because when you know your entry point, the
suggestion list would be smaller and more focused. This also works the other way around: when reading through your XAML controls, any binding that starts with UserInput necessarily means it's a a control that should send data back to the VM.
The only cons I can find is that this will require creating extra classes for each VM, but I believe it's a fair price to pay for the benefits you get.
Take note that the grouping I suggested may not be the best, but I don't mind any other grouping as long as it solves the problem with bulky VMs.
So, has any one ever tried a similar pattern? Do you think this is a good idea/practice? What other good practices I can use to improve my VMs?
Bonus question: One developer in my team who seemed to agree with this idea, suggested to go the extra mile and consider the grouped classes as VM dependencies and that they need to be injected inside the VM. What do you think about this?
So for every ViewModel you need to create own inner classes for every group. You cannot use Interfaces because ViewModels have different properties and commands
Then did you considered that every "groupclass" must to "know" about other groups for ViewModel will work properly.
In my opinion Class should be solid logical structure with minimal outside dependency.
Based on the pros you trying to achieve I can suggest another approach without changing structure of the ViewModel classes
Readability can be achieved partly by #regions.
Or use Partial class for separating different groups in the different files,
while keeping them inside one logical structure
Intellisense can be improved by naming conveniences - using prefix based on group property belong to. For example UserInputMyName, ViewDataFullName or CommandDelete
I want to ask pro developers out there that how they manage a big windows form class. Is it a good idea to split it with partial keyword across different files? That's the thing that I was doing so far, but it creats unnecessry designer files that when you double click on them in VS, a blank winform will pop up:
So what I do, basically is group events and code logic for each related group of controls in one file.
My answer is "I don't". If you need a lot of code in one single class (in this case a form) it usually means your class is doing a lot of stuff and you need to make it less coupled. A good way to achieve this is to use a sort of MVC or MVP pattern form putting the logic in another place, and to use UserControls so you could have the different functionalities in different controls (with their controller or presenter, depending if you implement MVC or MVP). Divide and conquer.
I not consider me an expert, but once we had a similar problem with a main form that did not stop growing up.
The solution was just OOP, make unattached and reusable classes, those can be in the same namespace with internal visibility.
For Example there you have a ComparisionForm.Menu that looks that can be unattached from your main code in ComparisionForm.
From another point of view 'Readability'.- Partial classes are useful but take into account that even with that division of code in different files, the logic is not always divided, that makes the code hard to read, understand and finally hard to maintain.
Divide logically my classes for my was the solution. You know what say they "Divide and Conquer"
I think the best way to separate the code of a form, it's to use UserControl.
And in my case, when I have a big class, I use region instead of partial class.
Not a pro, but my two cents are: Don't have a large class. Extract most of the code to other classes.
You'll gain, also, that you'll be able to make most of the methods private, thus reducing Intellisense "noise".
My situation is that I have a control that is implemented to handle two different types. So in some of the methods I have if(controlType == "Type1")
...
else... I would like to split this into two different controls with a base class to handle the common operations of both controls. Both controls would have the same markup too so I would like to handle the control events in the base class but the designer seems to screw this up for me. I almost feel like a generic .ascx would be perfect but I don't know where to start with that.
In the past I've tried all sorts of things with inheritance and user controls, including one ascx inheriting from another ascx, and decided in retrospect it wasn't worth the trouble as the maintenance of it tends to be a bit of a headache.
Having two ascx controls inheriting from a common base class works out ok, but I too found trying to handle the events in the base class gets difficult. In the end I just called methods in the base class from the events. You have to handle the events in both controls, but at least people will can follow the code 2 years from now.
Generic ascx would be awesome and is possible:
C# generics usercontrol
Is it Possible to Make a Generic Control in .Net 3.5?
BUT although this is a clever workaround, as the EDI doesn't directly support it I suspect it will end up adding to the maintenance problems.
I know it's probably not the answer you're looking for, but having ugly if(controlType == "Type1") code, although it feels inelegant, may end up being the easiest to maintain, just because Visual Studio doesn't inherently support inheritance for user controls.
Good luck, and if you find an elegant solution, please let me know!
Recently i got explained that MVVM can only be done "the right way" if i use DataTemplates. Is this truely the case?
I'd say its a good idea to use DataTemplates if you want highly reusable "Views".
But if i am going to develop an application that has, say, five to ten different pages, and there is very little to none reuse of specific controls (like the "Person" view is only used once, and its highly likely that this requirement doenst change), why cant i simply create a usercontrol and put that directly into the code?
Am i missing some important core principle of MVVM here?
Main selling point of MVVM is separation of View from the ViewModel (so that VM doesnt know about View) by using powerful Binding feature of WPF.
DataTemplates are a just another feature which allows you to represent data in different way. As you have said, if you dont have reusable DataTemplate then dont create one, even if you do make sure it resides in the View's Resources, you can share it wider group if you wanted do.
using UserControl can be useful where you need to do something extra (apart from simple representing data), for example, some complex validation or extra commands/buttons
I dont think MVVM and DataTemplates are related in the same context.
There is no special needing for DataTemplate, you have a view and a viewmodel that cooperates with databindings and events. The MVVM goal in WPF is to remove the code from the view to achieve a real presentation only view, and not a messy code behind store. Having the ViewModel agnostic from the view is another goal, even if not always achieved.
When adding a control to my form, currently I have to wire it up with my save and load code, with my internal data structures and I have to do this with all my controls. This scenario severely violates the DRY (don't repeat yourself) principle and can introduce subtle bugs.
I have came up with the idea of traversing all the Controls in a foreach loop, the Name property will be the key and the Text (or whatever depending on the type) will be the value in a dictionary (filtering for user input controls during the procedure). This way I will have to serialize/deserialize the dictionary to save/load it.
So, why am I asking? I am a beginner and I think there are more proven and tested methods for accomplishing the same task then what I came up with.
And sorry for my clunky English, I have not had the fortune to learn it as my first language.
Thanks for your help
note: I know about WPF, but I have to stick to .net 2.0
There are already good examples for doing that, see RealPosition. We modified this source to do form/control position saving in our project by just placing a component on the form in the designer and specifying the necessary properties there. Look at the IExtenderProvider and ISupportInitialize interfaces on MSDN too.
Ideally you want all the controls to inherit from a base class, the base class can then deal with all of this when each control is initialised. If you need the dictionary then pass the dictionary into a method, the method can then set all the various properties required on the control.
If each control inherits, then the logic is shared and DRY :)