.net WinForms data binding using Lambda instead of property - winforms

In my project I have a model and I want to bind the visible state of a label using one of the model properties. I do not want to add another ShowLabel property to the model. I want to be able to write something like this:
label.Bindings.Add("Visible", model, m => m.Name != "Default");
Basically I want to be able to write a lambda expression instead of adding a property to my model. Is this possible?

Yes, you can do this using the Format event of the Binding class. You'll still bind to the property in question, but your Format event handler will return a different value (a bool in this case).
var binding = new Binding("Visible", model, "Name");
binding.Format += (sender, args) => args.Value = (string)args.Value != "Default";
label.DataBindings.Add(binding);

Windows Forms data binding recognizes the ICustomTypeDescriptor interface, which allows an object to decide at runtime which properties it presents to data binding. So if you write an implementation of that, you can tell Windows Forms that you have whatever properties you feel like having, and you can decide how to implement them.
Of course, that may not help - if you wanted to avoid adding a property, you may also want to avoid implementing a fairly complex interface. The obvious solution would be to write a type whose job is to act as the data source and bind to that instead of whichever object you're currently binding to.
Of course, if you do that it's probably then easier just to implement whatever property you were going to implement on that wrapper instead.
In general with databinding, you want to avoid binding directly to some underlying model, precisely because you don't want to have to add things to your model purely for the benefit of the UI. This is why 'separated presentation' is very popular - instead of connecting the model and view directly, you stick something in the middle whose job is to mediate. Some call this a viewmodel, some call it a presenter, but the basic principle is always separation of presentation.
It sounds like you're trying to achieve separate of presentation (which is good) but without introducing an extra type so that this middle layer has somewhere to go. Why not just define a class (or a set of classes) to act as that layer?

Related

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.

Parameterize ValidationRule in WPF

I've only scraped the surface of validation in WPF and have come across a scenario that is likely fairly common: I have a TextBox whose value needs to be validated against a variable data type, depending on the context. For example, if the context's data type is 'int,' then the TextBox needs to accept only input that can be converted to an Int32.
My first thought was to inherit from the ValidationRule class and to include the context and to use a switch inside the overridden Validate function, but I am unable to bind anything to it since it is not a FrameworkElement.
Any thoughts?
You can expose IDataErrorInfo. This lets you do data validation with complex logic.
Personally I don't like using IDataErrorInfo for something this simple because it requires a gratuitous creation of a ViewModels and a lot of extra code where none should be necessary. It should be as simple as this:
I have a markup extension that allows me to create a binding with custom validation code specfied as a C# expression. This is extremely simple to do, except for the C# parser: Just implement ProvideValue() by constructing a MultiBinding that uses a converter and builds the appropriate validation structure. This allows the validation expression to receive the containing DataContext and the user-specified Binding object in addition to the value being validated.
With this solution coded, you can do something like this:
BoundProperty="{my:ValidatedBinding
Path=SomeProperty,
ValidationExpression = context is TextBox ? (int)value>3 : (int)value<7,
Mode=TwoWay,
Converter=...
You could easily adapt my solution without the C# parser by creating the expression as a lambda in the code-behind and referencing it with x:Static:
public static reaonly Expression myValidatorExpression =
(object value, object context, BindingBase binding) =>
context is TextBox ? (int)value>3 : (int)value<7;
...
ValidationExpression={x:Static local:MyClass.myValidatorExpression}
In general I find this technique easier and clearer than using ViewModels. I still use ViewModels when there is a complex transformation needed, otherwise just pure XAML straight to the business objects layer.
Note that this approach assumes your business objects layer is not tied to any particular the back-end storage layout (eg SQL table structure). If it were, changing the back-end storage would require changing my UI and this would not be desirable either, so a ViewModel would be desirable from that standpoint. But if not, I always prefer to keep it simple and just use straight XAML.

WPF data binding and type conversion

I have a question regarding WPF binding and converting the data types seen by the UI objects in XAML.
I have a user control that I would like to reuse in different applications. The user control displays a thumbnail image and several TextBlocks to display person demographic information such as name and address. The user control is used in an MVVM design, so it’s bound to a ViewModel specific to the user control.
Following typical MVVM design principles, The ViewModel for the user control is often embedded in other ViewModels to make up a larger UI.
The user control view model expects a certain type (class) as its binding object.
However, the ViewModels in which the UC’s VM in embedded have entirely different object models, so they cannot simply pass-through their data to the UC’s VM. There needs to be a conversion of the parent VM’s data model to the UC VM’s data model.
My question is this: Is there a sanctioned way to perform this conversion?
I looked at IValueConverter and IMultiValueConverter and these do not look like the way to go.
I guess what I need is a sort of shim between the parent VM and the embedded UC VM where the parent VM’s data is converted to the format required by the UC VM.
Or, does it basically come down to I have to write a custom UC VM to handle whatever types the parent VM provides?
I agree with Ken, I think he has the answer. If you have n many configurations of your data that you want to pass into a common user control, then you want the owner of that configuration of data to convert it into a common form to be bound to the user control.
Each view that uses the control would have a corresponding view model that exposes a property in a common format:
public class SampleViewModel {
...
IUserControlData ControlData
{
get
{
// Do conversion here or do it early and cache it.
}
}
...
}
Then you would bind that property to your user control in the view
<common:CommonUserControl DataContext={Binding Path=ControlData} ... >
If the parent VM is a superset of the child VM, normally the parent VM would just hold a reference to the child VM. It would expose that reference as a property, and you would bind a ContentControl (or whatever) to that property.
Would this not solve your problem?
If you really want and need to do type conversions, the value converters are exactly what you want to use. That said, typically the type of conversions handled by things like IValueConverter are relatively simple and direct.
If, however, your top-level/parent/management user control needs to parse off bits and pieces of some larger type to the user controls which host its actual content, then that is the job of that top level control. Don't get all wrapped up in doing all of this in XAML. It's perfectly fine to parse off what you need and set these child control properties directly.
Probably not what you are looking for but this is a solution for DataGrid dynamic columns. With datagrid you can pass a parameter. http://www.codeproject.com/Articles/36496/Binding-a-Silverlight-DataGrid-to-dynamic-data-Part-2-editable-data-and-INotifyPropertyChanged.aspx

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