observablecollection question - c#

I have a class/structure like the one given below
public class FileDetails
{
public FileDetails()
{
}
public PrintFile PrintFileDetails { get; set; }
public Boolean IsSelected { get; set; }
public DateTime UploadTime { get; set; }
public long FileSize { get; set; }
public UploadTypes TypeOfUpload { get; set; }
public DateTime DownloadStartTime {get;set;}
public DateTime DownloadEndTime {get;set;}
public bool ShouldDownload{get;set;}
}
In the above snippet PrintFile is defined in a XSD. I am planning to deploy this structure inside a ObservableConnection. If I implement NotifypropertychangedFileDetails will the items under PrintFileDetails also able to reap benefits of INotifypropertychanged. I believe i cannot implement the INotifyPropertyChanged as it is shared among other programmers.

No, each object must implement INotifyPropertyChanged itself. The PrintFile object does not benefit from the fact that the FileDetails object implements an interface.
Also, if you are generating these classes from an XSD, you can tell the generator to generate the classes with INotifyPropertyChanged implementation automatically using the /enableDataBinding command line switch on XSD.EXE.
Footnote: Putting objects that implement INotifyPropertyChanged into an ObservableCollection won't have any magical effects. Changes made to the objects in the collection will not fire the collection's PropertyChanged event (unless you write the code to do so). The collection's PropertyChanged event only fires if a property of the collection object changes.
In most cases, you're using an observable collection because you want to data bind it to WPF or Silverlight UI elements and you want the UI to update itself automatically when the data changes. The data binding system will notice if the objects in the collection implement IPropertyNotifyChanged and will attach to the PropertyChanged events automatically so that the UI will know when the data changes.

Related

Is it acceptable to bind Entity Framework entities to Window Forms controls?

I have two entities: the first is SalesOrder and the second is SalesOrderDetails. In the SalesOrder entity, I have an ObservableListSource list type that keeps track of SalesOrderDetails. The entities look something like this:
public class SalesOrder{
public int Id {get; set;}
public DateTime Date {get; set;}
...
public virtual ObservableListSource<SalesOrderDetails> OrderDetails { get; set; }
publi SalesOrder()
{
OrderDetails = new ObservableListSource<SalesOrderDetails>()
}
}
public class SalesOrderDetails{
public int Id { get; set; }
public int Quantity { get; get; }
public decimal Price { get; set; }
...
}
ObservableListSource extends ObservableCollection and implements IListSource. The GetList method returns a bindingList that stays in sync with the ObservableCollection. The GetList method is an extension method defined in the System.Data.Entity assembly. ObservableListSource looks like this:
public class ObservableListSource<T> : ObservableCollection<T>, IListSource
where T : class
{
private IBindingList _bindingList;
bool IListSource.ContainsListCollection { get { return false; } }
IList IListSource.GetList()
{
return _bindingList ?? (_bindingList = this.ToBindingList());
}
}
To bind the SalesOrder and SalesOrderDetails entities to my form, I use two binding source controls: salesOrderBindingSource and salesOrderDetailsBindingSource. The binding looks like this:
salesOrderBindingSource.DataSource = SalesOrder;
salesOrderDetailsBindingSource.DataSource = salesOrderBindingSource;
salesOrderDetailsBindingSource.DataMember = OrderDetails;
I bind every entity that needs change tracking the same way I bind SalesOrder and SalesOrderDetails. I've been reading that it's not recommended to bind the entities to the UI, that I should use view models and bind those to the UI instead. But that means that I would have to write the change tracking code or find a library that does change tracking.
What do you think?
If it's acceptable for your application to bind to DataSet and DataTable, then it's OK to bind to EF models.
In general, it depends to the requirements of your application; For example, usually for a small-scale or data-centric forms application it makes sense to bind to DataTable or Entity models, but usually in a large-scale application, you may want to consider better patterns for separation of concern.
If databinding to EF models makes sense to your application, then to do it in a correct way, follow this Microsoft Docs article:
EF 6 Fundamentals - Databinding with WinForms
Some notes about the IBindingList, IListSource
The interface that you need in Windows Forms to support databinding to lists, is IBindingList. BindingList<T> is a good implementation of that.
IListSource provides functionality to an object to return a list that can be bound to a data source. So while the object doesn't implement IBindingList, but it can return a bindable list from its GetList method. It's very well supported and used in Windows Forms. For example, DataGridView, ComboBox, ListBox, BindingSource check if the data source implemented IListSource and in this case, they get the data source by calling GetList method. That's why DataTable supports databinding without implementing IBindingList, instead, it returns a DataView in GetList, which implements IBindingList.

