Extending Binding class to provide a bindable converter parameter - wpf

I need to create a string in a particular format, for which I use IMultiValueConverter. Example:
{0} of {1} in {2}
SomeValue0
SomeValue1
SomeValue2
Results in:
SomeValue0 of SomeValue1 in SomeValue2
This part is not a problem. Basically converter accepts multiple strings, of which the first one is the string format, and later ones are the strings to format.
<MultiBinding Converter={...}>
<Binding>
<Binding.Source>{0} of {1} in {2}</Binding.Source>
</Binding>
<Binding Path="Value0" />
<Binding Path="Value1" />
<Binding Path="Value2" />
</MultiBinding>
It gets tricky when some of the strings (Binding) also require the use of IMultiValue converter. Imagine that property #Value1# has different value for different language. Normally we get such value also using IMultiValueConverter:
<TextBox>
<TextBox.Text>
<MultiBinding Converter={...}>
<Binding Path="Value1"?
<Binding Path="Strings" Source="{StaticResource langResources}" />
</MultiBinding>
</TextBox.Text>
</TextBox>
When the user switches to different language, a dictionary of Strings is updated, and TextBox receives new value (the same applies to changing a value to Value1).
Now the problem: It is not possible to use IMultiValueConverter inside IMultiValueConverter. You also cannot override ProvideValue for BindingBase, and IMultiValueConverter will accept only the objects of type BindingBase.
Is there any way I can somehow extend BindingBase so that it exposes a BindableConverterProperty, whose value will be used to provide value from Binding?

tricky when some of the strings (Binding) also require the use of IMultiValue converter.
Why not put the intelligence of the string's IMultivalue converter into a specialized class who's ToString() will output the correct string based on the current environmental settings? That would eliminate the need for the sub multivalue converter you describe but work within the framework of the parent MultiValue converter.
The super-classed string class I recommend simply has to subscribe to an event which informs it which dictionary to use. Then when ToString() is called, the correct string is passed on to the top level converter.

Related

How to supply a string literal value as a binding in WPF

EDIT:
My former question also referred to commands, but as pointed out in a comment below, it was unnecessary and added noise.
This is more a XAML syntax question, so it is probably trivial.
I would like to know how to pass a string literal as a value for a binding in WPF.
If the value is already known from the context in XAML, may its value simply be directly assigned to the binding, instead of using paths and other means?
If so, what would the syntax be in that case?
<MultiBinding.Bindings>
<!-- First binding, a textbox -->
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type TextBox}}"/>
<!-- Second binding, I want to pass a string as is, for instance, "Description" -->
<!-- The proper syntax for the line below is what I am after -->
<Binding Value="Description"/>
</MultiBinding.Bindings>
It's
<Binding Source="Description"/>
Source can be any type, so in attribute syntax that is interpreted as a string, if no Path is specified a binding's value is the source.
Also that is a multi-binding, i would not talk about command parameters as that is irrelevant to the matter...

Do you have to use a converter when using Multibinding in WPF?

I would like to know if there are scenarios where you can use a Multibinding without a converter - and the limitations which force us to use a converter.
In particular I am trying to bind a string to another two strings in a string.format style.
The most common area you use a MultiBinding without a converter is when you have a string format concatenating two individual values
say for example:
To format Names that have First, Last part and you want to format it based on locale
<StackPanel>
<TextBlock x:Name="firstName"
Text="John" />
<TextBlock x:Name="lastName"
Text="Wayne" />
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding ElementName="firstName"
Path="Text" />
<Binding ElementName="lastName"
Path="Text" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
You do see quite a lot of places you use a converter since using a MultiBinding your doing the same as a Binding but you have multiple source values formatted to a single result instead of single input -> single output.
You can have a Binding take a ConverterParameter to supply another input value however you have limitations like not being able to provide a runtime Bound value to it, which makes MultiBinding more appropriate for multiple inputs where you want to bind all of them.
It boils down to your use-case, If you want to provide a result based on different input types that you evaluate in a custom-way, you need a Converter(pretty much similar to Binding. Just think of the difference as 1 input bind-able value against multiple)

WPF TextBlock MultiBinding

