Using a Queue as datasource - c#

I would like to display items from a Queue in a Gridview in Windows Forms. I can set the datasource attribute of the Gridview to the Queue, but it won't be automatically updated. I know I can use the BindingList class, but then I lose my Queue functionality.
Is there any way to combine the two classes, or do I have to implement one of the behaviours in a derived class?
What I'm doing is processing a list of items, I want to show the remaining ones in a grid. The data should not be changed by the user, but I want the GridView to be updated as the contents of the Queue change.
Example:
In form:
Proccessor pro = new Processor();
gridview.DataSource = pro.Items;
In class:
class Proccessor {
Queue<DataBlock> _queue = new Queue();
public Queue<DataBlock> Items {
get {
return _queue;
}
}
public void AutoProcess() {
while (_queue.Count > 0) {
Process(_queue.Dequeue());
}
}
private void Process(DataBlock db) { ... }
}

The whole purpose of a Queue is that entries can only be added in one place. So the idea of binding this to a UI grid so it can be updated is, uh, interesting - how should the UI look?
You'll definitely have to consider your own custom collection, or as you say, derive from BindingList and handle e.g. CancelNew accordingly. See the MSDN article for details.

I would subclass Queue as QueueForDisplay. The constructor would take a view control. I would override the Enqueue and Dequeue methods. In those overrides, I would update the view control. If you don't like the tight coupling, you could simply subclass Queue as QueueWithEvents and provide OnEnqueue and OnDequeue events.

Related

BindingList vs List - WinForms Data Binding

