WPF binding from ListBox ItemTemplate - wpf

I have a problem binding from ListBox Itemtemplate that contains an Expander with its own HeaderTemplate and ContentTemplate.
<ListBox ItemsSource="{Binding Feeds}">
<ListBox.ItemTemplate>
<DataTemplate>
<Expander Content="{Binding Text}"
Header="{Binding Title}">
<Expander.HeaderTemplate>
<DataTemplate>
<DockPanel >
<TextBlock Text="{Binding PublishDate}" />
<TextBlock Text="{Binding}" />
</DockPanel>
</DataTemplate>
</Expander.HeaderTemplate>
<Expander.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Image Source="{Binding ImageURL}" />
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</Expander.ContentTemplate>
</Expander>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The PublishDate and ImageURL bindings don't work and I'd like to bind them to properties in the object Feed:
Public Class Feed
Public Property Title As String
Public Property PublishDate As DateTime
Public Property Text As String
Public Property ImageURL As String
End Class
I tried FindAncestor in the binding to find the ListBoxItem but it didn't help me.

the Content of the Expander serves as the DataContext for the ContentTemplate and the Header for the HeaderTemplate.
Set Content="{Binding}" and Header="{Binding}" instead. This sets the DataContext of both templates to the DataContext of the ListBoxItem (i.e. a Feed).

Related

Bind textbox list inside listbox in wpf

I have to make listbox with textbox in it... and it has to be dynamic. I have observable collection in code behind and I want to bind that for listbox. I want dynamic listbox and this list should have editable textbox in it. So, basically I want to bind multiplr textbox from listbox. Any help would be appreciated
<ListBox HorizontalAlignment="Left" Name="ListTwo" Height="100" Margin="286.769,165.499,0,0" VerticalAlignment="Top" Width="100" ItemsSource="{Binding Source=obs}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Name="TextBoxList"></TextBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
By doing this, I have number of textbox same as items in observable collection but textbox's text is not set up.
If the items in your ObservableCollection are just plain strings, then you can data bind to the whole string value like this:
<ListBox Name="ListTwo" ItemsSource="{Binding Source=obs}" ... >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Name="TextBoxList" Text="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
From the Binding.Path Property page on MSDN:
Optionally, a period (.) path can be used to bind to the current source. For example, Text="{Binding}" is equivalent to Text="{Binding Path=.}".
Note that if you had some objects with properties in the collection, then #nit's answer would have been correct as you would need to reference the relevant property name:
<ListBox Name="ListTwo" ItemsSource="{Binding Source=obs}" ... >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Name="TextBoxList" Text="{Binding PropertyName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You will have to Bind your textbox to the property in your class of which observable collection you have bound
<ListBox HorizontalAlignment="Left" Name="ListTwo" Height="100" Margin="286.769,165.499,0,0" VerticalAlignment="Top" Width="100" ItemsSource="{Binding Source=obs}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Binding="{Binding PROPERTYINCLASS}"></TextBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

ListBox not using its ItemTemplate

