The project I'm working on is quite large and we have a framework we developed for building simple UI screens easily. The two fundamental types we have are Search (search parameters + grid of results) and Detail (a set of editors that are usually populated from some model object).
The application is all C# .NET Winforms.
In the Detail we have the following process.
Load - Populate the edit controls based on the appropriate model object. Invoked just prior to the Detail being shown
User clicks ok
Validate - Validates the detail to ensure everything is consistent
Accept - Copy the updated control values back into the model
This all works nicely for simple stuff but in more complex cases I've noticed perhaps the above approach is not the smoothest.
The more complex cases mentioned above are when a Detail represents a model object and there is a grid embedded in the Detail which holds 'child' objects which can be added and removed. Typically you want to launch the child Detail and pass in the parent model object, however it is not fully populated/up to date at this point because that only happens when OK is clicked. I find myself working round this in an annoying fashion sometimes which leads me to the following question.
At a high-level, is the accepted/best practice approach for Detail screens like I describe to copy values to the model object when the control is changed, rather than waiting until OK is clicked?
If so, in a Winforms app, what is the best way to achieve this? I found some articles mentioning Control.DataBindings but it's not ideal because of the lack of compile-time safety on the binding. I've read WPF has good binding support, but unfortunately, I'm not using WPF.
For Winforms I would suggest that you look into the Model-View-Presenter pattern.
http://msdn.microsoft.com/en-us/magazine/cc188690.aspx
This might help:
Walkthrough: Creating a Master/Detail Form Using Two Windows Forms DataGridView Controls
http://msdn.microsoft.com/en-us/library/y8c0cxey.aspx
Related
this could be a long question, I'll do my best to ask it properly.
I want to read large .txt files with lots of numerical data. In each file there will be "channels" (30-50 channels, with own name, axis units, and of course, data). So I've created a class Channel with that properties, and a class File that has a list of that channels. It also has a method that reads the file and stores everything in lists.
I want to be able to load several files at the same time, and for that I've created a UserControl that consists in a button for loading the file and a ComboBox that displays each channel:
(The ComboBox is bound to an ObservableCollection)
The data is stored in the code behind of the user control. So when I insert in my MainWindow several UserControls I can't access that data.
What I want is have several UserControl...
...and be able to plot the data from each one in that Plotter, and be capable of some control (previous, next..)
My first approach was to store everything in the UserControl, that was easy to do but ineffective.
So what I figured out that might be the solution is to store everything in other place and then access to there from the MainWindow or other place. I've tried VERY HARD to learn MVVM and use it in my project. But I must be very STUPID because I can't get it.
My new approach is described in the next scheme:
My questions:
1.Is this the correct way of doing it? If the MVVM is the way, please, I beg you, please, guide me just a little bit in the beginning, because I am not capable to translate that intricate examples out there of MVVM to my project.
2.If I'm doing it more or less right, how could I store all that data in some other place and the access it from MainWindow? (in my File class I have a method that stores all in lists, so in my UserControl I have the "Browse" button that gets a filename, and then with the read() method I store everything inside (?) the File class, or at least inside the place I've created the new File: the UserControl).
I'll post code, pics, more info, anything if needed. Thanks.
If the MVVM is the way, please, I beg you, please, guide me just a little bit in the beginning, because I am not capable to translate that intricate examples out there of MVVM to my project.
You're already half-way to using something that's MVVM, at least in nature. It isn't "the way", but it would definitely be a (reasonably nice) way to handle this.
In order to design this with an MVVM type of design, you'd want to make your "MY DATA" class be the DataContext of the UserControl. All of the data would be stored there (preferrably in ObservableCollection<T> instead of List<T>, as that will handle binding more effectively).
Your "UserControl1" portion would likely be some form of ItemsControl, bound to a collection of sources. The selected item could then be bound to something on your "MY DATA" class, which determined which "plot" should be displayed.
To answer your questions directly:
1.Is this the correct way of doing it?
This is definitely a step in the right directly. Storing your data separate from your controls is one of the key pillars to making your application more flexible and maintainable (and a large goal of MVVM).
2.If I'm doing it more or less right, how could I store all that data in some other place and the access it from MainWindow?
You handle this by setting the class as the DataContext of your UserControl and/or MainWindow. This allows you to bind to properties on your data class (which is effectively your ViewModel in MVVM terminology).
Also, I know you've tried to study and learn MVVM - and it's difficult to grasp initially, but it is worth the effort. I will say that your design scenario (which is effectively a list of "options" on the left, and a "detail" pane on the right) is not an uncommon one - it's actually similar to my example in my blog series on MVVM, and should be fairly easy to create once you understand the basics.
I have a winforms app, I use a mix of standard controls and Syncfusion controls currently. In a few months or so new modules will be developed in WPF.
I'd like to add some state saving functionality. You know. TreeView x's last open node was y. Splitter X was split to point Y and so forth.
I've seen a few approaches. I've seen using the built in application settings and how to bind that to winforms and WPF. This has issues when your application is modular or the GUI is dynamically created.
I've got a few approaches in mind. I'd sort of like an approach which mirrors Entity frameworks POCO approach. I don't really want to be decorating my GUI code with attributes or deriving it from a special base class that knows about gui persistence, or implementing ISerializable, etc.
Saying that, I'm also considering using attributes to decorate the gui components and sort of duplicating a lot of what the serializable code in the framework already does, but specifically geared towards GUI settings. I also considered just using the serializable stuff, but it doesn't reflect my intent accurately.
Does anyone have any advice they can give on this?
Thanks
I'm developing a WPF GUI framework and have had bad experiences with two way binding and lots of un-needed events being fire(mainly in Flex) so I have gone down the route of having bindings (string that represent object paths) in my controls. When a view is requested to be displayed the controller loads the view, and gets the needed entities (using the bindings) from the DB and populates the controls with the correct values. This has a number of advantages i.e. lazy loading, default undo behaviour etc. When the data in the view needs to be saved the view is passed back to the controller again which basically does the reserve i.e. re-populates the entities from the view if values have changed.
However, I have run into problems when I try and validate the components. Each entity has attributes on its properties that define validation rules which the controller can access easily and validate the data from the view against it. The actual validation of data is fine. The problem comes when I want the GUI control to display error validation information. It I try changing the style I get errors saying styles cannot be changed once in use. Is the a way in c# to fire off the normal WPF validation mechanism and just proved it with the validaiton errors the controller has found?
Thanks in advance
Jon
Two things:
1) Trust the data binding in WPF. WPF's data binding is incredibly robust and very useful - there's no reason to let your "bad experiences" with other frameworks deter you from using the DataBinding. It will dramatically simplify your code.
2) The best option for data validation is to use WPF's built-in data validation capabilities. If you make your Data Context implementation (where the data is held for binding) implement IDataErrorInfo, you'll get the appropriate validation styles nearly for free (and completely customizable). This is the proper way to handle data validation on the UI in WPF.
I am looking for a best-practise approach on how to do UI validation in a model-view-presenter architecture.
I need to validate some forms with a lot of controls. And to make it easy for the user, I store all errors or warnings with a reference to the control in a Log which is displayed to the user afterwards so that he can jump right away to the control he has to fix. This is done in the view-part, which is actually wrong since validation should take place in the presenter in order to exchange the view.
The problem for me of doing this validation in the presenter is that it is not just checking if provided values are wrong, it also needs to check if radiobuttons have been checked which enables a textbox, which then has to contain some text for example.
I was thinking of using the BindingSource in the presenter since it's reflecting the UI changes and is visible to the presenter. But I am not sure if this is the right way to go (and I think it's kind of ugly)?
By the way: the validation takes not just place before I write to the database; it already takes place while the user is working on the forms.
Could anyone think of a good way of doing this?
We finally found a solution.
It will be done as I expected, using the DataSet in the presenter which is processed by different validator classes (one for each of our "pages"). The most difficult part is, when controls depend on each other (but in the end its just checking if values are set in the DataSet). Currently it is not possible to jump to the control to fix errors but this will be added later via Reflection by passing the name of the control to the LogEntries and the view can then figure out where this control is.
I am working on a Windows Forms app for quite some time now, and I really find myself doing more typecasts in the GUI code than I ever did in my underlying business code.
What I mean becomes apparent if you watch the ComboBox control that accepts some vague "object" as it's item.
Then you go off and may display some DisplayMember and a ValueMember and so on.
If I want to retrieve that value later I need to typecast my object back to what it was. Like with strings getting the value takes
string value = (string)combobox1.SelectedItem;
Since there are generics in the Framework for quite some time now, I still wonder why in the Hell not one control from the standard toolbox is generic.
I also find myself using the .Tag property on ListViewItems all the time to keep the displayed domain object. But everytime I need to access that object I then need another typecast.
Why cant I just create a ComboBox or ListView with items of type ListViewItem
Am I missing something here or is this just another example of not perfectly well thought through controls?
While the criticism of "didn't use generics" can't be fairly applied to controls developed before their existence... one must wonder about WPF controls (new in .NET 3.0, after generics in .NET 2.0).
I checked out the AddChild method in ComboBox. It takes an object parameter (ugh).
This control is intended to be used primarily via XAML. Was this done this way because there is no way to specify a type parameter in XAML? (aside, is there no way to specify a type parameter in XAML?)
Sorry to have no definitive "Why" answer, just sharing the common misery of needing to cast when working with the UI.
I dont think you're missing anything.
It's just that these classes were created back in the pre-Generics days, and WinForms is simply not cutting edge enough for MS to spend a lot of time changing or extending the API.
I often create wrapper classes for controls. This allows me to use generics. This is often in conjunction with Reflection, which is not type safe at compile time, but can be at run time.
A common source of this problem, I think, is not separating your view/presentation logic from your in-memory data model logic. Which, unfortunately, is an architecture fault that WinForms and the Visual Studio GUI designer are complicit in.
WinForms and the VS designer do not encourage the programmer to separate the management of their data objects from the form classes themselves. It would probably be better if the ComboBox ListViewItem objects didn't offer any support for arbitrary objects, either via generics or Object collections..
Unless you are hacking together something of limited use and lifetime, you should try to avoid storing references to individual data objects right in your controls or forms. They should be managed separately, and if they need to be referenced, it should be done via a model management class designed for the particular type of view class you're working with.
A simple-ish bandage for the problem, though, might be to "map" the text representations that you place into the ComboBox or ListView to the original objects, using a Dictionary field member on your Form class. It's not an ideal solution, but gives you at least a half-step of indirection between your data and your UI controls, which can make your code easier to maintain.
Edit: This is admittedly separate from the ListViewItemCollection class exposing Object instances... The official defense is likely to be that they wanted to support the standard IEnumerable and ICollection interfaces. But there's no reason they couldn't have also provided type-specific overrides of these methods, since it is designed explicitly to store ListViewItem instances. So I have no answer for you on that particular question.
Well, if you data-bind your controls to a DataBindingSource, you can get at your data that way, but AFAIK that's still not strongly typed. If you are displaying multiple parameters/aspects of a single business object, you can bind to that, then access the (strongly typed) members instead -- of course, this all goes back to Turbulent Intellect's answer, which is better separation between model and view. Still, I agree that generic-based typing would help.
It is possible (you can make your own generic controls, if you wish), but the form designer that comes with Visual Studio will freak out if you do this. You'll have to do stuff without it.
You aren't the first one to think of this, and Microsoft has already received a fair share of criticism from the public for this. Let's hope they add support for this in the future.