bind textblock to current listbox item in pure xaml - wpf

i have some data saved in a xml file.
Those will be displayed in a listbox.
Now, when i change the listbox Selectedindex, i would like to update the other information in the textblock based on the selectedindex.
is there any way to do this in pure xaml?
if not, how would i bind the Textblock to the selecteditem in the listbox ?
EDIT:
How would i navigate through the Data without using the listbox? i mean using a button to move to next item and other button to move backward..!!
any help is really appreciated..
<Window x:Class="WpfSingleInstance.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<StackPanel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Cornsilk">
<StackPanel.Resources>
<XmlDataProvider x:Key="InventoryData" XPath="Inventory/Books">
<x:XData>
<Inventory xmlns="">
<Books>
<Book ISBN="0-7356-0562-9" Stock="in" Number="9">
<Title>XML in Action</Title>
<Summary>XML Web Technology</Summary>
</Book>
<Book ISBN="0-7356-1370-2" Stock="in" Number="8">
<Title>Programming Microsoft Windows With C#</Title>
<Summary>C# Programming using the .NET Framework</Summary>
</Book>
<Book ISBN="0-7356-1288-9" Stock="out" Number="7">
<Title>Inside C#</Title>
<Summary>C# Language Programming</Summary>
</Book>
</Books>
</Inventory>
</x:XData>
</XmlDataProvider>
</StackPanel.Resources>
<TextBlock FontSize="18" FontWeight="Bold" Margin="10"
HorizontalAlignment="Center">XML Data Source Sample</TextBlock>
<ListBox
Width="265" Height="98" x:Name="lbox" Background="Honeydew" IsSynchronizedWithCurrentItem="True">
<ListBox.ItemsSource>
<Binding Source="{StaticResource InventoryData}"
XPath="*[#Stock='out'] | *[#Number>=8 or #Number=3]"/>
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock FontSize="12" Foreground="Red">
<TextBlock.Text>
<Binding XPath="Title"/>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel DataContext="{StaticResource InventoryData}">
<TextBlock Text="{Binding XPath=Book/Title}"/>
<TextBox Margin="5,31,98,10" x:Name="textBoxMainDetail" Text="{Binding XPath=Book/Summary}" />
</StackPanel>
</StackPanel>
</Grid>

You could bind like this:
<TextBox Text="{Binding ElementName=lbox, Path=SelectedItem[Title].InnerText}" />
SelectedItem is an XmlElement.
EDIT: Here is a bit of sample code how to access the data of the XmlDataProvider in code behind and apply it as DataContent of a TextBox.
Change the TextBox.Text binding like this:
<TextBox x:Name="textBoxMainDetail" Text="{Binding Path=[Title].InnerText}" />
In code behind get the XML data from the XmlDataProvider and set the DataContext of the TextBox:
XmlDataProvider dataProvider = (XmlDataProvider)stackPanel.Resources["InventoryData"];
XmlElement books = (XmlElement)dataProvider.Document.SelectNodes(dataProvider.XPath)[0];
// set DataContext to an item from the child node collection
textBoxMainDetail.DataContext = books.ChildNodes[0];
Note that the StackPanel with the XmlDataProvider in its resource dictionary has now got a name. If this code shall run during application initialization (e.g. in Window constructor), the XmlDataProvider.IsAsynchronous property must be set to false.
You should now be able to change the DataContext to another indexed item of the books collection in a button click handler.

You need to set the SelectedValuePath as the 'Title' for your listbox. Then simply bind the your textBlock to the selectedValue of your listbox using elementName like this -
<ListBox Width="265" Height="98" x:Name="lbox" Background="Honeydew"
IsSynchronizedWithCurrentItem="True" SelectedValuePath="Title">
</ListBox>
<StackPanel DataContext="{StaticResource InventoryData}">
<TextBlock Text="{Binding Path=SelectedValue, ElementName=lbox}"/>
<TextBox Margin="5,31,98,10" x:Name="textBoxMainDetail" Text="{Binding XPath=Book/Summary}" />
</StackPanel>
</StackPanel>

Related

How can I access the controls in a listbox control generated by an itemtemplate

