When to use Path in WPF Binding? - wpf

I've seen a lot of WPF Binding examples and have used the feature in a lot of different places in learning MVVM, but something that has seemed quite inconsistent to me is when you specify "Path=" in the binding string as appose to simply typing in the property you want to bind to. For example, what's the functional difference between the following XAML attributes:
DataMemberBinding="{Binding SomeProperty}"
DataMemberBinding="{Binding Path=SomeProperty}"

There is no functional difference. The default property of the Binding object is Path, this means if you don't specify which property you are setting then you will set Path.
This is because the Binding object has two constructors, one default and one that takes in a single string parameter. When you pass in a value without labeling it that property will be forwarded onto the matching constructor, in the case of Binding this sets the path. It is very similar in concept to the way attributes work, a call to the constructor followed by optional parameters, for example:
[AttributeUsage(AttributeTargets.Class), AllowMultiple = false, Inherited = false ]
Probably way beyond what you're actually asking the question for, but I've noticed that there is a slight (and probably inconsequential) difference between the two. Since I can't explain it myself I've started a new question about it here.

Related

How to bind ItemsControl's ItemsSource property by using naming conventions in caliburn.micro correctly?

There is an ItemsControl named Items in the view and a ViewModel contains a BindableCollection<T> property Items property, I want them get binding correctly by using the naming conventions mechanism in caliburn.micro, however it dose not works as expected.
When I add ItemsSource="{Binding Items}" in the view explicitly, it works, I am wondering what's the key point missed when using naming conventions in the ItemsControl?
Firstly, using the word "Items" as a name for a property, control etc is a bad choice. It's confusing. This is true if someone is maintaining your code or reading a question. You should have considered names for things.
The conventions for caliburn micro are explained here:
https://caliburnmicro.com/documentation/conventions
Essentially, a control is examined.
The name is used to look up a property from the datacontext.
If they match then a dependency property of that control will be bound.
Which dependency property is used varies from control to control. Text is the default for TextBox and TextBlock. ItemsSource is the default for an itemscontrol.
Hence the answer to your question is your control name should match the property name.
As they seem to, this is not why your binding is failing.
You also need to provide an instance of that datacontext somehow.
You proved that is happening with your working explicit binding.
The two most likely possible causes are therefore:
Your bootstrapper isn't running the caliburn micro wireup code.
or
Your view isn't provided by the bootstrapper and you've not used viewmodel.bind on it to wire everything up.
or
You've somehow interfered with the default binding conventions.
PS
https://caliburnmicro.com/announcements/stepping-away

How to tag viewmodel when using ViewModelLocator?