In order to get data binding in WinForms (to a DataGridView, for instance) to work anything like you'd hope and add/delete rows as the collection changes, you have to use a BindingList (or DataTable) instead of a generic List. The problem is, almost nobody has the first instinct to code with a BindingList instead of a List in their libraries.
The BindingList implements two events that the List doesn't have and these must be the difference in data binding action (also, a property to suppress the second event):
AddingNew
ListChanged
RaiseListChangedEvents
Similarly, the DataTable has two events which probably enable similar functionality:
RowDeleted
TableNewRow
EDIT: As the helpful SO community pointed out here and in another article, a List can be converted (maybe more accurately encapsulated?) by calling the correct BindingList constructor:
BindingList<MyType> MyBL = new BindingList<MyType>();
MyList.ForEach(x => MyBL.Add(x));
My situation is a little more complicated as illustrated by the code below.
EDIT Added INotifyPropertyChanged stuff that must exist in the real library.
public class RealString : INotifyPropertyChanged
{
private int _KnotCount = 0;
private List<KnotSpace> _KnotSpacings = new List<KnotSpace>();
public RealString()
{
KnotSpacings.Add(new KnotSpace());
}
public int KnotCount
{
get { return _KnotCount; }
set
{
int requiredSpacings = 0;
_KnotCount = value;
// Always one more space than knots
requiredSpacings = _KnotCount + 1;
if (requiredSpacings < KnotSpacings.Count)
{
while (requiredSpacings < KnotSpacings.Count)
{
KnotSpacings.Add(new KnotSpace());
}
}
else if (requiredSpacings > KnotSpacings.Count)
{
while (requiredSpacings > KnotSpacings.Count)
{
KnotSpacings.Remove(KnotSpacings.Last());
}
}
this.OnPropertyChanged(this, "KnotCount");
}
}
public List<KnotSpace> KnotSpacings { get => _KnotSpacings; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(object sender, string PropertyName)
{
if (this.PropertyChanged == null) return;
this.PropertyChanged(sender, new PropertyChangedEventArgs(PropertyName));
}
}
public class KnotSpace
{
private double _Spacing = 10;
public double Spacing { get => _Spacing; set => _Spacing = value; }
}
The things in the list are displayed in the UI, and the properties of the things in the list are modified in the UI, but the UI doesn't directly add/remove things from the list except by changing the KnotCount property. Wrapping the KnotSpacings property in a BindingList doesn't result in the BindingList updating when KnotSpacings is updated by changing the KnotCount property.
EDIT OK, more clarification...
BindingList BL = new BindingList<KnotSpace>(MyRealString.KnotSpacings);
DataGridView1.AutoGenerateColumns = true;
DataGridView1.DataSource = BL;
NumericUpDown1.DataBindings.Add("Value", MyRealString, "KnotCount", false, DataSourceUpdateMode.OnPropertyChanged);
The BindingList has no more success tracking the changes to the underlying List property (KnotSpacings) than the Windows controls. So data binding the controls to the BindingList doesn't accomplish much. BindingList works great if UI adds/removes items from the BindingList because it does the same operations in the underlying List. But then I would need to replicate the add/remove action and logic of the library in my UI and that's a breaking change in waiting.
EDIT Major changes made to my original post attempting to: (1) Clarify the problem. (2) Distinguish it as not a duplicate question (although one of the several questions was a dup). (3) Acknowledge the helpful efforts of others that would be lost if I deleted the post.
First Off, there is a better way to pass a List<T> to a BindingList<T>. BindingList<T> has a constructor that accepts a List<T> which copies the List's elements into the BindingList, like so:
List<int> myList = new List<int>();
BindingList<int> myBindingList = new BindingList<int>(myList);
But that's not your question, really. To answer your question simply - Correct, List<T> is not a good choice for two-way binding in WinForms. As List<T> does not have any events notifying for elements added, you can really only guarantee a one-way binding - data entry may work, but things break down when trying to refresh on, say, items being added to the List.
That said, you mention that these libraries are modifying a List<T> that you have access to during the modifications. I would argue that a good Library would use the Interface pattern to use, modify, and pass collections. Although List<T> and BindingList<T> are very different classes, they both implement IList<T>, ICollection<T>, and IEnumerable<T>. So any function which accepts any of those interfaces as a parameter would accept either a List<T> or a BindingList<T> (for example: public void DoSomethingWithCollection(IEnumerable<int> collection) could accept List<int>, BindingList<int>, or any other collection that implements IEnumerable<int>). The Interface pattern is a well-known standard at this point in C#'s lifespan, and though nobody's first instinct would be to use a BindingList<T> over a List<T>, their first instinct should absolutely be to use an IEnumerable<T> (or IList<T> or ICollection<T>) over a List<T>.
Where possible, it would be better for binding to pass your List to the BindingList's constructor, then never use the List again - instead, use the Add and Remove methods of the BindingList to manage it's internal collection.
If you use the BindingList<T> constructor that accepts an instance of IList<T>, then that instance is used to back the BindingList<T>, and changes in the IList<T> are reflected in the BindingList.
That's not the end of the story, however. WinForms databinding is structured in such a way that, the further away you get from simple, single-property 2-way binding, the more things you have to cover yourself.
For example, the INotifyPropertyChanged interface is implemented by classes that are used as a data source to notify of a change in a child property (like your KnotCount property).
For more complex scenarios, one would not use BindingList<T>, but would derive a class from it and override one or more of the data binding mechanisms. Ditto for the BindingSource class.
There is a lot of boilerplate behind the data binding mechanism, but almost every portion of it is open to derivation in order to customize the behavior. It is sometimes useful to draw out an object graph of the classes and interfaces used in data binding (lots of reading the documentation involved) to give yourself a good mental overview of the whole process.

When and how to call asynch method in ViewModel in windows phone wp8

I have a windows phone (wp8) app using MVVM pattern which contains a view with a pivot control and is binded to a ViewModel (PivotMainViewModel).
Each pivot item contains a different view (datatemplate) and is binded to its own viewmodel (PivotItemViewModel1, PivotItemViewModel1, etc...) and all of this is working well.
My PivotMainViewModel is initialized via xaml binding but as it needs a parameter, it is also "initialized" via the OnNavigatedTo event of the view.
PivotItemViewModel4 pivotItemViewModel4 = Resources["PivotItemViewModel4"] as PivotItemViewModel4;
if (selectedRow.Id > 0)
{
pivotItemViewModel4.InitializeDocumentDetails(selectedRow);
}
but I'm not sure about how to deal with the web service requests which I want to make asynchronously. I need to make a web service request for each individual pivot item "view" and load data the minute it is returned but I need to do this as soon as the pivot is initialized but I'm not sure about the following:
I need to fill data in each of the pivot item "views" and therefore their relevant viewmodels but I'm not sure whether I should make all the asynchronous call from PivotMainViewModel or from each individual viewmodel defined for each of the pivot item.
Whether I call this from the PivotMainViewModel or I call this from each of the pivot item viewmodel, when should I call this?
Should I call this from the constructor:
public PivotItemViewModel1
{
this.Document = GetDocument();
}
or the Get part of my property when its internal variable is null for example? i.e.
public Document Document
{
get { return this._document ?? GetDocument(); }
}
or other?
If I'm supposed to call this from the constructor of the individual viewmodel, how do I do this? I can't use async on a constructor nor can I set async on a property.
What is the best way to make an async call to a web service when dealing with MVVM.
Again, I'm not sure which is best:
4.1 Display a progress bar of some sort, request all 4 requests and wait for all of them to complete and then hide a progress bar
4.2 Display a progress bar of some sort within each individual views and hide them accordingly as each request gets completed
Last problem... Hanging. I've ready numerous articles on the async and hanging but they always describe the problem when dealing with a click event, but I don't understand how to deal with this when you don't have a click event but when you want to call this when a viewmodel is initialized. If you know how, can you please explain and provide a simple example.
There are different concerns to keep in mind:
Code structure. In general you want to restrict the scope of views and view-models, for a modular structure. (This is also called encapsulation.)
UX responsiveness. You don't want to make the user wait, and if they do have to wait, then show them a progress bar / status indicator.
Data usage. The user may be on a data connection, so you want to be conservative with data usage.
So, the question of:
loading all data immediately, or
loading only when the user swipes to the given view
presents a trade-off between #2 and #3. It's really a judgement call, depending on what kind of feel you want the app to have.
I'm not sure whether I should make all the asynchronous call from PivotMainViewModel or from each individual viewmodel defined for each of the pivot item
I do think that #1 above implies the latter -- each view model should own its own data if possible, for the sake of encapsulation.
Edit To use async on a property, you have to use the setter, not the getter. Hook to the view-model's "initialize" event (or similar):
public Document Document
{
get { return this._document; }
set
{
if (this._document == value)
return;
this._document = value;
RaisePropertyChanged("Document");
}
}
public async Task<Document> GetDocument
{
// ...
}
private async Task LoadData()
{
Document = GetDocument();
}
public void Initialize()
{
LoadData();
}

WPF: property similar to WinForms Modified

In WinForms controls like a TextBox have property Modified that gets value "true" after changing the control's content and may be set to "false" manually. Their WPF analogues seem not to have such property (neither IsModified in new naming style). So do I have to handle their modifying events myself or there's some more convenient way?
For example I have few textboxes and a function, which combines their contents into one document for preview. Opening the preview I want to keep an old content for the document, if none of the textboxes was changed or to call the function to produce new document's content if at least one textbox was edited.
In WPF it's easier to control everything through ViewModel/Model... This might be too much/not what you're looking for. But through experience, I feel that the pattern below pays off in easy usage.
Wrap your simple data class (with all the properties that it is using now/in your question now) in a class/Model that implements IEditableObject, INotifyPropertyChanged and possibly IEquitable. Lets call your class Data.
In a wrapper class create fields:
Data _current;
Data _proposed;
Data _previous;
IEditableObject requires you to implement BeginEdit(), EndEdit() and CancelEdit().
in them you need to control the state _current, proposed, and previous. For example,
public void CancelEdit()
{
_current = _previous;
_proposed = null;
}
public void EndEdit()
{
_previous = _proposed;
}
public void BeginEdit()
{
_proposed = _current;
}
You might need more logic in methods above, so this is just an example. The key of knowing if your object has changes is implementing a flag, lot's of people call it IsDirty:
pubic bool IsDirty { get { return _current != _previous; } }
Now the user of this class can easily check the state. Oh, and on more thing each property would have the following mechanism:
public string Example
{
get { return _current.Example;}}
set
{
if(_current.Example == value) return;
BeginEdit();
_current.Example = value;
RaisePropertyChanged (() -> Example);
}
}
What's nice about implementing IEditableObject, all controls respond to it, DataGrid is a good example and also you can easily return to the original state by cancelling edit.
Anyway, there are lots of samples that you should browse for. I just hope to can get you started onto that path...
P.S. this pattern was used before WPF came out, its super common in WinForms as well
WPF doesn't have that because UI is not Data and therefore your UI is not the right place to store information about whether your data has changed or not.
Crappy dinosaur winforms doesn't allow a clean and true separation between UI and application logic/data and therefore has all sorts of horrible hacks in order to mash together these completely separate concepts.
You must learn to develop correctly, using the MVVM pattern. Then you will realize there's no sense in placing state data on any UI elements.