I have a listbox and a dataTemplate defined like so:
<Window.Resources>
<DataTemplate x:Key="propertyTemplate">
<StackPanel Margin="8" Orientation="Horizontal">
<CheckBox Name="Chosen"/>
<TextBlock Text="{Binding Path=MAP}" Margin="10,0,0,0"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="100" Margin="388,203,0,0" VerticalAlignment="Top" Width="522"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource propertyTemplate}"/>
I populate the listbox using a linq query:
Dim propertyList = (from a In db.properties
select a).ToList()
listbox.datacontext = propertyList
I want to check and set the value of the "Chosen" checkbox for each item in the listbox. Is there a way for me to do this?
Don't do it, bind IsChecked to a property on your item class, then iterate over your source list.

WPF UserControl or ControlTemplate... (not sure)

I have a listbox where I have to add about 20 static custom items. All the items are based on the same template (something like that) :
<Border>
<StackPanel Orientation="Horizontal">
<Image Source="" Height="30" />
<TextBlock Text="" VerticalAlignment="Center" />
</StackPanel>
</Border>
I don't want to repeat that 20 times in the ListBox.Items I would like to have some kind of UserControl where I could do something Like the following where I could set some custom properties :
<ListBox>
<ListBox.Items>
<MyListBoxTemplate x:Name="Item1" ItemText="Item #1" ItemImageSource="/Image1.jpg" />
<MyListBoxTemplate x:Name="Item2" ItemText="Item #2" ItemImageSource="/Image2.jpg" />
...
</ListBox.Items>
</ListBox>
But I don't wan't to create a userControl just for that!!! Is there an easy way to put that template in the Window.Resources?
Thanks
If you are ONLY using it for that SPECIFIC listbox, you can just assign the ItemTemplate property. This will need to work in conjunction with a collection of custom objects defined in your resources somewhere else. This will save you from creating a custom UserControl, but you will need an object that can be defined in XAML and a list of them in XAML anyway. To be honest, creating a UserControl is relatively painless and may be easier, but it is possible without doing so.
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate TargetType="CustomObjectType">
<Border>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImageSource}" Height="30" />
<TextBlock Text="{Binding TextContent}" VerticalAlignment="Center" />
</StackPanel>
</Border>
<DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
EDIT: If you are going to use it in more than one place, put the DataTemplate in your Application resources and ive it a key, then assign the ItemTemplate property to {StaticResource MyListBoxItemsTemplateKey}
Not my favorite approach since it uses the XmlDataProvider and XPath syntax (which I tend to always forget). But you can embed your static data as xml within your Window.Resources like so:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.Resources>
<XmlDataProvider x:Key="MyStaticData" XPath="StaticItems" >
<x:XData>
<StaticItems xmlns="">
<StaticItem>
<ItemText>Item #1</ItemText>
<ItemImageSource>/Image1.jpg</ItemImageSource>
</StaticItem>
<StaticItem>
<ItemText>Item #2</ItemText>
<ItemImageSource>/Image2.jpg</ItemImageSource>
</StaticItem>
</StaticItems>
</x:XData>
</XmlDataProvider>
</Window.Resources>
<Grid>
<ListBox>
<ListBox.ItemsSource>
<Binding Source="{StaticResource MyStaticData}" XPath="StaticItem" />
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<Border>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding XPath=ItemImageSource}" Height="30" />
<TextBlock Text="{Binding XPath=ItemText}" VerticalAlignment="Center" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Then within your ListBox bind to the XmlDataProvider you specified and use the XPath notation within the bindings to drill down to the data you want the controls to bind to.
This site has a couple good examples too:
http://vbcity.com/blogs/xtab/archive/2010/12/24/more-xpath-examples-in-a-wpf-application.aspx
Hope this helps!

Selecting listbox item inside datatemplate