I have multiple instances of a viewmodel:
<views:MyView x:Name="view1" mefed:ViewModelLocator.NonSharedViewModel="MyViewModel" />
<views:MyView x:Name="view2" mefed:ViewModelLocator.NonSharedViewModel="MyViewModel" />
These two instances should listen for different messages. Hence, I need to somehow tag these viewmodel instances. How?
I'm using MEFedMVVM and Prism. There ought to be a way to let the viewmodel know about some state. E.g.:
<views:MyView x:Name="view1" mefed:ViewModelLocator.NonSharedViewModel="MyViewModel">
<!-- Let the viewmodel know it is of type X -->
</views:MyView>
<views:MyView x:Name="view2" mefed:ViewModelLocator.NonSharedViewModel="MyViewModel">
<!-- Let the viewmodel know it is of type Y -->
</views:MyView>
How can this be achieved?
In an ideal world you would use a view's parameterized constructor through XAML, but this is not supported. Another idea is to use different classes for the views, but that will soon bloat the code!
Quick Answer and Summary:
As you noticed, what you really want is to parameterize your ViewModel from XAML. So my instinct is to write an Attached Behavior to provide the ability to pass in parameters for your ViewModel. And more specifically, what comes to mind is that we want a single Attached Behavior class that we can specify both (a) which ViewModel we want and (b) a parameter for that ViewModel. To satisfy both of these desires in a single class while also being as DRY as possible, I think it is easiest to use a "Blend" Behavior, since Blend behaviors are not static classes and thus it seems much easier to be able to use them to pass in both pieces of related information together.
Explanation:
First a quick disclaimer: I have not used MEFedMVVM or Prism (but I have used other MVVM libraries), so my answer uses a more general approach that I have recently learned to make use of. Thus, this approach does not rely on any "magic" stuff that Prism may give you when you use things in their "normal" way (i.e., hooking up DataContext automatically, etc.), so let that frame this mindset.
For a good writeup about the differences between "regular" Attached Behaviors and "Blend" Behaviors, I like this blog post. I won't repeat his explanations here, but the key thing I notice is that regular Attached Behaviors seem to just rely on a single piece of information (i.e., a single "parameter") in order to do its thing. Such as (from the blog post):
<GridView local:ItemClickNavBehavior.Destination="Home" ...>
Now lets put that in terms of your case, and examine how it could work if you just used regular Attached Bahaviors. You would write an Attached Behavior class, call it "MyViewModel1Creator" that would:
(1) register an attached property called "Type" and
(2) include a change callback handler for "Type" (which also gets called when its initially set - see the "HookupBehavior" method in the linked blog post). In this change callback you would instantiate "ViewModel1" and pass in to it the value of the "Type" Attached Property. Also in this method you could take care of any other necessities such as setting the DataContext for the View, etc. You can access the object that the Attached Property is attached to (the the View object in this case) by using the first parameter in the callback handler (the Dependency object param).
Then your Xaml use of the "MyViewModel1Creator" class would look like:
<views:MyView x:Name="view1" MyBehaviors:MyViewModel1Creator.Type="X" />
<views:MyView x:Name="view2" MyBehaviors:MyViewModel1Creator.Type="Y" />
Although this would work, I see a disadvantage to this approach (using regular Attached Properties). To use this approach, you would have to create a separate Attached Behavior class for each ViewModel, meaning that if you had 3 ViewModels ("ViewModel1", "ViewModel2", "ViewModel3") then you would need to write 3 Attached Behavior classes ("ViewModel1Creator", "ViewModel2Creator", "ViewModel3Creator"). Each one would instantiate its respective ViewModel (and expose a "Type" Attached Property as shown above). Another disadvantage is that it seems to be harder to find a way to add additional parameters to pass in.
A slightly alternate approach to the one above, but equally deficient in terms of being DRY, would be to have a single class (call it "MyViewModelCreator" - without the "1" this time) that houses several Attached Properties with names like "CreateViewModel_1_WithType", "CreateViewModel_2_WithType", "CreateViewModel_3_WithType", etc. Its usage would look like:
<views:MyView x:Name="view1"
MyBehaviors:MyViewModelCreator.CreateViewModel_1_WithType="X" />
<views:MyView x:Name="view2"
MyBehaviors:MyViewModelCreator.CreateViewModel_1_WithType="Y" />
Again, these approaches are not very DRY, so we really need to...
Now let's consider how it could work if we used a "Blend" behavior:
You would write a class that derives from a typed Behavior - for your views it would probably be Behavior<UserControl>, so your class heading might look like:
public class ViewModelSetupBehavior : Behavior<UserControl>. In this class you would: (1) register as many Dependency Properties as you like, including a "Type" Dependency Property, and a "ViewModelName" Dependency Property, and (2) You will override the OnAttached() method, where you will instantiate whichever ViewModel is indicated by the value of the "ViewModelName" Dependency Property, and also pass in to it the value of the "Type" Dependency Property. Again, this would be the place to also handle any other necessities such as setting the DataContext for the View, etc. You can access the object that the Behavior is "attached to" (your View in this case) by using the AssociatedObject property.
This could let you do this:
<views:MyView x:Name="view1">
<i:Interaction.Behaviors>
<MyBehaviors:ViewModelSetupBehavior ViewModelName="ViewModel1" Type="X" SomeOtherParam="bla" />
</i:Interaction.Behaviors>
</views:MyView>
<views:MyView x:Name="view2">
<i:Interaction.Behaviors>
<MyBehaviors:ViewModelSetupBehavior ViewModelName="ViewModel1" Type="Y" />
</i:Interaction.Behaviors>
</views:MyView>
Now notice that we have the ability to use a single Behavior class for the creation of all of our ViewModels, and we can pass in several parameters to dictate how we want the ViewModel to be instantiated.

Two way Multiconverter or Converter with property

