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.
Related
To better show my problem, I drew a graph of how my ViewModel hierarchy looks like so far:
ViewModel hierarchy
What I want to achieve is simply call a method from ScriptEditorViewModel and ask it, if the object, which is currently being edited inside EditObjectViewModel has been specified in the script.
Later I also want to send some information to ScriptEditorViewModel and make it generate a script for the object if it doesn't exist.
ScriptEditorViewModel and ProjectManagementViewModel are 2 separate tabs in my program, which are basically operating at the same time.
Is it possible to do that and if so, is it a good approach?
Note: I'm currently using ReactiveUI as my MVVM framework but any other MVVM solution is also welcome.
When using MVVM pattern, you want to decouple components.
In View part there is xaml with bindings to data and command present in ViewModel.
In ViewModel you should keep data that is presented and logic that does something with that data. It is not the wisest thing to couple multiple ViewModels - keep their logic separated. If you have a command method, all data it deals with should be present in its ViewModel. For anything more complex, you shoud consider communicating with some kind of service or database.
Hence comes the Model part. Here you want to create the model of something you want to store and not necessary present in a View.
I don't know if I understood your problem well, but including a database or any kind of 'persistence layer' into your solution should resolve the problem of accessing specific information. You can create some in-memory storage for start.
After beeing used to structure my project in WPF on a light MVVM pattern, I'm looking into WINUI for a new project.
In the elapsed time, UWP and x:Bind did appear and it looks like the pattern can be much lighter. The whole concept of ViewModel has changed (maybe in a better way).
I'm looking for a "correct and maintainable" way to use x:Bind, to display Properties and call a function from a class.
In my App.xaml, I'm declaring a Configuration which contains all the sub-instances. Let's say a Camera. This Camera has an IP, and a method to call from the UI. What is the minimum code to be able to call and display those ?
For the moment, I have created a CameraView which is a UserControl. I have declared a public Camera object inside, which I can call and display but I don't see the way to affect this from my Configuration. This "link" between the view and the model.
Thank you for the help.
Of course there is a simpler way to implement MVVM: Microsoft itself shows how in its own samples, on GitHub.
However, to summarize it all, have a look at my answer in this question: How to pass data between pages
There I show, step after step, how to easily implement a working pattern to have a “shell” that holds all the app’s data.
Best regards
I've got a project I've got to crank out (thanks to an employee quitting on the job before the deadline).
He'd been working in WPF. The interface looked cool, but it never was able to collect data from the company's old data access DLLs. (Rewriting the DLLs is a great idea, but not feasible in the short time left by the deadline) Collecting data was the whole point!
The project was thrown at me, but I'm no WPF developer. I've been told to make it work with WinForms, which is what I know. I had a WinForm interface cranked out in a few hours, and it looks every bit as good as the WPF version ...and I know what it is doing. WPF involves voo-doo I haven't learned yet.
There are things used in the WPF project that I need to get a grasp of what they do, and I do not have time to completely redesign it all.
The Business Logic Layer returns an ObservableCollection to the WPF interface.
The WPF interface takes the ObservableCollection and stores it in a CollectionViewSource using its Source parameter.
OK, I'm immediately thinking DataGridView control and using the DataSource parameter from it.
Am I on track?
What was the point of the IEditableCollectionView? Is it necessary? And if not, should I just remove all references to it?
ObservableCollection, CollectionViewSource etc. are important in the WPF's MVVM (MVC...+) scheme. You could drop them but you could certainly reuse them in a WinForms project. It might actually be better to do so to retain the clean separation between UI and data.
You could also hang on to them and use them as "more standard" collections which would simply result in a little bit of unnecessary overhead. And since meeting your deadline is of utmost importance, this might be the way to go.
The observable collection is used so that other controls can participate when the collection is added to, removed, or refreshed. This helps keep the entire UI in sync. As far as the IEditableCollectionView, it raises the INotifyPropertyChanged event so that the controls on the WPF form automatically update when a property in the collection is updated.
If you are doing this in WinForms, you just need to raise events when your collection has changed.
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
What method is considered the "standard" for keeping data structures within GUI controls synchronized with the data structures that are maintained by the application?
For example:
In WinForms, if one creates a ListView instance, rather than pointing it to a data structure that represents the items to appear within the list, one must programmatically instantiate ListViewItem(s) and call an .Add method to manually replicate them, one by one, into a data structure that is internal to the ListView itself. This makes sense from a threading standpoint, and it also makes sense within the context of rendering that a control should require a specialized data structure to exist for which the control alone knows the details regarding maintenance.
However, this creates two issues:
Redundancy:
If the client class manages its own list of entities, to allow the user to select among them from the WinForms UI, this entire list must be read, converted and then recreated inside of the UI control via methods such as: .Add(ListViewItem item) Lists now occupy twice as much memory.
Complexity:
Since two lists now exist, one must programmatically ensure that they remain synchronized. This can be achieved with events that are fired from the client class's collection object, or a programmer can simply be careful to always add/remove from one list when they add/remove from the other.
I have seen many instances where programmers will take the shortcut of using a UI element like a ListView as the actual collection object used to maintain the list. For example, each user entered item will be immediately inserted into the ListView, and then when it comes time to access to user's entires, the application just iterates through the ListView. This method fails to apply when you are properly seperating business/application logic from UI logic.
Overall, something just doesn't seem right about storing application data within a data structure that is internal to a GUI control. Likewise, storing two lists and keeping them programmitically synchronized doesn't seem like an elegant solution either. Ideally, one would need only to supply a UI element with a reference to a list that resides within the scope of the client.
So, what is the "right" way to approach this problem?
Every UI control needs some state of its own. With complex controls (like ListView) that state is correspondingly complex. The trick is to make the maintenance of the controls state as simple as possible. With a standard ListView, that's not possible -- the programmer has to do the work.
That's one reason I wrote ObjectListView (an open source wrapper around .NET WinForms ListView). It allows you to use a ListView at a higher level where the maintenance of the controls state is invisible. An ObjectListView operates on your model objects directly:
this.objectListView1.Objects = listOfModelObjects;
this.objectListView1.SelectedObject = aPerson;
Once you can work at this level, data binding itself is no so useful. But, if you really want to use it, you can use the data-bindable DataListView from the ObjectListView project. It gives you the best of both worlds.
With an ObjectListView, there is no reason to switch to the far less interesting DataGridView. An ObjectListView gives you the ease of DataGridView with the nice UI features of a ListView, then plus some more:
Standard DataBinding might make your life a whole lot simpler here. Using a BindingList<T>, you can easily achieve two-way binding. Two-way binding makes it easy to update the UI with changes made programmatically (i.e. by the model) or by the user. The list will remain synchronized.
However, you might want to trade off your ListView for a (readonly) DataGridView if you can afford to. It will make your like a whole lot easier with DataBinding.
dataGridView.DataSource = new BindingList<T>(initialList);
I think there isn't a right approach for this problem. Generally, I'd strongly support separating the data source collection from the UI by all means. Several data binding solutions exists to put the two together.
Anyways, let me make some considerations on the points you exposed.
On Redundancy: You indeed would have 2 lists for the essentially the same entities in the mind of the user. The lists are not at all equivalent.
For a start, there won't be duplication of memory. The list on the UI side may have a reference to the original object in the data source list, but it's nothing more then a reference. The total memory consumption wouldn't be much larger than having a single collection object in the UI
Secondly, the two lists (UI vs. data source) may not have the same number of items. If you use paging in your interface, the UI list may be much smaller than the data source list.
On Complexity: Using a good data binding solution may greatly reduce the complexity of synchronizing UI with its data source. There are some cases where having the two lists separated will actually simplify your code.
Consider the possibility of having a separate window/page/user control/whatever that is responsible for editing (new or old) objects. If you only have a single collection of objects directly on your UI, this separate component would have to reference to the same UI control that holds the list. This simply doesn't makes sense.
DataBinding is the way to go. Take a look at this article, it is very helpful:
Data Binding in .NET / C# Windows Forms
Data binding provides a way for
developers to create a read/write link
between the controls on a form and the
data in their application (their data
model). Classically, data binding was
used within applications to take
advantage of data stored in databases.
Windows Forms data binding allows you
to access data from databases as well
as data in other structures, such as
arrays and collections.
(source: akadia.com)
The problem with accessing the ListView (for example) directly, is that you are modifying the "master" copy of the data in memory. This means that if your user decides to cancel their changes you need to be able roll back any changes they might have made.
So you have the choice, the added memory of two copies of the data structure or the added complexity of having to roll back on cancel.
Check out this article on data binding. For things like ListViews, you can bind to a custom class that implements one of the list interfaces. By adding support to your custom class for events you can automatically update the GUI whenever a change is made to the list (or vice versa).
I just went through this mess with a List(Of MyObject) and the ListView. The ListView is deficient in that it doesn't offer a .DataSource property like many other object containers, such as the ComboBox, ListBox, and DataGridView. I chose to drop the ListView in favor of a DataGridView, simply because I the requirements didn't require a ListView (I added a custom first column to the DataGridView to render an image, which is why I originally chose the ListView. But you are right, the extra code to keep things in synch was too much of a headache. As to your question, do what I did. Figure out if you really require a ListView by considering if you can use a DataGridView instead and meet the requirements.