WPF, passing variable to converter inside data template - wpf

I assume this is possible but not sure how to do it. I need to pass the value of a class level variable to a converter, from within side a data template.
<DataTemplate x:Key="ResponseItemTemplate">
<StackPanel Orientation="Horizontal" >
<StackPanel.Visibility>
<MultiBinding Converter="{StaticResource VisibilityConverter}">
<Binding Path="Key"/>
<Binding Path="CurrentLanguage"/>
</MultiBinding>
</StackPanel.Visibility>
<TextBox Width="200" Text="{Binding Value}" />
</StackPanel>
</DataTemplate>
The 'Key' value exists on the response item for the data template so this gets passed correctly, whereas the CurrentLanguage is a class variable and I can't get that to pass properly to the converter. Any ideas?

Thanks for the replies, this is what I needed to use in the end:
<Binding Path="DataContext.CurrentLanguage" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Window}}"/>

You can use the binding object as follows:
<Binding Source="{x:Static local:DataObject.MyData}" />
See: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/c94682e5-ad16-42f9-973f-fd7588a9c0b5.

If you define the converter as a resource, which you have, you can access it in the code behind. Once you have the converter you can then set a property on it.
var myVisConverter = (VisibilityConverter)window.Resources["VisibilityConverter"];
myVisConverter.CurrentLanguage = ...
EDIT Ok, if you're trying to get access to the parent DataContext from within the DataTemplate, there's a couple of options. Easiest is to name the control with the correct DataContext, then bind to that control like so...
<Binding Path="DataContext.CurrentLanguage" ElementName="nameGivenToElement" />
Josh Smith wrote an article with more ways of getting inherited DataContexts.

Related

The object 'Label' already has a child and cannot add ''. 'Label' can accept only one child

I am trying to use a helper class that another SO user provided me to apply stringformatting on a label. However, when I apply his solution, I get the following error :
The object 'Label' already has a child and cannot add ''. 'Label' can accept only one child.
Here is the label:
<Label Grid.Column="1"
Grid.Row="1">
<ui:Helper.Text>
<PriorityBinding>
<Binding Path="Worker.Employer.Name" StringFormat="Employer: {0}" />
<Binding Source="Unemployed" />
</PriorityBinding>
</ui:Helper.Text>
<Binding RelativeSource="{RelativeSource Self}" Path="(ui:Helper.Text)" />
</Label>
The error points at the "Binding RelativeSource..." line. What can I do to fix this? I would like to use Labels instead of TextBlocks, but it's getting to the point where it might not be worth it.
Just looks like a case of xaml assuming your attached property to be the Content of the Label
just wrap your actual Content in an explicit <Label.Content>
<Label Grid.Row="1"
Grid.Column="1">
<ui:Helper.Text>
<PriorityBinding>
<Binding Path="Worker.Employer.Name"
StringFormat="Employer: {0}" />
<Binding Source="Unemployed" />
</PriorityBinding>
</ui:Helper.Text>
<Label.Content>
<Binding Path="(ui:Helper.Text)"
RelativeSource="{RelativeSource Self}" />
</Label.Content>
</Label>
Without having tested i, I suppose there's a bug in the definition of the attached property, because it is attached to the Helper class itself and not to Label. That way you just create a new instance of Helper in your labels content. When you then add the binding to the content as well, you get the exception, because there already is a content.
I don't actually see a reason to make it an attached property anyway and binding to the attached property of self seems clumsy to me.
Try the following; Make Helper.Text a normal dependency property by replacing RegisterAttached(...) with Register(...). (Rename helper to something like CompositeString.) Then define a CompositeString as a resource of the label and bind the content of the label to this resource:
<Label>
<Label.Resources>
<ui:CompositeString>
<ui:CompositeString.Text>...</ui:CompositeString.Text>
</ui:CompositeString>
</Label.Resources>
<Label.Content>
<Binding Path="Text" Source="{StaticResource Test}" />
</Label.Content>
</Label>
Note, that the resource needs to be defined before binding to the content, that's why the binding gets its own tag.

Using CommandParameters and MultiBindings?