WPF Share and Update lists between different windows

I am trying to create a scheduler in WPF. I have a central static list in main window, which is initialized on load by a backgroundworker. There also is a dispatchtimer in mainwindow, whose interval is recalculated everytime the list changes.
public static List<ListViewcls> TODOdatalst = null;
public static void RefreshdblList()
{
if (ApplicationState.GetValue<bool>("dbDetected"))
{
TODOdatalst = DataAccess.ReadAllTODODataFromDataBase();
InitialiseDailyReminders();
}
}
Now there is another window which contains a listview which is bound to an observable collection, which is derived from the static list in mainwindow. whenever an item is added, updated or deleted from the list, the list in both the windows is manually refreshed via static functions.
private static readonly ObservableCollection<ListViewcls> TO_DOViewlst = new ObservableCollection<ListViewcls>();
public void RefreshView()
{
MainWindow.RefreshdblList();
if (MainWindow.TODOdatalst != null)
InitialiseListView(MainWindow.TODOdatalst);
else
InitialiseListView(DataAccess.ReadAllTODODataFromDataBase());
}
so is this approach proper ?? It works for now but suppose in the future, i have one more window which will also access the list but then i will be managing the refresh of data between 3 windows....that does not figure right. Anyone can suggest some better way, that i can keep a central repository and whenever it is updated all other lists get updated.
When one uses MVVM there is an option to use one ViewModel (the class which acquires and holds the data which is used as Data Contexts for a window/page(s)) between multiple windows and this scenario is common.
I would opt to share the instantiated ViewModel (or class which houses your data) between all windows and pass it in during window creation to have the window/page's data context bound to that one VM. That way the satellite window(s) are using the same data as the main and not having to do any update tricks as shown. Plus any new windows simply bind to the observable collection which everyone else is binding to.

