Custom property dependant on other properties - wpf

Advance apologies for the event-style explanation; there's a lot of factors that I feel all play a role of their own. WPF is not my native framework of choice, and it probably shows. :)
Old situation: I had a window with several controls. Depending on their selections, I used multibindings and a converter to determine whether certain controls needed to be shown that inform the user about the implications of their changes before they'd eventually confirm them by OK (or simply dismissed by using Cancel). This worked perfectly.
Problem: Too many controls as time went by, too much clutter.
Solution: Put stuff in different Pages so it becomes easier to browse for the user. In order to have changes-to-be persist as a user arbitrarily browses between the pages, I create these dynamically and put them in a cache (Dictionary<string, BasePage>, see below), from which they will be pulled as the user chooses them.
Consequence: I need to decouple the bindings to the notification controls as the different options are now on different pages.
Solution? I put a BasePage class in that exposes certain abstract read-only properties that define the various aspects that the window needs to know about in order to do its notifications. For example, a bool requiresReboot property defines whether the current state of things on that page requires a reboot to take (full) effect. A specific page implements the property based on its controls.
Problem: I do not know how to keep create a proper binding that properly gets updated as the pages are changed. I tried giving my notification controls a binding to the Dictionary<string, BasePage> with a converter that checks all pages and the relevant property.
Questions:
1) How do I create a proper property for this purpose? I presume I need a DependancyProperty as I did a fair bit of reading on MSDN, but I can't figure out how this fits together.
2) How do I make a link between my custom property so that it allows (multiple) control(s) on a page to change that property? Do I use INotifyPropertyChanged somehow? My old example bound against several CheckBox.IsChecked properties in XAML. I am trying to avoid putting tons of events (OnChange, etc) on the controls as the original code did not need it and I have been told it makes for a messy solution for as far WPF is concerned.
3) Finally, I suspect I may need to change my Dictionary<string, BasePage> class to a custom implementation that implements some sort of INotifyPropertyChanged but for Collections? Observable Collection is the term I am looking for, I believe.
I hope someone is able to bridge the gap in my understanding of WPF (property) internals; I would very much appreciate it. A basic sample would be even better, but if it is too complicated, just a nudge in the right direction will do. Thank you. :)

It's been a while since I solved this, and while I cannot remember the exact cause of the problems, there were a few different issues that made up the bulk of the trouble I ran into.
I ended up making the Property in question a non-abstract DependencyProperty in the base class; it was the only way in which I could properly delegate the change notifications to the interface. Derived classes simply ended up binding it to their controls (with a proper Converter in the case extra logic was necessitated).
As Dictionary<string, BasePage> does not support any sort of change notification, I made an extra collection of ObservableCollection<BasePage> which I used for binding purposes.
However, such a collection does not propagate a change event when items inside of it has a property changed. Since this situation required that, and I was binding to the collection itself in the context of a property that does not have a Master<->Detail relationship like a DataGrid (which basically add their own OnPropertyChanged handlers to the binded object), I ended up subclassing a VeryObservableCollecton<>. This one listens to its own items, and throws a proper change event (I think it was an OnPropertyChanged from the INotifyPropertyChanged interface) so that the binding (or in this case a multi-binding) would refresh properly and allow my interface to update.
It is hardly the prettiest code, and it feels over-engineered, but at least it allows me to properly bind the UI to the data in this manner.

Related

WPF resetting DataContext to refresh binding