Composite Models with INotifyPropertyChanged - PostSharp Delegate Changes from SubModels

First of all, I do use the NotifyPropertyChanged implementation for Change handling and not MVVM implementation.
That said i have the following construct:
[NotifyPropertyChanged]
public interface ISpecimen : INotifyPropertyChanged
{
string Name { get; }
IOpticModel Optics { get; }
}
[NotifyPropertyChanged]
public interface IOpticModel : INotifyPropertyChanged
{
string Lens { get; }
void UpdateOptics(string lens);
}
Now I want PostSharp to Notify me that the Specimen Property Optics got changed (or more precise modified) when I Update the Lens of the IOpticModel. How can i achieve that? Is there anything already ready to go or do i need to create a custom Aspect for that?
I did expect something like that to be ready to use but may be just to blind to find it in the Docs.
This behavior is currently not supported. This means that you'd need to raise the event manually.
You can submit a feature request at https://postsharp.uservoice.com/.

WCF Service-Consumer Syncrohnisation

I am trying to synchronise changes to a DataContract between my service and it's consumers. I am having trouble designing a maintainable way of informing of property changes.
For example, I want to keep the below synchronised:
[DataContract]
public class MyObject
{
[DataMember]
public Guid Id { get; private set; } = Guid.NewGuid();
[DataMember]
public int Foo { get; set; }
[DataMember]
public string Bar { get; set; }
}
My original approach was to use an event which took a property name and an object, as such:
public delegate void PropertyChangedEventHandler(Guid id, string propertyName, object value);
The service & consumers could then subscribe to the property changes:
myObject.PropertyChanged += MyObjectPropertyChanged;
// MyObject would raise the property change inside of the property set.
private void MyObjectPropertyChanged(Guid id, string propertyName, object value)
{
// Depending on which end is listening the service can send
// the change to the consumer or vica versa
}
I have encountered an issue using this method as the serializer could not determine how to serialize object.
I now don't know how to handle informing of changes. I can see two approaches but I am hoping for a better solution.
I could inform the consumer/service that a change has been made. It can then request from the service/consumer for the changed MyObject. I see this being a problem if more than one consumer changes the same object at the same time (as the service is concurrency is set to multiple). It could result in one consumer's changes being lost.
The second approach is to create an EventArgs, which mirrors the properties of the MyObject and you access the property based on the property name passed with the EventArgs and synchronise the local copy. This would allow two consumers to change different properties without fear of either being lost. However this feels like a lot of repeated code. A lot of unused data is also passed around as MyObject grows. Admitidly there is room for reflection in regards to reading and setting the appropriate property.
For example:
public class MyObjectPropertyChangedEventArgs : EventArgs
{
public Guid Id { get; set; }
public string PropertyName { get; set; }
// Then one of the relative property below would be set to the new value
public int Foo { get; set; }
public string Bar { get; set; }
}
I don't see this being an uncommon use case and was hoping for some insight into how this is usually done?
As far as service is concerned, why do not you leverage of CallbackContract in order to notify client that some changes occured?
On client side in turn DataContract can implement INotifyPropertyChanged interface and whenever change to any property takes place then you call service.

MVVM communication between viewmodels with different DTO's

