ItemTemplate: how to refer to the item itself - silverlight

I have a ListBox displaying items with a template something like this:
<ListBox
x:Name="CustomerResultList"
ItemsSource="{Binding Customers}">
<ListBox.ItemTemplate>
<DataTemplate>
<controlsToolkit:DockPanel>
<Button
x:Name="CustomerButton"
Command="{Binding MyCommand}"
CommandParameter="{Binding WhatGoesHere?}"
controlsToolkit:DockPanel.Dock="Left"
Content="ButtonText" />
<TextBlock
Text="{Binding Path=Name}"
controlsToolkit:DockPanel.Dock="Right" />
</controlsToolkit:DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The button in the template should invoke a command that gets passed the customer as a parameter.
I can't figure out how to refer to the customer in the buttons CommandParameter binding.
Is there a special Elementname or Path I can use to refer to the Custome itself and not some of its properties?

Simply:
CommandParameter="{Binding}"
If you specify Binding without Path, you bind to the DataContext itself.

Related

Getting CurrentItem within a nested ItemsControl

I have an itemscontrol, with a item template. Inside this item template another itemscontrol exists. The latter ItemsControl has a button in its template, the command bound to this template needs to get the "parent" itemscontrol current item.
The structure looks something like this:
<ItemsControl x:Name="outerItemsControl" ItemsSource={Binding MyCollection}>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource={Binding MySecondCollection}>
<ItemTemplate>
<DataTemplate>
<Button Command="{Binding MyFantasticCommand}"
CommandParameter="{Binding ????}"/>
</DataTemplate>
</ItemTemplate>
</ItemsControl>
</DataTemplate>
<ItemControl.ItemTemplate>
</ItemsControl>
What should I replace the {Binding ????} with to get hold of the current item in MyCollection?
I've tried with both:
Binding ., ElementName=outerItemsControl
and
Binding Path="." RelativeSource="{RelativeSource AncestorType={x:Type ItemsControl}, AncestorLevel=2}
EDIT
Usually when we need to access the "current item" in an items control we do the following:
<ItemsControl x:Name="outerItemsControl" ItemsSource={Binding MyCollection}>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding MyCommand}" CommandParameter="{Binding .}"/>
</DataTemplate>
<ItemControl.ItemTemplate>
</ItemsControl>
I want to do the same as this example, but access the parent's "current" item from the child itemscontrol.
It seems you want to access the object with the MySecondCollection property from the inner DataTemplate.
This should work:
CommandParameter="{Binding DataContext,
RelativeSource={RelativeSource AncestorType=ContentPresenter, AncestorLevel=2}}"

MahApps.Metro: WindowCommands ItemsSource binding

I am trying to bind a collection of items to the windowcommands of metrowindow. Below is the xaml snippet.
<metro:MetroWindow.WindowCommands>
<metro:WindowCommands ItemsSource="{Binding WindowCommands}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding DisplayName}"
Command="{Binding Callback}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</metro:WindowCommands>
</metro:MetroWindow.WindowCommands>
But it does not display the DisplayName property, but the type name of the bounded datatype. How can I achive the intended behaviour?
Works if you add the template as a resource to the MetroWindow. For this to work you will need to create a WindowCommandViewModel that has Label and Callback properties.
<metro:MetroWindow.Resources>
<DataTemplate DataType="{x:Type viewModels:WindowCommandViewModel}">
<Button Content="{Binding DisplayName}"
Command="{Binding Callback}"/>
</DataTemplate>
</metro:MetroWindow.Resources>

How to bind ListBox to a member of a view model in xaml?

I'm just starting with wpf/vmmv. I've seen examples of binding collections to list boxes. Example: in xaml , in code-behind (e.g. Page) "DataContext = collection.. ".
My view model has more properties than just a single collection that need to be bound to a view. Therefore I'd like to set the view model as DataContext for the view and then, in xaml, bind the view model's collection to a ListBox. Assuming that my view model is set as DataContext and it has a property called 'Customers', what is the correct way of binding the property to a ListBox in xaml?
I tried but it does not work.
Thanks.
Do you mean 'how do you bind a collection to a 'ListBox'? You would do that like this:
<ListBox ItemsSource="{Binding Customers}" />
Or this:
<ListBox ItemsSource="{Binding Path=Customers}" />
If you want to bind the internal values of each instance of the Customer class, you would do something like this:
<ListBox ItemsSource="{Binding Customers}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding Age}" />
<TextBlock Text="{Binding EyeColour}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I guess you want to display the property "Customers", what you have to do is define ItemTemplate of ListBox, define DataTemplate inside ItemTemplate, and binding Customers to a control, just like below:
<ListBox ItemsSource="{Binding}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Customers}"/>
......something else you want display
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Binding in listbox with textblocks not working

I have the following xaml code:
<ListBox Foreground="{Binding MyColor, Converter={local:ColorConverter}}" ItemsSource="{Binding LogCollection, Mode=TwoWay}" Grid.Row="1">
</ListBox>
This changes the foreground color for the entire listbox, so I modified the code in this way:
<ListBox ItemsSource="{Binding LogCollection, Mode=TwoWay}" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Foreground="{Binding MyColor, Converter={local:ColorConverter}}" Text="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In this way I wanted to set the foreground for an item instead for the entire listbox, but it is not working. How do I find the right datacontext ? MyColor is a property on my MainViewModel.
LATER EDIT WITH THE SOLUTION
Jens's answer was the one that showed me where I was wrong. Instead of storing simple message log strings in the ObservableCollection, I created a new class (LogItems) which contains a Message and a Color members. Now the LogCollection is typeof LogItems instead of strings.
I populate the listbox with the following code in my viewmodel:
LogItems logitem = new LogItems(myMessage, myColor);
LogCollection.Insert(0, logitem);
And the view has the following form. Also it doesn't require anymore to use RelativeSource, because the datacontext is the same.
<ListBox ItemsSource="{Binding LogCollection, Mode=TwoWay}" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Foreground="{Binding Path=Color, Converter={local:ColorConverter}}" Text="{Binding Path=Message}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Thank you all for your answers which lead me to this solution.
The DataContext of generated container in a listbox is automatically set to the corresponding item, therefore your Binding does not find the Property MyColor. You need to use a RelativeSource binding to bind to the DataContext of the containing list:
<TextBlock Foreground="{Binding DataContext.MyColor,
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type ListBox}},
Converter={local:ColorConverter}}"
Text="{Binding}"/>

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.

Resources