I have a project that gets data from a database and binds that data to some elements in xaml. I have added a button that fetches new data from the database and want to refresh the data bound elements in the xaml.
Now, I know the proper way of doing this is to implement the INotifyPropertyChanged events in the data class but I wanted to avoid this as there are so many properties. I figured out that simply calling 'this.DataContext = data;' after I have retrieved the new data from the database updates the binding in xaml.
Can anyone tell me what is wrong with this method?
Thanks!
Quite simply, if you don't want to implement the INotifyPropertyChanged interface, then don't use WPF. WPF is quite often a verbose language... it took me a while to get used to this. While there are mechanisms like Converters, Styles and Attached Properties that enable us to reuse code, you will often find yourself writing code that you've written before. Just get used to it, or change languages.
To summarise, you can't write effective applications in WPF without implementing the INotifyPropertyChanged interface.
If you don't use INotifyPropertyChanged interface you don't allow the binding mechanism to work since it wont know of any changes of your data.
The data binding is one of the most powerful tools in WPF if you dont use it you will have to write the propagation of the data changes between you model and the UI yourself like it was done in Winforms....
if its too hard to write the implementation for each property of each class in your than you can create a code snippet.. like prop/propdp

How to use MediaElement.NaturalDuration to set MediaTimeline.Duration in WPF MVVM

My MVVM program is a media player and uses the Media Element's Natural Duration property to set the Media Timeline's duration. Before I implemented MVVM design pattern, I could simply put
MyMediaTimeline.Duration = MyMediaElement.NaturalDuration;
in the code-behind. I am new to using MVVM but I believe this is not the correct way to perform this action according to the MVVM design pattern. I believe that MediaElement.NaturalDuration is not a dependency property so it cannot be bound to directly. Do I need to make it a dependency property somehow? Would this be coded in the ViewModel?
When we need to implement functionality like this that relates to UI controls using MVVM, we have a few options. One is to implement some kind of service or manager class that can implement this functionality for us and another is to use Attached Properties. Out of these two options, I believe this second option to be more suitable for this problem.
However, there is absolutely nothing wrong with adding event handlers into the code behind of your view, even when using MVVM. I keep seeing new users panicking over what to do rather than use the code behind when using MVVM. This is a common misconception about MVVM.
If you really know how to use Attached Properties properly, then I would advise that you use one (or more) of those to solve your problem, otherwise I would happily advise you to use the code behind. Note that if your view models are correctly data bound to your views, then you can access your view model from the code behind like this:
TypeOfViewModel viewModel = (TypeOfViewModel)DataContext;

viewmodel have to be public. How should I deal with that?

Pretty much it summarizes my problem here:
Double check - does it ever make sense to have internal viewmodel class?
I have controls.DLL and I'd like to keep this custom control bindings and viewmodel's internal. However, this doesn't seem to be possible.
How do you get around that? The only way I see it - don't use bindings..
Why do you have a view model for a custom control? I assume you're assigning the view model object to the DataContext property, but this is almost always a mistake: the DataContext should be available to consumers to use and abuse as they please. Stated another way, what happens if a consumer of your custom control explicitly sets the DataContext? It sounds like your control will stop working and throw a bunch of xaml binding errors.
A custom control is inherently lookless. There is no model or view model, just a view. That view is the .cs file. You supply a default look via your themes/generic.xaml file, but consumers should be able to supply their own template. If you're tying them to a view model, they also need to know how to create a view model instance and all of its dependencies. You've just created highly coupled code. DI containers can loosen the coupling, but that just downgrades the relationship between classes from "coupled" to "related". I say, why do consumers even need to know that information?
A better approach is to provide all of the properties for your control as dependency properties. Then your generic.xaml can provide a control template that uses the more efficient TemplateBinding to bind properties/objects to your control. If you need to populate these dependency properties from a business object, expose another dependency property of type IBusinessObject and set the derived values in that object's PropertyMetaData changed handler. If your IBusinessObject type contains a property which is yet another class which implements INotifyPropertyChanged, you should probably (1) rethink your object graph or (2) create a Bnding object in code using the subclass.
I think following all of the above advice will eliminate the problem about which you're concerned plus the other problems as well. Leave the view models to the UserControls. And yes, this is why custom controls are a MASSIVE headache. Doing them right is fairly involved.
Try protected internal. I suppose this should work. Although I don't think its good idea to have the ViewModel not public at all, cause one of the purposes of it is to be able to define several Views against the same ViewModel, which may come from different assemblies.

Is it just me, or is WPF a mess of databinding and custom IValueConverters?