Is it possible to use CommandParameter="{Binding}" in a multi binding?
I am trying to do this in a data grid.
<CheckBox.CommandParameter>
<MultiBinding Converter="{StaticResource CDetailConverter}">
<Binding Path ="IsChecked" ElementName="chkSelection"/>
<Binding ConverterParameter="{Binding}"/>
</MultiBinding>
</CheckBox.CommandParameter>
The second Binding throws an error.
In a nutshell, the answer is no.
In your second inner Binding you have set ConverterParameter. There are a couple of problems with this:
First, Binding is its own class separate from MultiBinding with both Converter and ConverterParameter properties. Here you have set the ConverterParameter property without setting the Converter property. Remember that ConverterParameter is passed to the Binding's specified converter regardless if it is used within a MultiBinding or not. If you were to add a Converter here, then the converter would be passed the specified ConverterParameter.
What you probably meant to do was set the ConverterParameter on the outer MultiBinding which also has this property:
<CheckBox.CommandParameter>
<MultiBinding Converter="{StaticResource CDetailConverter}" ConverterParameter="{Binding }">
<Binding Path ="IsChecked" ElementName="chkSelection"/>
</MultiBinding>
</CheckBox.CommandParameter>
If you try this, you will quickly see that ConverterParameter can not be the target of a Binding expression since it is not a DependencyProperty.
Since you can not bind to CommandParameter, the typical workaround is to modify your IMultiConverter to accept an additional value, and supply this value through a binding expression:
<CheckBox.CommandParameter>
<!-- CDetailConverter updated to expect an additional value in the values array -->
<MultiBinding Converter="{StaticResource CDetailConverter}">
<Binding Path ="IsChecked" ElementName="chkSelection"/>
<Binding />
</MultiBinding>
</CheckBox.CommandParameter>
Hope this helps!

Binding as a formatted string

I have a ListBox which hold a set of objects (linked via ItemsSource bind to an ObservableCollection). I haven't used Dynamic binding yet. It currently use the ToString() method of the object. The ToString() method shows a string this way : name (someOtherProperty)
However, even if the INotifyPropertyChanged is implemented and that i use an ObservableCollection, if i change an item property this string won't be updated.
I believe that this is because it only calls ToString once. instead i guess i have to use data binding but how i can form such a string with it ? << name (someOtherProperty) >>
Thanks.
You can use a multibinding, e.g. something like this:
<MultiBinding StringFormat="{}{0} ({1})">
<Binding Path="name"/>
<Binding Path="someOtherProperty"/>
</MultiBinding>
If you just let it execute ToString there is no proper binding at all, any notifications will have no effect.
You use it like this:
<ListBox ...>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<!-- The above binding here -->
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Problem with validation and multibinding

In my WPF application I use the following xaml:
...
<TextBox
services:TextBoxService.IsFocused="{Binding Path=IsSelected, Mode=OneWay}"
FocusVisualStyle="{x:Null}">
<MultiBinding
Converter="{StaticResource mconv_operableToString}"
UpdateSourceTrigger="PropertyChanged">
<Binding
Path="Value"
Mode="TwoWay"
NotifyOnValidationError="True" />
<Binding
RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}"
Path="DataContext.Status"
Mode="OneWay" />
</MultiBinding>
The view model class which the first binding uses implements IDataErrorInfo for validation purposes. The problem is that although the error is caught in the property setter, the UI doesn't notice it. I have a style defined with an error template which should be applied when any error occurs in the text box. I suppose that maybe this scenario is not allowed with multi binding because where I use single binding everything works fine.
Thanks in advance.
It seems to me that nobody knows the answer to this but I suppose that this scenario just doesn't work. I'll try to answer it in case somebody will need it. I've tried to bind my View to my View Model class which implements IDataErrorInfo, in xaml I specified a converter and although everything worked fine, the Errors just didn't show up on the UI. So, I removed the converter from the binding and implemented that logic inside the View Model and, voila now everything works fine.

Bind to several class properties

I have some class with properties firstName and lastName. I want bind TextBlock to concatanation of this two properties. I know that I can create third property that will be return concatanation of these properties. But I dont want to use this approach. Is it possible to Bind TextBlock to two properties. and also I dont want create composite userControl.
In .NET 3.5SP1, Microsoft added StringFormat to bindings. This makes it much easier. See Lester's blog post for an example. In your case:
<TextBox>
<TextBox.Text>
<MultiBinding StringFormat="{0} {1}">
<Binding Path="FirstName" />
<Binding Path="LastName"/>
</MultiBinding>
</TextBox.Text>
</TextBox>
or
<TextBox>
<TextBox.Text>
<MultiBinding StringFormat="{1}, {0}">
<Binding Path="FirstName" />
<Binding Path="LastName"/>
</MultiBinding>
</TextBox.Text>
</TextBox>
You could use multibinding, but I guess that you have to code your way out of the concatanation.
Here is an example: Multibinding
I'm not sure if it's possible to bind to two properties, but there is not reason you cannot create two TextBlocks right?
<TextBlock Text="{Binding firstName}"/> <TextBlock Text="{Binding lastName}"/>
use either MultiBinding or Converter (if complex operation is there)

Resources