I currently have three models in EF (House,Room,Item).
public class House
{
property int ID { get; set; }
property string Name { get; set; }
property List<Room> Rooms { get; set; }
}
public class Room
{
property int ID { get; set; }
property string Name { get; set; }
property List<Item> Items { get; set; }
}
public class Item
{
property int ID { get; set; }
property string Name { get; set; }
}
In my UI I have a Treeview and a display area to show the items further details for modification when I double click an item in the treeview.
My treeview to improve performance calls a webservice which returns the following DTO/s
public class LayoutItemDTO
{
property int ID { get; set; }
property string Name { get; set; }
property List<LayoutItemDTO> Children { get; set; }
}
these DTO's are mapped built using a query to the database on the house, room, item models.
Now when the user double clicks a house item on the treeview it calls a webservice to return the house model with the rooms collection into a view for the user to add/remove rooms and when they close the view it prompts for a save.
The same happens when the user double clicks on a room (i.e add/remove items to a room).
This all works great apart from keeping the treeview and the opened view in sync so if they change the name of a room or add/remove an item I want it reflecting in the treeview in memory and reverting if they cancel the changes on close.
Currently I have done this using the event aggregator but it seems untidy calling events for each action, if I could just use WPF binding it would all work instantly.
The reason for not using the same models on the treeview is due to these models having a lot more information on them than is shown, when obtaining everything this causes a performance problem.
Databinding and INotifyPropertyChanged
If you want that changes on your objects to be reflected in the UI using data binding, you have to implement INotifyPropertyChanged interface in your model class (or in a ViewModel if you are using MVVM pattern).
By implementing the interface, an event (PropertyChanged) will be triggered each time a property value is modified, and the controls databinded to the property will refresh to show the new values.
You can find an example here: How to: Implement the INotifyPropertyChanged Interface
Collections
For the collection, WPF databinding will work if the collection implements INotifyCollectionChanged. The List<T> type does not implement this interface, so the TreeView won't reflect add/removes from the list. The type ObservableCollection<T> implements this interface, so you just have to change List<LayoutItemDTO> to ObservableCollection<LayoutItemDTO> and the changes should be reflected.
MVVM
As you mentioned using MVVM, I would add that I normally would have ObservableCollection and INotifyPropertyChanged implementations in my ViewModels. You may want to create a LayoutItemViewModel that would encapsulate a LayoutItemDTO.
I can also advise you to have a look at existing toolkits and frameworks that can help a lot for implementing "plumbing code" for MVVM (like INotifyPropertyChanged implementation). I use mainly MVVM Light, but there are a lot of other availabe depending on your needs.
Here is also a good link for implementing TreeView databinding in a MVVM manner: Simplifying the WPF TreeView by Using the ViewModel Pattern

Aggregate detail values in Master-Detail view

I have a master-detail relationship in some custom entities. Say I have the following structure:
class Master : INotifyPropertyChanged
{
public int Id { get; set; } // + property changed implementation
public string Name { get; set; } // + property changed implementation
public ObservableCollection<Detail> Details { get; }
}
class Detail : INotifyPropertyChanged
{
public int Id { get; private set; }
public string Description { get; set; }
public double Value { get; set; } // + property changed implementation
}
My goal is to have a ListView, using a GridView, showing a list of Master objects. When I select a specific Master, I'll have a separate ListView for the details, allowing editing. Basically, a fairly standard Master-Detail view.
However, I also want the GridView for the Master to show the Sum of all of that master's Detail elements, ie: Details.Select(d => d.Value).Sum();
This is fairly easy to display using a custom IValueConverter. I can convert from the details collection directly to a double displaying sum, and bind a TextBlock's Text to the Details OneWay, via the IValueConverter. This will work, and show the correct values when I open the window.
However, if I change one of the detail members, this will not update (even though detail implements INotifyPropertyChanged), since the collection itself is still the same (the ObservableCollection reference hasn't changed).
I want to have an aggregated value in a master list, showing the sum (or average/count/etc) within the detail list, and have this stay up to date when the user changes properties in details. How can I go about implementing this?
Edit:
Ideally, I would prefer if there is a means of accomplishing this that doesn't involve changing the Master class directly. The application in question is using the MVVM pattern, and I'd really prefer to not change my Model classes in order to implement a specific View. Is there a way to do this without introducing custom logic into the model?
I was considering possibilities with the UI where you'd make the binding explicit and perform binding/updates from a command... but it seems that the easiest way to do it would be to extend the ObservableCollection to add/remove listeners to each Detail instance as its added/removed, then just fire CollectionChanged when any of them change. Call it DeeplyObservableCollection<T>.
class Master : INotifyPropertyChanged
{
public int Id { get; set; } // + property changed implementation
public string Name { get; set; } // + property changed implementation
public double Sum {get {return Details.Sum(x=>x.Value);}}
public DeeplyObservableCollection<Detail> Details { get; }
// hooked up in the constructor
void OnDOCChanged(object sender, CollectionChangedEventArgs e)
{ OnPropertyChanged("Sum"); }
}
Worst case you'd have to wrap an ObservableCollection in another type if you can't properly override all the methods you need...

Categories