Databinding to Classmember of Classmember - c#

I need some help about WPF and Databinding.
Let's say I have a ClassA with a member of ClassB. ClassB has again a member,
maybe an int:
ClassB
{
public int MemberOfB { get; set; }
}
ClassA
{
private ClassB _theB;
public ClassB MemberOfA
{
get {return _theB;}
set
{
_theB = value;
// Need to do something here...
}
}
}
When I have a Databinding in XAML like this:
<TextBox Text="{Binding Path=MemberOfA.MemberOfB}"/>
Where the Datacontext of the Textbox is an object of type ClassA.
As you can see, i need to do some computations in the setter of MemberOfA in ClassA.
But with the databinding above, this setter is of course never called, because it binds
to the member of ClassB.
So, how can i get to be informed if the MemberOfA changes (when I Type something into the Textbox)? Are there any best practices?
(Didn't check the code in Visual Studio, so there may be some syntax errors).
Thanks, Walter

The best way to handle this would probably be to make B implement INotifyPropertyChanged. When A gets a new instance of B, have it hook up to the PropertyChanged event (and unhook from the old B's event if necessary).
public B MemberOfA {
get { return _b; }
set {
if (_b != null) { _b.PropertyChanged -= B_PropertyChanged; }
_b = value;
if (_b != null) { _b.PropertyChanged += B_PropertyChanged; }
DoWhatever(_b);
}
}
private void B_PropertyChanged(object sender, PropertyChangedEventArgs e) {
DoWhatever((B)sender);
}

Fundamental problem
In my opinion, all 3rd party vendors ought to implement at least one of NET Framework's standard notification mechanisms, which are:
The original XyzChanged event pattern
INotifyPropertyChanged
INotifyCollectionChanged
OnDependencyPropertyChanged
All of these are fully supported by WPF, so if your vendor implements any of these you should be able to just drop their objects into your WPF application and go.
Unfortunately you will find many 3rd party libraries that don't implement any of these mechanisms: Instead they implement their own custom change notification, or even none at all!
In the rest of this answer I will explain several possible soutions to this problem.
1. Wrap 3rd party objects in wrapper models
You may create a "wrapper model" object to parallel each 3rd party model object that doesn't implement standard notifications. Expose all the 3rd party's properties and methods as your own (yes, this is a lot of code). Register with the 3rd party object's nonstandard notifications mechanism and send standard notifications using INotifyPropertyChanged. This solution is labor-intensive and can be a maintenance headache, but it works well and is many times a good way to make the best of a bad situation.
Many people call these wrapper models "view models" but this terminology leads to confusion: A "view model" is fundamentally a model that models the current state of the user interface such as what the user has open right now, what objects are selected, the current search filter, etc. WPF data binding typically binds to the view model for these types of properties but directly to the model objects themselves for the actual data.
When model objects don't support standard notification, it is common to overload the use of the view model objects to expose both "real" view model properties and also properties from the underlying models. Thus the view model acts both as a real view model and also a wrapper model: The additional properties have nothing to do with UI state but are merely a convenient way to get proper change notification without using a separate wrapper model around the broken 3rd party object.
There is nothing inherently wrong with merging your wrapper model and your view model up into a single object, but it confuses the terminology. For many people I think "view model" has come to be synonymous with "wrapper model" and I think that's a shame. If the wrapper model is kept separate from the view model you get a cleaner interface in your XAML and can more easily adapt once the vendor fixes their change notification.
You may not have time to generate wrapper models for every 3rd party model object, or you may realize that doing so would be impractical due to maintenance issues, updates, or other considerations. It can be a pain to continually be adding and updating your wrapper model every time the 3rd party object changes. In this case I would consider one of the alternative solutions below.
2. Replace DataContext on notification
You may simply tap into the 3rd party's change notification mechanism, and every time an update is signalled simply clear out the relevant DataContext (set it to null), and set it again. This will cause all WPF data bindings to be re-evaluated.
This solution is a bit like killing a fly with a sledgehammer, but it actually works and gets the job done. If it is only simple objects it works well, but as things get more complex it can be messy. If you have ItemsControls or ContentPresenters that create visual trees for your items, setting DataContext to null and back will cause those visual trees to be regenerated. This means you will lose scroll positions, Expander settings, and other UI-specific state within them. You can solve this by binding those properties to a view model to preserve their state.
This solution may be the only solution if the 3rd party's change notification mechanism is broken or inconsistent. It also tends to be the simplest "quick and dirty" solution if you need to get something usable out the door TODAY.
3. Wrap using TransparentProxy / RealProxy
If your 3rd party library includes a sane and consistent but nonstandard change notification mechanism, you have another alternative: You can implement a generalized mapping between the 3rd party mechanism and the standard INotifyPropertyChanged mechanism using the TransparentProxy / RealProxy mechanism of NET Framework.
To do this:
Expose the INotifyPropertyChanged interface on the TransparentProxy, and on your RealProxy handle add_PropertyChanged and remove_PropertyChanged by registering with the 3rd party's event notification system
When the RealProxy receives a property get on a property, do any 3rd party registration required for change notification on that particular property (if not already done) before returning the property
Automatically convert each object returned by the 3rd party property getters into a TransparentProxy of the same object.
Now you can bind your DataContext to an intially-constructed TransparentProxy and from then on pretend the 3rd party library uses a standard change notification mechanism and is completely compatible with WPF.
The TransparentProxy / RealProxy solution is a lot of work to set up and is specific to the 3rd party library's notification mechanism, but once it is working you don't need to worry about out-of-sync UI or losing UI state during refreshes.
4. Use a timer
If the 3rd party library provides no change notifications at all, you can simply set a timer that periodically checks for changes.
Your timer will probably scan the 3rd party object for relevant changes from the values during the last scan. If any are found, it uses one of the previous techniques to provide a standard notification of the changes. In other words, it will signal the wrapper model or RealProxy of the change or it will clear/set a DataContext.
The simplest possible timer solution just periodically sets DataContext to null and then sets it back again without checking for changes.
5. Encourage your 3rd party to implement one of the standard mechanisms
NET Framework defines four different change notification mechanisms, all of which are fully supported by WPF, so it seems inexcusable for anyone to generate objects that support none of these.
Hopefully the next version of your third party library will properly implement one of these standard change notification mechanisms. Contact your vendor and ask them to do so, or at least to create bridge code.
The sad part is, at the moment Microsoft is the worst culprit of all: Neither LINQ to SQL nor LINQ to Entities implements standard change notification on their objects! I think that's too bad because people tend to follow Microsoft's example.

Related

Defining properties of UI using Attributes

For a new project, I was recently asked to investigate a method of attaching information related to UI rendering to business objects in a WPF application. For example a report class:
class ExecutionReport
{
[Displayable(Bold, Background=Color.Red)]
public String OrderId{get; private set;}
[Displayable(Normal, HAlignment=Center)]
public String Symbol {get; private set;}
// this should be hidden as it doesn't have DisplayableAttribute
public String ClientOrderId {get; private set;}]
[Displayable(Normal, HAlignment=Right,
Format("If [Position] < 0 then Background=Color.Red"),
Format("If [Position] > 0 then Background=Color.Lime"),
DisplayFormat("+#;-#;0")]
public Int Position {get; private set;}
}
This is a very new approach for me as typically in most wpf MVVM applications I have worked on there has been a clear separation of the view and viewmodel and I strive as much as possible to keep UI specific details out of the VM. Instead I would lean towards writing this using resource dictionaries and simple converters applied on the bindings in the view layer.
My questions are: Are there any wpf/mvvm frameworks out there that use this kind of an implementation? If so I'm curious to see how it would be achieved.
Are there any obvious pitfalls? The first couple things that come to my mind are
Change notification (ie. INotifyPropertyChanged to trigger an update of the view). Would the implementation of this be a lot harder now?
Difficulty in being able to leverage resource dictionaries for system wide values. For example, maybe I wanted to change the color of red being used throughout the application. I would have to ctrl + f through and find every place in business objects where it was used and change it instead of being able to modify a single StaticResource
Inability to leverage DesignTime DataContexts
Performance. Seems likes this would require heavy use of reflection which might not be as performant as typical value converters
I'm very interested to see if I'm correct on the second and third points or if both of these things could still be acheived?
Ultimately I feel that this is a bad design and I'm leaning towards writing a different implementation to show the interested party how I would typically approach this kind of problem. Just want to make sure I'm not missing something obvious that might actually make this more elegant.
IMO this seems like a horrible idea, they all seems like examples that should be implemented as XAML converters.
All of the points list seem to be valid reasons to avoid doing this.
Note: There are a set of attributes in the framework which provide some UI functionality already (very limited), see the System.ComponentModel.DataAnnotations namespace.
This approach is very popular and it's called aspect oriented programming (ASP.NET MVC leverages it a lot). The most popular library to write this fast is PostSharp (see customers case studies, there are some companies which have used it for WPF). The best thing in PostSharp is that uses compile-time weaving.
For the first point:
PostSharp got well tested NotifyPropertyChanged aspect, you can add [NotifyPropertyChanged] attribute to class and all properties will call PropertyChanged when value gets changed.
For the second point: you can always make your attribute to look for StaticResources and pass resource key in attribute.
For the third (although I'm not 100% sure about it) and fourth point: compile time weaving means that aspect is "appended" to code on compilation - like you would have written it inside method/property to which you have appended attribute. It's like post-build compiler and doesn't use reflection (if aspect you wrote doesn't use reflection) so performance is really good.
However in example you gave I'd rather go with value converters and styles like #AwkwardCoder said - but aspects(attributes) are also useful with "view" for example: they're great for validiation.
I agree that this seems like a horrible idea, and your comment ...
in most wpf MVVM applications I have worked on there has been a clear
separation of the view and viewmodel and I strive as much as possible
to keep UI specific details out of the VM. Instead I would lean
towards writing this using resource dictionaries and simple converters
applied on the bindings in the view layer
... I think sums up why and how to avoid it.
Tying your business objects directly to implementation details such as colour, horizontal alignment, or position, seems like a short-term win (but long term hell).

Proper way to communicate/pass values between viewmodels?

I know there's a lot of questions on the topic and I understand how to do it but I need some help on the design of my architecture. I'm using the Simple MVVM Toolkit.
Architecture
I have a ShellVM which is the main VM for my app. It dishes out navigation and props that my main view binds to.
Then I have a ManageVM that does all the grit work for managing the client, stores, imports, exports etc. It also handles navigation of all my management views.
Then I have an ImportVM that fleshes out the importing of data.
I also have a static PageValues dictionary that stores pages and specific properties and values that should be retained when switching views. It also stores any 'global' properties that is used throughout certain VMs.
I'm using Messaging to pass data between the VMs. The validation and prompts (using dialogs) of the PageValues data is controlled in my ManageVM. I placed it here as I feel my ManageVM should handle all 'management' like setting the client and store. Setting the actual values is done by sending a message to the ShellVM that handles this.
The ShellVM handles the CRUD of the PageValues. So in other words, if any VM gets or sets a global/shell-wide property, it does so by means of messaging to the ShellVM. The ShellVM then sends the message/result back to whichever VM requested it.
Question
This feels very spaghetti-like. I've got a ManageVM that does the loading and validations on PageValues that are actually CRUD'ed in the ShellVM.
Am I on the right track or is there any other suggestion I can try to make this feel a bit cleaner?
Thanks for reading.
Edit
What I'm trying to achieve is to have a container that holds values (ie client and store) that could be accessible from multiple VMs. A bonus is to have each page's/view's values in this container too. Then on showing of the view, it will grab its values from the container and populate the view.
You said
if any VM gets or sets a global/shell-wide property, it does so by
means of messaging to the ShellVM
I propose an interface based approach instead of message passing for this purpose. ViewModels passing messages is for view models to communicate,not for setting a global state. If there is a global state of the application,it is better handled through a dedicated service, IMO.
public interface IApplicationService
{
//your applcation methods here
}
public class ApplicationService:IApplicationService
{
}
public class ManageVM
{
public ManageVM(IApplicationService){}
}
public class ShellVM
{
public ShellVM(IApplicationService){}
}
public class SomeOtherVM
{
public SomeOtherVM(IApplicationService){}
}
Yes, this does sound rather messy. You need to try and isolate areas of functionality into their own VMs so they are not dependent on one another.
One of the tricks I use to do this is to try and imagine that I suddenly need to copy a blob of functionality (say one of your pageviews) into another application. How easy would it be? Would it be a case of just copying one VM and injecting a few dependencies? Or is the VM impossibly coupled to the rest of the app?
It's a bit difficult to give advice without knowing exactly what your app is doing, but really you want each PageVM to be in charge of it's own validation, and CRUD. Or, if the data is shared between many pages, then you need to pass in some kind of repository than the PageVMs can query for data. If validation logic is specific to some data, then put it on the model itself and just leave the presentation of that validation to the VM.
For global settings, I tend to pass around a settings object rather than using messaging.
Have a read up on inversion of control, and dependency injection. These can help you to keep objects loosely coupled because you can see exactly what other things your object is depending upon by looking at the constructor. If you are passing in half the application then it can serve as a warning alarm to try and reduce the coupling.

Proxy objects to simulate a soon-to-be-created database

I have a database that contains "widgets", let's say. Widgets have properties like Length and Width, for example. The original lower-level API for creating wdigets is a mess, so I'm writing a higher-level set of functions to make things easier for callers. The database is strange, and I don't have good control over the timing of the creation of a widget object. Specifically, it can't be created until the later stages of processing, after certain other things have happened first. But I'd like my callers to think that a widget object has been created at an earlier stage, so that they can get/set its properties from the outset.
So, I implemented a "ProxyWidget" object that my callers can play with. It has private fields like private_Length and private_Width that can store the desired values. Then, it also has public properties Length and Width, that my callers can access. If the caller tells me to set the value of the Width property, the logic is:
If the corresponding widget object already exists in the database, then set
its Width property
If not, store the given width value in the private_Width field for later use.
At some later stage, when I'm sure that the widget object has been created in the database, I copy all the values: copy from private_Width to the database Width field, and so on (one field/property at a time, unfortunately).
This works OK for one type of widget. But I have about 50 types, each with about 20 different fields/properties, and this leads to an unmaintainable mess. I'm wondering if there is a smarter approach. Perhaps I could use reflection to create the "proxy" objects and copy field/property data in a generic way, rather than writing reams of repetitive code? Factor out common code somehow? Can I learn anything from "data binding" patterns? I'm a mathematician, not a programmer, and I have an uneasy feeling that my current approach is just plain dumb. My code is in C#.
First, in my experience, manually coding a data access layer can feel like a lot of repetitive work (putting an ORM in place, such as NHibernate or Entity Framework, might somewhat alleviate this issue), and updating a legacy data access layer is awful work, especially when it consists of many parts.
Some things are unclear in your question, but I suppose it is still possible to give a high-level answer. These are meant to give you some ideas:
You can build ProxyWidget either as an alternative implementation for Widget (or whatever the widget class from the existing low-level API is called), or you can implement it "on top of", or as a "wrapper around", Widget. This is the Adapter design pattern.
public sealed class ExistingTerribleWidget { … }
public sealed class ShinyWidget // this is the wrapper that sits on top of the above
{
public ShinyWidget(ExistingTerribleWidget underlying) { … }
private ExistingTerribleWidget underlying;
… // perform all real work by delegating to `underlying` as appropriate
}
I would recommend that (at least while there is still code using the existing low-level API) you use this pattern instead of creating a completely separate Widget implementation, because if ever there is a database schema change, you will have to update two different APIs. If you build your new EasyWidget class as a wrapper on top of the existing API, it could remain unchanged and only the underlying implementation would have to be updated.
You describe ProxyWidget having two functions (1) Allow modifications to an already persisted widget; and (2) Buffer for a new widget, which will be added to the database later.
You could perhaps simplify your design if you have one common base type and two sub-classes: One for new widgets that haven't been persisted yet, and one for already persisted widgets. The latter subtype possibly has an additional database ID property so that the existing widget can be identified, loaded, modified, and updated in the database:
interface IWidget { /* define all the properties required for a widget */ }
interface IWidgetTemplate : IWidget
{
IPersistedWidget Create();
bool TryLoadFrom(IWidgetRepository repository, out IPersistedWidget matching);
}
interface IPersistedWidget : IWidget
{
Guid Id { get; }
void SaveChanges();
}
This is one example for the Builder design pattern.
If you need to write similar code for many classes (for example, your 50+ database object types) you could consider using T4 text templates. This just makes writing code less repetitive; but you will still have to define your 50+ objects somewhere.

Using DependencyProperty on ViewModel with Entity Framework

I am writing a desktop application in C# using the MVVM pattern with an Entity Framework model. I tend to use DependencyProperties in my VM's and have come to (generally) prefer this system over implementing INotifyPropertyChanged. I would like to keep things consistent. My VM accesses the Entities in the Model and I have managed to keep things pretty separate - the View has no knowlege of the VM except for binding and command names and the Model has know knowlege of the VM.
Using INotifyPropertyChanged in the VM, it seems pretty easy to update the Entities in the Model:
public string Forename
{
get { return CurrentPerson.Forename; }
set
{
if (Forename != value)
{
CurrentPerson.Forename = value;
NotifyPropertyChanged("Forename");
}
}
}
...where CurrentPerson is a Person object auto-created by the Entity Data Model. There is therefore no private field created specifically to store the Forename.
With DependencyProperties, it appears that I would have to create a DP, add the default Property, using GetValue and Setvalue and then use the PropertyChangedCallback in order to update the CurrentPerson Entity. Calling a callback in this situation appears to be adding overhead for the sake of being consistent with my other VM's.
The question is therefore whether one or other of these methods is the way I should do things? In this instance, should I use a DependencyProperty or INotifyPropertyChanged? One thing that should be pointed out is that this will potentially be a very large scale project (with plugins and a lot of database accesses from different machines) and that everything really should be as reusable, and the modules as "disconnected", as possible.
I would recommend using INotifyPropertyChanged instead of DependencyProperty. The main reason I stay away from DependencyProperty in ViewModels is because the DependencyProperty is located in WindowsBase.dll. This ties you to the Windows UI a bit too much (at least IMHO).
Using the INotifyPropertyChanged is a lot easier to maintain since it allows the various plugins to implement it the way they want. If you force Dependency Properties, all viewmodels need to inherit from DependencyObject.
See this article for more details about the use of INotifyPropertyChanged and DependencyProperty: http://kentb.blogspot.com/2009/03/view-models-pocos-versus.html
Another supporting answer: https://stackoverflow.com/a/783154/27669

Design time data in WPF / Silverlight - how to use wrapper classes correctly?

I am facing a problem of "design time support" best practices. I am using PRISM, and my objects are created by a DI container. Lets assume the following simple scenario:
I have an object workflow. This workflow has several properties, and there is a WorkflowProvider which provides a list of workflows.
If I design the ListView I do not have a problem. I am using a MainApplication object as design time data context, and my list binds to the property "WorkflowList". In my live application I can set the data context to the appropriate implementation.
But I do not know how to handle a single workflow view!
Normally I would create a workflow object as design time data context. But my workflow object can't be created on its own (with an empty constructor), it has to be a property of e.g. my WorkflowProvider. So one approach I used in the past was this:
Write a dummy subclass for workflow
In the empty constructor of the dummy, get the "real workflow"
Assign all properties of the "real workflow" to the properties of my dummy class
Use an instance of the dummy workflow in my design time view
The only reason for that is that I do not know how to set the design time data context to a property, instead of an object. Is this possible, or is there any other way which makes sense. To clarify, I know I could bind e.g. my grid in my "workflow details view" to a property, but then I could not use the details view without changes as a DataTemplate in my list view. I hope you got my problem :-)
Chris
Ok,
like so often, a little bit thinking and a good guess solved my problem:
d:DataContext="{Binding WorkflowProvider.CurrentWorkflow}"
does the trick, and will be ignored in real time scenarios...

Categories

Resources