I need to convert a two part value into a string and back again for example:
{Value = 12.0, Units = DimensionUnits.Inches}
Converts to
"12 in"
This is pretty simple using a multivalue converter to convert from source but becomes impossible to convert back if the user doesn't provide the unit type in the string so a Multivalue converter doesn't look like the solution I need.
A direct converter parameter won't work because the unit type needs to be bound so I researched how to create a bindable parameter. Creating a bindable parameter is actually pretty easy - deriving from DependencyObject - but then you have the problem of your converter not living in the visual tree - and thus not being able to bind to anything - to which there are 2 solutions:
http://tomlev2.wordpress.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
http://shujaatsiddiqi.blogspot.com/2011/02/wpf-binding-converter-parameter.html
The first method derives your Converter from Freezable instead of DependencyObject to allow DependencyProperties. This works and allows you to bind within the Whatever.Resources section but it has extremely odd behavior like only listening to the binding the first time it is used in your entire application.
The second method doesn't seem to work at all. The dependency property is never updated when the source changes.
<pf:BindingReflector Target="{Binding Source={StaticResource DistanceConverter}, Path=Units, Mode=TwoWay}"
Source="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=g:TestWindow, AncestorLevel=1}, Path=Units, Mode=TwoWay}"/>
Does anyone know of a solution to this problem or is this a big limitation of WPF?
Personally, I would actually suggest rethinking this a bit, and doing either:
Keep the final string one-way using a IMultiValueConverter, and have this be input as two separate items. This seems like a reasonable approach, as the units appear to be an enum with a specific set of options. A combo box for units and textbox for amount seems appropriate, and the total display can be done with a one-way converter.
Handle this conversion explicitly in the ViewModel. This has the advantage of allowing much better validation handling, which is probably going to be required as entering two separate values (amount + units) in one control is likely to not validate correctly. By moving the logic directly into your ViewModel instead of binding to the properties, you can correctly handle errors in a clean way.

Current binding value

I'm writing markup extension. I have XAML like this
<TextBlock Text="{ui:Test SomeInfo}" />
and TestExtension with constructor taking one string argument. I'm getting "SomeInfo" string so everything is find. Now I want to nest extensions and write something like
<TextBlock Text="{ui:Test {Binding PropName}}" />
and it does not work as is. I had to add constructor which takes one argument of System.Windows.Data.Binding type.
Now I need to know
How should I retrieve a current value from the Binding object?
When should I do this? Should I subscribe to changes some way or ask for that value every time in ProvideValue method?
Update1 PropName should be resolved against DataContext of TextBlock.
Update2 Just found related question: How do I resolve the value of a databinding?
Bindings like this will not work because your MarkupExtension has no DataContext and it does not appear in the visual tree and i do not think you are supposed to interact with binding objects directly. Do you really need this extension? Maybe you could make do with the binding alone and a converter?
If not you could create a dedicated class which has bindable properties (by inheriting from DependencyObject), this however would still not give you a DataContext or namescope needed for ElementName or a visual tree needed for RelativeSource, so the only way to make a binding work in that situation is by using a Source (e.g. set it to a StaticResource). This is hardly ideal.
Also note that if you do not directly set a binding the ProvideValue method will only be called once, this means that even if you have a binding in your extension it may not prove very useful (with some exceptions, e.g. when returning complex content, like e.g. an ItemsControl which uses the binding, but you set the extension on TextBlock.Text which is just a string), so i really doubt that you want to use a MarkupExtension like this if the value should change dynamically based on the binding. As noted earlier: Consider converters or MultiBindings for various values instead.

How to bind to a "x:static" resource in code-behind in WPF

For some user controls, I have this binding:
AppLanguage="{Binding Path=ApplicationLanguage, Source={x:Static Application.Current}}"
This works for controls that are declared/instantiated in XAML. However, I have a control that is only instantiated dynamically (it won't be used regularly, so I don't want an instance (up to 3, actually) to gobble up memory for nothing all the time. Now, unless I'm missing something, I have to declare my bindings in code-behind. That works fine when I have an easy one (ElementName + Path), but in the above case, I can't figure out how to write it in code-behind.
Of course, in this particular case, the control could simply refer to My.Application.ApplicationLanguage, but trying to do this got me curious anyway. I did a good number of searches and couldn't find anything similar (might be my search keywords though. :))
x:Static just resolves a static member for you, so you can write as:
var binding = new Binding("ApplicationLanguage");
binding.Source = Application.Current;
That said, I don't follow why you think you need to do this in code.

Resources