How can I achieve a binding path which is bound by another binding? - wpf

I'm writing my own UserControl which displays data in a ListBox. I want to achieve something similar to a property like "DisplayMemberPath". In my example, it's "EditableMemberPath", which should determine which member will be displayed in the textbox. However, using a binding on a binding does not work.
<ListBox ItemsSource="{Binding Path=Items, ElementName=me}"
SelectedItem="{Binding Path=SelectedItem, ElementName=me}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding Converter={Binding Path=ItemToImageConverter, ElementName=me}}" />
<TextBlock Text="{Binding Path={Binding Path=EditableMemberPath, ElementName=me}}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Can you help me finding a proper solution?
Best Regards
Oliver Hanappi

You can't do that directly in XAML (at least not with the built-in classes) : a Binding is not a DependencyObject, so you can't bind its properties.
However the post mentioned by Martin Harris looks promising...

Related

Binding to two dependency properties of the user control which is a ListViewItem

I've created an user control which is a ListViewItem. That control has 2 dependency properties I would like to bind to from my ViewModel. But how am I supposed to do that when I can only bind one thing (collection) to ListView ItemsSource property? How can I bind to ExpanderInfo dependency property? Is there any way to do that or maybe I have made a bad assumption and should have created user control in other way?
Here is my xaml code:
<ListView ItemsSource="{Binding Tasks}" SelectedItem="{Binding SelectedTask}" Height="200" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<tc:TaskTile TaskInfo="{Binding}" ExpanderInfo="{Binding ExpanderStatus}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
Thank you for your help!
Replace <tc:TaskTile TaskInfo="{Binding}" ExpanderInfo="{Binding ExpanderStatus}"/> with
<tc:TaskTile TaskInfo="{Binding}" ExpanderInfo="{Binding DataContext.ExpanderStatus, RelativeSource={RelativeSource AncestorType=ListView, Mode=FindAncestor}}"/>

Dynamic Telerik RadOutlookBar headers come out wrong with ItemTemplate