What in the world is wrong with this ListBox? It is showing items as plain strings, not using the template I have provided:
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse Width="20" Height="20" Fill="LightBlue" />
<TextBlock Text="{TemplateBinding Content}" Foreground="Red" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Items>
<ListBoxItem>html</ListBoxItem>
<ListBoxItem>head</ListBoxItem>
<ListBoxItem>body</ListBoxItem>
<ListBoxItem>table</ListBoxItem>
<ListBoxItem>tr</ListBoxItem>
<ListBoxItem>td</ListBoxItem>
</ListBox.Items>
</ListBox>
From the Remarks section in the ItemTemplate MSDN page:
When you set an ItemTemplate on an ItemsControl, the UI is generated
as follows (using the ListBox as an example):
1.During content generation, the ItemsPanel initiates a request for the ItemContainerGenerator to create a container for each data item.
For ListBox, the container is a ListBoxItem. The generator calls back
into the ItemsControl to prepare the container.
2.Part of the preparation involves the copying of the ItemTemplate of the ListBox to be the ContentTemplate of the ListBoxItem.
3.Similar to all ContentControl types, the ControlTemplate of a ListBoxItem contains a ContentPresenter. When the template is applied,
it creates a ContentPresenter whose ContentTemplate is bound to the
ContentTemplate of the ListBoxItem.
4.Finally, the ContentPresenter applies that ContentTemplate to itself, and that creates the UI.
These steps are apparently not executed when you create ListBoxItem instances directly in XAML. It is however not strictly necessary to bind the ItemSource property. You may also directly set items like this:
<ListBox xmlns:sys="clr-namespace:System;assembly=mscorlib">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse Width="20" Height="20" Fill="LightBlue" />
<TextBlock Text="{TemplateBinding Content}" Foreground="Red" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Items>
<sys:String>html</sys:String>
<sys:String>head</sys:String>
<sys:String>body</sys:String>
<sys:String>table</sys:String>
<sys:String>tr</sys:String>
<sys:String>td</sys:String>
</ListBox.Items>
</ListBox>
public class MyViewModel
{
public List<String> Items
{
get { return new List<String> { "html", "head", "body","table","tr","td" }; }
}
}
//This can be done in the Loaded event of the page:
DataContext = new MyViewModel();
Your XAML
<ListBox Margin="20" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<Ellipse Width="20" Height="20" Fill="LightBlue" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

WPF binding Listbox layoutpanel

I´m using devexpress and I want to do a binding with a Listbox, but I have an error. Here my code:
<ListBox x:Name="_list" >
<ListBox.ItemTemplate>
<DataTemplate>
<dxd:LayoutPanel
Caption="{Binding nameList}"
AllowHide ="False" AllowFloat="False"
GotFocus="panel_GotFocus" >
<TextBox Text="Hello" />
</dxd:LayoutPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
With this code, Caption {Binding nameList} is empty.
I have tried this.
<ListBox x:Name="_list" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBox Text="{Binding nameList}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In this case, text in TextBox is correct, I need to use the first code.
You seem to be a bit confused about how to use this ListBox. First, you need a collection property to bind to the ListBox.ItemsSource property. Let's say you have a collection of User objects called Users:
<ListBox ItemSource="{Binding Users}" />
Now we want to define how each User should be displayed... all the properties of the User class will be available to the Binding inside the DataTemplate. Let's say that the User class has two properties; Name and Age:
<DataTemplate DataType="{x:Type YourDataTypeNamespace:User}">
<StackPanel>
<TextBox Text="{Binding Name}" />
<TextBox Text="{Binding Age}" />
</StackPanel>
</DataTemplate>
Then putting it all together:
<ListBox ItemSource="{Binding Users}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type YourDataTypeNamespace:User}">
<StackPanel>
<TextBox Text="{Binding Name}" />
<TextBox Text="{Binding Age}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Silverlight pass DataContext to ConverterParameter?

How can I pass the DataContext of LayoutRoot to the converter of the ContentControl inside the ListBox items template?
<Grid x:Name="LayoutRoot"
Background="White"
DataContext="{Binding Source={StaticResource myViewModel}}">
<StackPanel HorizontalAlignment="Left"
Margin="6,6,0,394"
Orientation="Vertical"
Width="200"
d:LayoutOverrides="Height">
<ListBox x:Name="listBox2"
ItemsSource="{Binding MyCollection, Mode=TwoWay}"
VerticalAlignment="Top"
Height="400">
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}"
ContentTemplate="{Binding Converter={StaticResource myConverter}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox Text="{Binding Value1, Mode=TwoWay}"/>
</StackPanel>
</Grid>
I want to be able to touch the objects inside the DataContext from within the Converter and use them for TwoWay binding on controls within the ListBox item's DataTemplate.
Any ideas? Any suggestions?
Thank you.
I just got the DataContext up to the converter using:
<ContentControl Content="{Binding}"
ContentTemplate="{Binding Converter={StaticResource stringToDataTemplateConverter}, ConverterParameter={StaticResource myViewModel}}" />
Now I have another problem my dynamic property binding is not working.
(sorry for my bad english)
I'm not sure about what you are trying to do here but with SL 5 you can use RelativeSource to get the DataContext:
{Binding DataContext,RelativeSource={RelativeSource AncestorLevel=1,AncestorType=Grid}}