ObservableCollection and CollectionView

I'm writing an application that reads data from a local db and display them in a listbox(I'm working in WPF).
I've a DVD object, where its properties are the columns of the db. This DVD object also implements INotifyPropertyChanged. "MyDVDs" is the table that refers to db. Once created these object, I create a class that inherits from ObservableCollection and takes data from "MyDVDs" in the constructor. However I don't need only to add, remove and update data from the listbox, but I also need to sort and filter them. Here is the code for ObservableCollection:
class ObservableDVD : ObservableCollection<DVD>
{
private ICollectionView collection;
public ObservableDVD(MyDVDs e)
{
foreach (DVD d in e.DVDs)
{
this.Add(d);
}
Collection = CollectionViewSource.GetDefaultView(this);
}
public ICollectionView Collection
{
get { return collection; }
private set { collection = value; }
}
}
I wanted to know, this is a good way?? Or can I do better?
In the MainWindow of the project, when Load_Window event fires, I assign the Collection property to listbox.ItemSource(in MainWindow code-behind I declare a private field that obviously refers to an ObservableDVD Object). I have some buttons that allow me to do the operations I tell you before.In the event headler of the buttons, I directly update and modify the ObservableDVD Object, not its property Collection. However, the Collection property also reflects those changes.
Why this behavior occurs?
It's ok for me, but I can't understand why it's happens. Is because of the notifications?
The property Collection has a reference to the view of the ObservableDVD. Being a reference means pointing to the same data in memory.
ObservableCollection Class Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.
The Collection you are specifying is just a "view" of the ObservableDVD collection. Which means that both are really pointing to the same data in the memory, they're not 2 separate things. A "view" can be a subset of items when you apply filters to a collection, for instance.
Otherwise said, your ObservableDVD contains your "Data Table" for the entire dataset while the ICollectionView lets you manipulate which records/objects are visible to the user through custom logic.

Categories