Seriously, it seems like every time I want to make my UI elements talk to each other, I end up coding a new, custom, IValueConverter :(. Someone tell me that I'm doing it wrong, please!
Examples:
I wanted a button to be enabled only if my textbox contained a valid URI. Great, time to code up a UriIsValidConverter!
Oh oops, I also wanted to disable it while I'm processing something. I guess now I need to code up a UriIsValidAndBoolIsFalseMultiConverter!
I want to display a list of files in a certain directory (specified by a textbox) inside a listbox. I guess I need a DirectoryPathToFileList converter!
Oh hey, I want icons for each of those files in the listview. Time for a FileInfoToBitmap converter!
I want my status to be red if my status-string contains "Error", and green otherwise. Yay, I get to code up a StatusStringToSolidColorBrushConverter!
I'm really thinking this isn't that much better than the old Windows Forms method of just wiring up everything manually using TextChanged events (or whatever). Which I guess is still an option. Is that what people actually do, perhaps, and I'm trying too hard to make everything fit into the databinding paradigm?
So yeah, please tell me if this is really how WPF coding is---or if I'm doing it wrong, and if so, what I should be doing.
Your approach is perfectly valid (though I would use a multibinding for the second example, rather than a such a specialised converter), though by placing all your logic into the XAML you are producing very high coupling between the way the application looks and the way that it behaves, because of this you may want to look into the MVVM pattern to separate those things out.
Under the MVVM pattern your XAML (the view) just contains very simple data bindings into a ViewModel which handles all the logic and updates the view through the INotifyPropertyChanged interface. The code for your third example may look something like:
public class DirectoryManagerViewModel : INotifyPropertyChanged
{
private string _directory;
public string Directory
{
get { reutrn _directory; }
set
{
if (_directory != value)
{
_directory = value;
OnPropertyChanged("Directory");
if (IsValidDirectory(value))
{
PopulateFiles();
}
}
}
}
public ObservableCollection<FileViewModel> Files { get; private set; }
private bool IsValidDirectory(string directory)
{
//return if the directory exists etc.
}
private bool PopulateFiles()
{
//Populate Files with files in directory
}
}
Where FileViewModel is another view model which contains the name and the icon for a file.
The advantage of this approach is that the ViewModels can be reused with other views and other technologies such as ASP.NET or Winforms so you are not locked into the WPF stack. (alos if you work in an environment where there are designers responsible for the look and developers responsible for the behaviour, this helps define those boundaries)
At the end of the day though this logic does need to go somewhere and while there are better and worse ways to architect your application you are still going to be writing code that takes a string and converts it into a series of filenames and icons somewhere.
First, you might want to start by reading about the Model-View-ViewModel pattern (MVVM). Josh Smith had a fantastic article in MSDN Magazine recently. MVVM and WPF go perfectly together. Done right, you won't need IValueConverters so much. The way that you are going about it now is causing a very tight coupling between your visualization and your application actions. MVVM is designed to decouple these elements.
In this context, your view model will track state for you. Your button will be enabled if the CanExecute method on a certain ICommand in your view model returns true. This same concept can handle disabling the button when processing something.
You want to display a list of files in a certain directory that is specified inside a listbox? Have a DirectoryViewModel view model that will handle providing the list of files to the view by binding to the view model. The display of the files can be specified with a DataTemplate specified in XAML with no code behind. This same concept can handle providing the icons to the view whose display can be specified in the template.
You want your status to be red if a status message contains "Error" and green otherwise? Let a view model handle determining the state and let the view bind to that state and now you only need an IStateConverter to convert the state to red or green appropriately (this is one of many ways to handle this problem in the MVVM context).
Get in the habit of keep data and state separate from your view and your applications will be loosely coupled, easier to design and maintain, and easier to test.
Don't know if you are wrong, just making it a lot harder than it has to be!
I use MVVM, so where you are writing customer converters, I provide a bindable property on the view model that tells the view what to do. For example:
To display a list of files, I provide a collection that contains that list.
If I want icons the object in that collection has a icon property
If I want a status to be red or green I provide a StatusColorbrush property.
By moving this logic into the view model, I get:
much simpler Xaml.
can test my view logic without the view.
This approach uses one of the strong points of WPF, it's binding capabilities.

Does WPF databinding make things more of a pain than it is worth?

Ok,
So I have been stalled in my latest non-work project, trying to use WPF. I am just frankly annoyed at databinding. I thought it was supposed to make things simpler by binding data directly to the UI. But the more I learn about having to implement INotifyPropertyChanged to get things to notify the UI if they changed, seems to make the whole thing counter productive.
Am I missing something? It seems like a bunch of work and having to make the classes implemented INotifyPropertyChanged seems like a fishy way to get databinding to work.
What am I missing? I must be missing something. Please enlighten me into how to make databinding easy, or at the least straightforward.
If you want the UI be notified when the underlying data source changes, then you need some sort of notification mechanism. For WPF, INotifyPropertyChanged is that mechanism.
It's the same in Windows Forms as well, but Windows Forms also supports the old notification mechanism, where you have an event with the name <Property>Changed.
However, neither of these required these mechanisms if all you want to do is bind to the data once and display it.
If you are ok with not receiving notifications, then just bind to the data source and it will work.
Truth be told, I haven't seen that it was that bad, and think it a highly workable solution.
Take this simple, Data Model object:
Public Class SimpleItemViewModel
Implements INotifyPropertyChanged
Private _item As String
Public Property Item As String
Get
return _item
End Get
Set (value as string)
_item = value : OnPropertyChanged("Item")
End Set
End Property
Protected Overridable Sub OnPropertyChanged(propChange as string)
Raise Event PropertChanged(me, new PropertyChangedEventArgs(propChange))
End Sub
Public Event PropertyChanged(sender as object, e as PropertyChangedEventArgs)
End Class
That is easily bound to a simple Textbox via:
<Textbox Text="{Binding Item}" />
additionally, if I wanted to have a DIRTY flag, I can easily put the flag being set in the OnPropertyChanged sub, and easily determine if I need to save any user changes or not.
I have found it easiest to have a set of classes which rest between the Data Access layer and the UI which holds this stuff. You can even have your Business Logic and DAL pass these classes around rather than the atomic values.
Implementing INotifyProperty changed is not particularly difficult, seeing as it only has one member.
If you don't expect changes in the underlying object then don't worry about INotifyProperty changed, and use a Binding with Mode=OneTime.
If the underlying object can change and you want the GUI to reflect those changes, then how else can this be achieved without the kind of notification that INotifyProperty changed provides? It's not reasonable to expect a bound item to poll its binding's source.
Personally I've found WPF has taken some time to get to grips with, but now that I'm gaining comfort I'm finding it incredibly powerful and enjoyable to work with. I encourage anyone who's finding WPF challenging to stick with it.
Binding in XAML is quite easy, however, dynamic WPF data binding in code is painful and confusing.
DataBinding is the only way to implement a model-view pattern in WPF/Silverlight. Your models can be UI-stupid by implementing INotifyPropertyChanged, which isolates them from the UI. It also saves a lot of UI code when stuffing information into the UI.
Another benefit that I enjoy is the ability to further bind child controls with the same data by using the { Binding } shortcut.
First, INotifyPropertyChanged isn't the only way to get data binding to work - dependency properties work too.
Second, INotifyPropertyChanged can be implemented with just one line of code in your entity class, if you use AOP - you don't actually have to do all those notification calls yourself.
Overall, I'd say data binding is a great boon, especially when you're doing code generation to make automatically bound controls from some data source.
If you're looking for a good way to think about structuring your data binding, then aim to set a DataContext on your logical tree only once, then use binding paths to populate the various parts of your UI.
Be as declarative as you can in your binding. Let the template system do it's job and make heavy use of DataTemplates that specify explicit DataTypes.

Resources