I'm trying to use Telerik RadControls in a MVVM kind of way but having some strange problems.
The Viewmodel behind the RadOutlookBar has a collection of ViewModels that each have a Title string property. I wanted to define it so way the they get Wrapped inside a RadOutlookBarItem and bind the header/title properties together.
XAML:
<telerik:RadOutlookBar x:Name="Items">
<telerik:RadOutlookBar.TitleTemplate>
<DataTemplate>
<ContentControl Content="{Binding Path=Title}" />
</DataTemplate>
</telerik:RadOutlookBar.TitleTemplate>
<telerik:RadOutlookBar.ItemTemplate>
<DataTemplate>
<telerik:RadOutlookBarItem Header="{Binding Path=Title}" >
<ContentControl Content="{Binding}" />
</telerik:RadOutlookBarItem>
</DataTemplate>
</telerik:RadOutlookBar.ItemTemplate>
</telerik:RadOutlookBar>
This works as intended except that the Header comes out strange. Instead of being like a static string item it seems to get wrapped inside another object that behaves like a similar to a RadOutlookBarItem ( it' changes color when mouseover and such )
Even if I cahnge to straightforward string instead of binding it's still strange. But If I don't define a ItemTemplate inside the RadOutlookBar (that is, not a dynamic control) it looks all right.
What could be going on there?
Solved this and another problem in one fell swoop. I was binding to the wrong Template the whole time. This made me think I had to add OutLookBarItem myself.
In the end I was supposed to bind what I was trying to bind to the ContentTemplate.
<telerik:RadOutlookBar x:Name="Items">
<telerik:RadOutlookBar.ContentTemplate>
<DataTemplate >
<ContentControl Content="{Binding}" />
</DataTemplate>
</telerik:RadOutlookBar.ContentTemplate>
<telerik:RadOutlookBar.TitleTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" />
</DataTemplate>
</telerik:RadOutlookBar.TitleTemplate>
<telerik:RadOutlookBar.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" />
</DataTemplate>
</telerik:RadOutlookBar.ItemTemplate>
</telerik:RadOutlookBar>
Should work I think.

Pattern for working with a form in Silverlight 4? (How to get references to XAML elements)

I have a form:
<StackPanel Orientation="Horizontal" Visibility="{Binding Editable, Converter={StaticResource visibilityConverter}}"
ToolTipService.ToolTip="Add new topic to this group">
<sdk:AutoCompleteBox Width="160" ItemsSource="{Binding ElementName=LayoutRoot, Path=DataContext.TopicNames}" />
<Button Click="addTopicButton_Click">
<Image Source="Images/appbar.add.rest.png" />
</Button>
</StackPanel>
This form appears in a DataTemplate for an ItemsControl. I'm not sure what the best way is to get the data from the AutoCompleteBox when the button is clicked. I can't give the elements x:Name attributes, because they're in a template (right?).
How can I get around this? The Click event will give me the Button, but I need a reference to the text box. Use the Button's parent, then look through the children for the Textbox? If I factored this out into its own UserControl, I could set x:Name values, but I'd rather not do that.
Any other ideas?
Update: Here is another example of such a problem:
<ListBox x:Name="topicList"
ItemsSource="{Binding Id, Converter={StaticResource topicGroupIDConverter}}"
SelectionChanged="ListBox_SelectionChanged"
HorizontalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"
Width="150"
VerticalAlignment="Center"
ToolTipService.ToolTip="{Binding Description}"
ToolTipService.Placement="Right" />
<Button ToolTipService.ToolTip="Remove this topic from this group"
Visibility="{Binding ElementName=topicList,
Path=DataContext.Editable,
Converter={StaticResource visibilityConverter}}"
Click="removeTopicButton_Click"
HorizontalAlignment="Right"
Margin="10,0">
<Image Source="Images/appbar.cancel.rest.png" />
</Button>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
When the button is clicked, I want to access topicList.DataContext. However, topicList itself is a DataTemplate in an ItemsControl, so I can't access it using its name from code-behind. How else can I do this?
You can add a property, say SelectedItemInAutoCompleteBox, to your presenter, and then can bind it to the SelectedItem property of AutoCompleteBox, using Mode=TwoWay, like this,
<sdk:AutoCompleteBox SelectedItem="{Binding Path=DataContext.SelectedItemInAutoCompleteBox, Mode=TwoWay}" ... />
You may try the same approach with Text property of AutoCompleteBox, also. See if it solves your problem.:-)
You have several choices:
If you're on Silverlight 5, use the AncestorBinding
Otherwise, use a Silverlight 4 AncestorBinding hack (it doesn't look pretty)
Or you could try DataContextProxy, which stores the DataContext in a resource so that it is accessible. Note: you should set the DataContextProxy as a Resource of topicList ListBox, not the UserControl as in Dan Wahlin's example.

Access property of DataContext inside ItemTemplate

I have a really nasty problem with bindings. I know that there are other topics regarding binding itmes inside itemtemplate to datacontext of an object outside the template. However, this just won't work, i.e. the first textblock display 'Test' as desired whereas the same textbox inside the itemtemplate shows nothing.
<TextBlock Text="{Binding DataContext.Test, ElementName=myList}"/>
<ItemsControl x:Name="myList" ItemsSource="{Binding AllItems}"
Margin="0,0,0,0" VerticalAlignment="Top" HorizontalAlignment="Center">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel Orientation="Horizontal"
ItemHeight="170" ItemWidth="140"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image x:Name="{Binding KeyName}"
Source="{Binding ImagePath}"
Width="128"
Height="128">
</Image>
<TextBlock Text="{Binding DataContext.Test, ElementName=myList}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I would appreciate some help here folks as this is really a problem for me.
Inside the itemtemplate, the binding is initialized to the context of the current item in AllItems.
Update
Outside of the ItemTemplateyour bindings are relative to the DataContext of the page.**
Once inside an ItemTemplate then bindings are limited to the scope of the item specifically being evaluated at that time.
So, if we assume the following (based on the code in your question):
<ItemsControl x:Name="myList" ItemsSource="{Binding AllItems}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock x:Name="tb1"
Text="{Binding DataContext.Test, ElementName=myList}"/>
<TextBlock x:Name="tb2" Text="{Binding KeyName}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
tb1 cannot access the DataContext object directly.
tb2 cann access KeyName - assuming that whatever object AllItems is an IEnumerable of contains a property with that name.
As I understand it, inside an itemtemplate, the item past from the enumeration controls the binding source and this can't be overridden (by setting ElementName or otherwise).
If you need the value from Test in every object in your enumeration then you'll need to add it as a property of the object in the enumeration.
I'm sure someone more knowledgeable than me could explain why this is or give a better explanation but that's the gist of it.
** Assuming no other nesting of ItemsControls (or equivalent)

Silverlight 3 Binding to the Current Item in a Collection

The Binding syntax, {Binding /}, works in WPF but does not work at all in Silverlight 3:
<ContentControl Content="{Binding MyCollection}">
<ContentControl.ContentTemplate>
<DataTemplate>
<ContentControl Content="{Binding /}" />
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
What's the way to approach this in Silverlight?
When binding to a collection in WPF, you're actually binding to something that understands the concept of "Current Item".
However in Silverlight what you're binding to doesn't have this concept. So you need to do it yourself.
For example in a MVVM app expose a property.
<ListBox SelectedItem="{Binding MyCurrentItem}"
ItemsSource="{Binding MyCollection}"/>
<ContentControl Content="{Binding MyCurrentItem}" />
or do some element binding
<ListBox x:Name="listBox"
ItemsSource="{Binding MyCollection}"/>
<ContentControl Content="{Binding SelectedItem, ElementName=listBox}" />
I think you want {Binding} or {Binding .}, either of which do the same thing.

Resources