Silverlight: DataGrid inside ListBox. Binding on DataGrid Column to a parent listbox's ItemsSource property. Silverlight

I'm a little puzzled with this one. I have a Collection called "AllProducts", which has a collection inside called "ProductGroups" (to group items separately) which inside contain a collection of "Product" objects called "LineItems" (the actual items).
To set this up, I have set a ListBox with a DataGrid inside the itemtemplate for the ListBox's Items. Setting the ItemsSource of the listbox to "ProductGroups" and the DataGrid(In the itemtemplate) has an ItemsSource pointing to LineItems.
The DataGrid contains Columns:
"Select" -- A checkbox and a radiobutton
"Image" -- string
"Name" -- string
"Description" -- string
"Price" -- string
The "ProductGroup" collection has a bool property called "IsListItem" per group, which is supposed to tell me if you can select multiple or a single item for that group (hence the checkbox and radiobutton in the first column of the DataGrid). I want the checkbuttons and radiobuttons visibility property to be bound to "IsListItem" bool which I have already set up with a BoolToVisibility converter with an "IsInverted" property to switch them back and forth.
The problem that I'm running into is that I want the first column of the DataGrid which contains the checkboxes/radiobuttons to be bound to the IsLineItem of ProductGroups (which is the ListBox's ItemsSource. But Since the DataGrid's ItemsSource is bound to LineItems, the DataContext of the DataGrid is set to LineItems and I can't access anything outside of it.
Here's some code to help:
ListBox XAML:
<sdk:TabItem Header="Pmt" x:Name="Payment">
<Canvas x:Name="PaymentRoot" DataContext="{Binding Products.ProductGroups}">
<Rectangle Height="418" Canvas.Top="-14" Width="560" Style="{StaticResource MappingRectangleBG}" />
<StackPanel Canvas.Left="20" Canvas.Top="20" Width="520" Height="360">
<ListBox x:Name="lstProductGroups" ItemsSource="{Binding}" ItemTemplate="{StaticResource ProductListItem}" />
</StackPanel>
</Canvas>
</sdk:TabItem>
ListBox ItemTemplate XAML:
<sdk:DataGrid x:Name="dgLineItems" ItemsSource="{Binding LineItems}">
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn Header="Select">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Visibility="{Binding IsListType, Converter={StaticResource boolToVisibilityConverter}}" />
<RadioButton Visibility="{Binding IsListType, Converter={StaticResource inverseBoolToVisibilityConverter}}" GroupName="{Binding GroupName}"/>
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="Image">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding ImageUrl}" Height="50" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTextColumn Header="Item Name"
Binding="{Binding Name}" />
<sdk:DataGridTextColumn Header="Item Price"
Binding="{Binding Price}" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</StackPanel>
</DataTemplate>
And my Objects:
public class AllProducts
{
public IEnumerable<ProductOptionGroup> ProductGroups;
}
public class ProductOptionGroup
{
public string GroupName;
public IEnumerable<Product> LineItems;
public bool IsListType;
}
public class Product
{
public int ID;
public int OrdinalNumber;
public string Name;
public string Description;
public Decimal Price;
public string ImageUrl;
public CartItemType Type;
}
(MichaelS): I tried setting it to the Parent "PaymentRoot" Canvas' DataContext but it isn't doing anything for me. Here is what I tried:
<CheckBox Visibility="{Binding ElementName=PaymentRoot, Path=DataContext.IsListType, Converter={StaticResource boolToVisibilityConverter}}" />
<RadioButton Visibility="{Binding ElementName=PaymentRoot, Path=DataContext.IsListType, Converter={StaticResource inverseBoolToVisibilityConverter}}" GroupName="{Binding ElementName=PaymentRoot, Path=DataContext.GroupName}"/>
(MichaelS): here's how it's set up in my VM:
private AllProducts products;
public AllProducts Products
{
get
{
return products;
}
set
{
//Products.ProductGroups[0].LineItems[0].
products = value;
RaisePropertyChanged("Products");
}
}
Update:
The below code won't work since it's a known issue that was discovered late in the Silverlight 3 timeframe.
Setting the Binding in the LoadingRow event using column.GetCellContent(e.Row) should solve the issue.
In this particular case , you want be able to do that since the dataGrid itself is a dataTemplate of another control.
Try this:
Wrap your datagrid with another Grid. Name it, and use it for the element binding.
This code should work:
<StackPanel>
<Grid x:Name="GridDataHolder">
<sdk:DataGrid x:Name="dgLineItems" ItemsSource="{Binding LineItems}">
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn Header="Select">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Visibility="{Binding ElementName=GridDataHolder, Path=DataContext.IsListType, Converter={StaticResource boolToVisibilityConverter}}" />
<RadioButton Visibility="{Binding ElementName=GridDataHolder, Path=DataContext.IsListType, Converter={StaticResource inverseBoolToVisibilityConverter}}" GroupName="{Binding ElementName=GridDataHolder, Path=DataContext.GroupName}"/>
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="Image">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding ImageUrl}" Height="50" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTextColumn Header="Item Name"
Binding="{Binding Name}" />
<sdk:DataGridTextColumn Header="Item Price"
Binding="{Binding Price}" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Grid>
</StackPanel>
By the way, i'm not sure if binding works with public members, you may need to change those binded members to public properties.
Finally got it fixed! What I had to end up doing was getting rid of the DataGrid altogether because a lot of controls from the toolkit seem to have that bug not being able to bind outside even through Element Binding.
I turned the DataGrid into a ListBox with another DataTemplate for the LineItems completely customizing the look of it to achieve a similar look that I had with the DataGrid.
Also to note: I tried at first binding to the StackPanel outside of the DataTemplate through Element Binding but it seemed to have a problem with that. So I set the grid inside the DataTemplate's DataContext and then I made the checkbox and radiobutton bound to the grid inside the Parent Listbox's dataTemplate through element binding and that did the trick!
Here is some working code for anybody who runs into this same issue later on!:
<DataTemplate x:Key="LineItemsTemplate">
<StackPanel Orientation="Horizontal">
<StackPanel Height="100" Width="100">
<StackPanel Height="40" Orientation="Vertical">
<RadioButton Content="{Binding Name}" Visibility="{Binding ElementName=GridDataHolder, Path=DataContext.IsListType, Converter={StaticResource boolToVisibilityConverter}}" GroupName="{Binding ElementName=GridDataHolder, Path=DataContext.GroupName}"/>
<CheckBox Content="{Binding Name}" Visibility="{Binding ElementName=GridDataHolder, Path=DataContext.IsListType, Converter={StaticResource inverseBoolToVisibilityConverter}}"/>
</StackPanel>
<Image Source="{Binding ImageUrl}" Height="50" />
</StackPanel>
<TextBlock TextWrapping="Wrap" Text="{Binding Description}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ProductListItem">
<StackPanel x:Name="GridDataHolder">
<TextBlock TextWrapping="Wrap" Text="{Binding GroupName}" VerticalAlignment="Top" d:LayoutOverrides="Width"/>
<ListBox x:Name="lstProductGroups" ItemsSource="{Binding LineItems}" ItemTemplate="{StaticResource LineItemsTemplate}">
</ListBox>
</StackPanel>
</DataTemplate>
<sdk:TabItem Header="Pmt" x:Name="Payment">
<Canvas>
<Rectangle Height="418" Canvas.Top="-14" Width="560" Style="{StaticResource MappingRectangleBG}" />
<ScrollViewer Height="389" Width="545" x:Name="PaymentRoot" DataContext="{Binding Products.ProductGroups}">
<StackPanel Orientation="Vertical" ScrollViewer.VerticalScrollBarVisibility="Auto" Width="500" HorizontalAlignment="Center">
<ListBox x:Name="lstProductGroups" ItemsSource="{Binding}" ItemTemplate="{StaticResource ProductListItem}" />
</StackPanel>
</ScrollViewer>
</Canvas>
</sdk:TabItem>
Thanks MichaelS for all your help! You got me going the right way!

Resources