I have a listbox that uses a data template. The template is very simple and consists of an Image and a TextBlock. They are both bound to an XML document. The template is as follows:
<Window.Resources>
<XmlDataProvider x:Key="NinjaData" Source="\Data\Ninjas.xml" XPath="/Ninjas"/>
<DataTemplate x:Key="NinjaDataTemplate">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0">
<Image Source="{Binding XPath=ImageFile}" Margin="5" Width="50"/>
<TextBlock Text="{Binding XPath=#Name}" Margin="5" FontFamily="OCR A Std" Foreground="#FF9114" FontSize="14" Name="NinjaName"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</Window.Resources>
The Listbox is as follows:
<ListBox Background="{x:Null}" BorderBrush="{x:Null}"
ItemsSource="{Binding Source={StaticResource NinjaData}, XPath=Ninja}"
ItemTemplate="{StaticResource NinjaDataTemplate}"
>
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Gray"></SolidColorBrush>
</ListBox.Resources>
<ListBox.Effect>
<DropShadowEffect ShadowDepth="1" Color="#FF282828"/>
</ListBox.Effect>
</ListBox>
I'm having trouble working out how to retrieve the content of the TextBlock inside the data template when I click on it in the listbox. I want to display it in a label somewhere else on the page, but I can't work out how to access that textblock.
Can anyone help and point me in the right direction? I feel like I'm going round in circles at the moment.
Thanks for any help.
As you have a ListBox you can use the selection, just name the ListBox and bind to the SelectedItem:
<ListBox Name="lb" ... />
<Label DataContext="{Binding SelectedItem, ElementName=lb}"
Content="{Binding XPath=#Name}"/>
This does not retrieve the Text of the TextBlock in the template but gets it from the same source as the template. (You could actually target the TextBlock in the Template itself but i would not recommend it)
Add a MouseLeftButtonUp event handler to your textblock inside your datatemplate like :
<TextBlock Text="{Binding XPath=#Name}" Margin="5" FontFamily="OCR A Std" Foreground="#FF9114" FontSize="14" Name="NinjaName" MouseLeftButtonUp="TextBlock_MouseLeftButtonUp"/>
Now your TextBlock_MouseLeftButtonUp should look like:
private void TextBlock_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
TextBlock txt = sender as TextBlock;
}
And now do whatever you like to do with txt

Binding to a data template control property

Is it possible to bind something to a property of a control in a data template entirely in XAML? The following code is a simplified version of the problem I'm running into. I'd like the text of the TextBlock (displayName) to be updated as the user types in the TextBox located in the DataTemplate.
<Window x:Class="WpfApplication4.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfApplication4="clr-namespace:WpfApplication4"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<DataTemplate DataType="{x:Type WpfApplication4:Foo}">
<TextBox Text="{Binding Path=Name}" />
</DataTemplate>
<WpfApplication4:Foo x:Key="testObject" Name="This is a test" />
</Window.Resources>
<StackPanel>
<TextBlock x:Name="displayName" Margin="5" />
<ContentControl x:Name="contentControl" Margin="5" Content="{StaticResource testObject}" />
</StackPanel>
No, at least, not from XAML. You could write code to traverse the visual tree and find the element you want to bind to, but that would be nasty.
But in your particular example, would it not make sense to just bind the TextBlock to the same data object (Foo instance)?

How to properly bind a ListBoxItem in WPF?

I have a listbox and I want to iterate over a collection of Bars in my Foo-object.
<ListBox DataContext="{Binding Path=Foo.Bars}" >
<ListBox.Items>
<ListBoxItem>
<ContentControl DataContext="{Binding Path=.}" />
</ListBoxItem>
</ListBox.Items>
</ListBox>
This is the datatemplate I want to use.
<DataTemplate DataType="{x:Type Bar}">
<Label Content="hello stackoverflow" />
</DataTemplate>
If I snoop (--> examine by using the tool Snoop) my application, I notice that the entire collection of Bars is bound to the ContentControl, in stead of just 1.
How can I properly bind so the iteration over the collection goes fine?
You can just set the DataTemplate, and WPF does all the work. Set the ItemsSource to a list of Bar items, and then define a DataTemplate for Bar items.
<ListBox ItemsSource="{Binding Path=Foo.Bars}">
<ListBox.Resources>
<DataTemplate DataType="{x:Type Bar}">
<Label Content="hello stackoverflow" />
</DataTemplate>
</ListBox.Resources>
</ListBox>
You could also set the ItemsTemplate directly by using <ListBox.ItemTemplate> instead of <ListBox.Resources>
See Data Binding Overview at MSDN.
First add your namespace to the Window element (Intellisense) :
xmlns:local="clr-namespace:yourenamespace"
Then the following XAML ( in Window.Resources is a clean way to do it ) :
<Window.Resources>
<ObjectDataProvider x:Key="DataProvider" ObjectType="{x:Type local:Foo}"/>
<DataTemplate x:Key="Template" >
<TextBlock Text="{Binding Bar}"/>
</DataTemplate>
</Window.Resources>
Place the Listbox :
<ListBox DataContext="{Binding Source={StaticResource DataProvider}}" ItemsSource="{Binding Bars}" ItemTemplate="DynamicResource Template" />
But, it depends on your code-behind object, you have to set a constructor to initialise public properties within your object which are ObservableCollection<> preferably (There is some restriction rules with object instance in XAML).

Resources