I want to bind TextBlock's Text property to some elements' and some model's properties. Something like this:
<TextBlock>
<TextBlock.Text>
<MultiBinding>
<Binding ElementName="myElement1" Mode="OneWay" Path="Text" />
<Binding ElementName="myElement2" Mode="OneWay" Path="Text" />
<Binding Mode="OneWay" Path="Property1" />
<Binding Mode="OneWay" Path="Property2" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
The TextBlock has a text value, combination of myElement1, myElement2 and Property1, Property2. There is not a problem. The text value is generated successfully.
Here is my question:
Can I bind whole (combined) text value of the TextBlock to another model's property, i.e. Property3, without code?
Not without some really bad hacking which would require writing some code to set up attached properties and other bindings anyway. The issue is that any binding has 2 ends: target and source. Since the target (where the binding is set) must be a DependencyProperty that means that your model must be on the source end of the binding you're trying to do. This isn't a problem as far as setting a value since TwoWay and OneWayToSource bindings do this just fine.
You have a bigger problem though in that the original place where the value is coming from (TextBlock.Text) already is assigned a binding and so can't be the target for your model binding. You might next want to try using another UIElement property as an intermediary to take the Text value and push it to the model. To do that you again need the model to be the source and the other UIElement property to be the target. But that same property also needs to be the target of a binding to the original Text property that you're trying to extract, so again you're stuck.
Bottom line is that you're much better off handling this in your Model and ViewModel layers rather than trying to force the stuff you have set up in XAML to be driving everything.

Can a WPF converter access the control to which it is bound?

Long version:
I have a simple WPF converter than does date conversions for me. The converter basically checks the date and formats it in dd/M/yyyy format. The converter does some smarts with the handling of the date which means that the user could type "23061971" and the value will be converted to "23/06/1971".
All this is trivial and working. The problem is that when I update the value, it does not update the caret position. Assume "|" is the caret and the user types "23061971|" then a millisecond later it is updated to "230619|71".
What I'd like to do is detect if the caret at the end of the value - if so, shift it to the end of the edit field once the new value has been updated. In order to do this, I'll need access to the edit control to which the converter is attached.
Short version:
From A WPF converter, can I get a reference to the control that is bound to that converter?
Here is an excellent article on how to get direct access to the control from within a converter: http://social.technet.microsoft.com/wiki/contents/articles/12423.wpfhowto-pass-and-use-a-control-in-it-s-own-valueconverter-for-convertconvertback.aspx
Essentially:
<MultiBinding Converter="{StaticResource MyConverter}" >
<Binding RelativeSource="{RelativeSource Self}" Mode="OneTime"/>
<Binding Path="MyValue2" />
</MultiBinding>
in the converter values[0] will be your control, ready for casting and values[1] would be the data that you are binding.
In a ValueConverter you can't get access to the control - however you can get access if you use a multibinding with a multivalueconverter.
In the multibinding the first binding is your binding as now - without the converter. The second binding you bind to the control itself - there you go acces to the control.
I have used this approach to gain other things also - you can make "dummy" bindings to properties you want to trigger updates, i.e. if you bind to the control itself you will only get updated if it changes, not if a property does - so create dummybindings for those.
You can send the control with the MultiBinding like this.
<TextBox Height="100" x:Name="textbox1" DockPanel.Dock="Top">
<TextBox.Text>
<MultiBinding Converter="{StaticResource MultiConverter}">
<Binding ElementName="textbox1" Path="." />
</MultiBinding>
</TextBox.Text>
</TextBox>
I don't thknk a converter has any way to get at the control that is using it. It is only a simple piece of logic that converts one object to another object.
However, in you case, perhaps you can trap the change event and then manually move the caret. If you think about it, caret position is strictly a view concern; it has nothing to do with converters or the data. You should not burden view-controller logic with it. You should definitely not burden converter logic (which is classified under utility classes) with it.

Why does my IMultiBindingConverter get an array of strings when used to set TextBox.Text?

I'm trying to use a MultiBinding with a converter where the child elements also have a converter.
The XAML looks like so:
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource localizedMessageConverter}" ConverterParameter="{x:Static res:Resources.RecordsFound}" >
<Binding Converter="{StaticResource localizedMessageParameterConverter}" ConverterParameter="ALIAS" Path="Alias" Mode="OneWay" />
<Binding Converter="{StaticResource localizedMessageParameterConverter}" ConverterParameter="COUNT" Path="Count" Mode="OneWay" />
</MultiBinding>
</TextBlock.Text>
The problem I'm facing here is, whenever this is used with a TextBlock to specify the Text property, my IMultiValueConverter implementation gets an object collection of strings instead of the class returned by the IValueConverter. It seems that the ToString() method is called on the result of the inner converter and passed to the IMultiValueConverter. If used to specify the Content property of Label, all is well.
It seems to me that the framework is assuming that the return type will be string, but why? I can see this for the MultiBinding since it should yield a result that is compatible with TextBlock.Text, but why would this also be the case for the Bindings inside a MultiBinding?
If I remove the converter from the inner Binding elements, the native types are returned. In my case string and int.
Probably the targetType parameter of your localizedMessageParameterConverter converter is System.String. This is because the target type of the Bindings is inherited from the MultiBinding, and the targetType of the MultiBinding is System.String because TextBlock.Text is a string property.
See the following article for a similar problem: Multi-Value Converters, Value Converters and the Case of the Wrong Target Type
According to Microsoft Connect, this has been fixed in WPF 4.0. See: Microsoft Connect
The above article also explains a workaround.

Resources