Reputation: 7469
I have a ListBox that I provide with DisplayMemberPath
in run time, and have a TextBlock
that I want its Text property to be bound to the selected item text of the ListBox, hardcoding the value works:
<TextBlock Text="{Binding ElementName=lstBx, Path=SelectedItem.Title}"/>
But how I do it without knowing which property is used for displaying?
Edit
The ListBox
and the TextBlock
are parts of the ControlTemplate
of a custom control that has a custom DisplayMemberPath
property that I bind to the listBox's DisplayMemberPath
<ListBox Name="lstBx" ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ItemsSource}"
DisplayMemberPath="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DisplayMemberPath}"
SelectedValuePath="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectedValuePath}"/>
Upvotes: 0
Views: 104
Reputation: 5666
In my opinion you have 2 options:
SelectedDisplay
property (it should work like SelectedValue
property, but using DisplayMemberPath
instead of SelectedValuePath
)MultiBinding
and some lamba expression dynimic building.I will show you the second solution. First of all the multibinding:
<TextBlock>
<TextBlock.Text>
<MultiBinding Mode="OneWay" Converter="{StaticResource PropertyMultiValueConverter}">
<Binding ElementName="lstBx" Path="SelectedItem"/>
<Binding ElementName="lstBx" Path="DisplayMemberPath" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
Now the code for the PropertyMultiValueConverter
class (of course it can be improved and optimized for avoiding a continuos lambda expression generation):
public class PropertyMultiValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
object selectedItem = values[0];
string displayMemberPath = values[1] as string;
if (selectedItem != null)
{
ParameterExpression param =
System.Linq.Expressions.Expression.Parameter(selectedItem.GetType(), "x");
MemberExpression body =
System.Linq.Expressions.Expression.Property(param, displayMemberPath);
LambdaExpression lambda =
System.Linq.Expressions.Expression.Lambda(body, param);
Delegate expression = lambda.Compile();
return expression.DynamicInvoke(selectedItem);
}
else
{
return null;
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
Lambda expressions are faster than using reflection, so I prefer this way. As you can see the generated lambda expression retrieves the value of the property and returns it.
Upvotes: 1
Reputation: 4164
I think i get your question. Seems you meant SelectedItem.{CanBeAnyProperty} right?
One solution could be you bind your textblock like below :
<TextBlock Text="{Binding ElementName=lstBx, Path=SelectedItem}"/>
And override SelectedItem ToString() method to return appropriate desired property value.
For example: say your Item bound to list is Person.
So you can override ToString() method of person class like :
class Person{
Public string ToString(){
return Name; /*this again you need to work out runtime* OR/
return Age.ToString();}
}
Upvotes: 0