Nested DataTemplates in ListBox - c#

Is there any way to make a DataTemplate reference itself just from XAML? In this particular case trying to reference a DataTemplate from a ListBox contained within the same DataTemplate. Here is the solution I'd like, which doesn't work.
<DataTemplate x:Key="nestedItem" DataType="{x:Type local:NestedItem}">
<Expander Header="{Binding Path=Name}">
<ListBox ItemsSource="{Binding Path=Items}" x:Name="itemsList"
ItemTemplate="{StaticResource nestedItem}"/>
</Expander>
</DataTemplate>
And here's the solution I am currently using, which works.
<DataTemplate x:Key="nestedItem" DataType="{x:Type local:NestedItem}">
<Expander Header="{Binding Path=Name}" Expanded="OnItemExpanded">
<ListBox ItemsSource="{Binding Path=Items}" x:Name="itemsList"/>
</Expander>
</DataTemplate>
With code behind:
private void OnItemExpanded(object sender, RoutedEventArgs e)
{
if (e.OriginalSource != sender) return;
var source = (Expander) sender;
ListBox listBox = source.FindName("itemsList") as ListBox;
NestedItem item = source.DataContext as NestedItem;
listBox.ItemsSource = item.Items;
listBox.ItemTemplate = (DataTemplate) FindResource("nestedItem");
}

If you change your inner reference to be a DynamicResource instead of a StaticResource then it will work as you want. This is because there are some differences in how a StaticResource and DynamicResource actually look for the Resource item.
<DataTemplate x:Key="Local_NestedItem"
DataType="{x:Type local:NestedItem}">
<Expander Header="{Binding Path=Name}">
<ListBox ItemsSource="{Binding Path=Items}"
x:Name="itemsList"
ItemTemplate="{DynamicResource Local_NestedItem}" />
</Expander>
</DataTemplate>
Also, if you don't mind using some code, another good option is to use a DataTemplateSelector

Did you try using HierarchicalDataTemplate instead of DataTemplate for your first solution?
Did not test it for your case, but for treeviews it usually works that way.

Related

How to create a wpf template with nested datatemplate (datatemplate in datatemplate)

I'm totaly new to wpf. I try to create a nested datatemplate like this layout (datatemplate inside another datatemplate). I managed to create a datatemplate and to connect to "Object A" in an ObservableCollection, which worked really well. Now I need to have a nested ObservableCollection in each Object A to display Object B and Object C in columns. But I don't really know how to do that and can't find examples.
Maybe anyone could give me a hint?
Thanks and regards,
Marlene
Assuming you're using a ListView or ListBox to display a collection of Object A (lets call it ObjectACollection), and that Object A has properties named (in this example) ObjectBCollection and ObjectCCollection you could do something like this:
<UserControl xmlns:namespaceA="clr-namespace:MyProj.Models.ObjectANamespace"
xmlns:namespaceB="clr-namespace:MyProj.Models.ObjectBNamespace"
xmlns:namespaceC="clr-namespace:MyProj.Models.ObjectCNamespace" >
<ListBox ItemsSource="{Binding ObjectACollection}">
<ListBox.ItemTemplate>
<DataTemplate DataType="namespaceA:ObjectA">
<StackPanel Orientation="Horizontal">
<ListBox ItemsSource="{Binding ObjectBCollection}">
<ListBox.ItemTemplate>
<DataTemplate DataType="namespaceB:ObjectB">
<TextBlock Text="{Binding ObjectBProperty}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox ItemsSource="{Binding ObjectCCollection}">
<ListBox.ItemTemplate>
<DataTemplate DataType="namespaceC:ObjectC">
<TextBlock Text="{Binding ObjectCProperty}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>

TwoWay Binding WPF Treeview

WPF beginner here.
I managed to bind a TreeView control to a DataViewManager using the code shown at the end of this post. Everything works fine when populating the TreeView control initially but I want to implement two way binding so that I can use a textbox to filter out unwanted TreeView items.
My problem is that the treeview isn't updated if
I'm trying to use something like this:
private void SearchTree_TextChanged(object sender, TextChangedEventArgs e)
{
if(SearchTree.Text.Length>0)
Command.dvm.DataViewSettings["Categories"].RowFilter = "CategoryName LIKE '%"+SearchTree.Text+"%'";
}
Can anyone please help me find out what I'm doing wrong here?!
Xaml:
...
<UserControl.Resources>
<ObjectDataProvider
x:Key="dataVMProvider"
MethodName="CreateDataVM"
ObjectType="{x:Type local:DataVMCreator}"
/>
<DataTemplate x:Key="InstancesTemplate">
<TextBlock Text="{Binding InstanceUID}"/>
</DataTemplate>
<HierarchicalDataTemplate
x:Key="SymbolsTemplate"
ItemsSource="{Binding Symbols2Instances}"
ItemTemplate="{StaticResource InstancesTemplate}"
>
<TextBlock Text="{Binding SymbolName}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate
x:Key="FamiliesTemplate"
ItemsSource="{Binding Families2Symbols}"
ItemTemplate="{StaticResource SymbolsTemplate}"
>
<TextBlock Text="{Binding FamilyName}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate
x:Key="CategoriesTemplate"
ItemsSource="{Binding Categories2Families}"
ItemTemplate="{StaticResource FamiliesTemplate}"
>
<TextBlock Text="{Binding CategoryName}"/>
</HierarchicalDataTemplate>
</UserControl.Resources>
...
<TreeView
x:Name="ElementsTree"
...
DataContext="{StaticResource dataVMProvider}"
ItemsSource="{Binding Categories}"
ItemTemplate="{StaticResource CategoriesTemplate}"
/>
The DataViewManager comes from:
public static class DataVMCreator
{
public static DataViewManager CreateDataVM()
{
return Command.dvm;
}
}
Try this binding for the DataContext of your TreeView:
DataContext="{Binding Source={StaticResource dataVMProvider}}"

How to (is it possible to) set property of user control from outside?

This is my XAML:
<UserControl x:Class="SearchResultsBox">
<ListBox ItemsSource="{Binding SearchResults}" SelectedItem="{Binding Selected}"
Style="{StaticResource ListBoxStyle1}"
ItemContainerStyle="{StaticResource SearchItemContainerStyle}"
Background="{StaticResource DefaultBackground}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="Transparent">
<local:Forecast_SearchResults_ListView_Data/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl x:Class="SearchResultsBox">
I want to be able to reuse this listbox and just slap on a new datatemplate from the external context:
<local:SearchResultsBox>
<DataTemplate = {ForecastDataTemplate}/>
</local>
And it will put this DataTemplate into the ListBox.ItemTemplate property. Is this even possible? If so, how? If not, is there another way to achieve a similar effect?
you may use as follows
<local:SearchResultsBox ItemTemplate="{StaticResource ForecastDataTemplate}" />
and you can wire up the property to the underlying ListBox
eg
add a name to listbox
<ListBox x:Name="list" ... />
add a property wiring
public DataTemplate ItemTemplate
{
get { return list.ItemTemplate;}
set { list.ItemTemplate = value;}
}

Databinding CustomControls within PivotControls

I'm trying to use a PivotControlPage to control the paging of an object with a List
My current attempt is like so
<controls:Pivot x:Name="quizPivot" Title="MY APPLICATION" ItemsSource="{Binding Questions}" SelectedIndex="1" >
<controls:PivotItem Header="{Binding QuestionTitle }">
<Grid>
<local:Text5Control DataContext="{Binding .}"></local:Text5Control>
</Grid>
</controls:PivotItem>
</controls:Pivot>
I want the pivot control to control the "next" and "previous" actions and pass that current item to the DataContext of my custom control.
I'm doing this slightly wrong I think, but i'm setting the DataContext of the pivotcontrol and the currentitem in the code behind.
this is where i set the datacontext for the pivot control
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
quiz = new Quiz();
quiz.Questions = loadQuestions() // loads questions from file
quizPivot.DataContext = quiz;
}
I changed the xaml to look like this.
<controls:Pivot x:Name="quizPivot" Title="Mensa" SelectedIndex="1" DataContext="{Binding quiz}" ItemsSource="{Binding Questions}">
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding QuestionTitle}" />
</DataTemplate>
</controls:Pivot.HeaderTemplate>
<controls:Pivot.ItemTemplate>
<DataTemplate>
<Grid>
<local:Text5Control DataContext="{Binding .}"></local:Text5Control>
</Grid>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
What I was missing is the use of templates for the data. PivotItem is only applicable for static items.

ListBox with DoubleClick on Items using DataTemplate

I want to know if a double-clicking functionality for a ListBox can easily be build. I have a ListBox with a collection as ItemSource. The collection contains own data-types.
<ListBox ItemsSource="{Binding Path=Templates}"
ItemTemplate="{StaticResource fileTemplate}">
I defined a DataTemplate for my Items, which consists of StackPanels and TextBlocks.
<DataTemplate x:Key="fileTemplate">
<Border>
<StackPanel>
<TextBlock Text="{Binding Path=Filename}"/>
<TextBlock Text="{Binding Path=Description}"/>
</StackPanel>
</Border>
</DataTemplate>
Now I want to detect a double-click-event for the double-clicked list-item. Currently I tried with following, but it doesn't work because it doesn't return the Item bound to the ListBox but the TextBlock.
if (TemplateList.SelectedIndex != -1 && e.OriginalSource is Template)
{
this.SelectedTemplate = e.OriginalSource as Template;
this.Close();
}
What is a clean way to handle a double-click-event on an item in a ListBox, if the icons are not ListBoxItems, but own DataTemplates?
I've been playing around with this and I think I've got there...
The good news is, that you can apply a style to your ListBoxItem and apply a DataTemplate - the one does not preclude the other...
In other words, you can have something like the following:
<Window.Resources>
<DataTemplate x:Key="fileTemplate" DataType="{x:Type local:FileTemplate}">
...
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Templates}"
ItemTemplate="{StaticResource fileTemplate}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<EventSetter Event="MouseDoubleClick" Handler="DoubleClickHandler" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
and then implement a handler in your Window, like
public void DoubleClickHandler(object sender, MouseEventArgs e)
{
// item will be your dbl-clicked ListBoxItem
var item = sender as ListBoxItem;
// Handle the double-click - you can delegate this off to a
// Controller or ViewModel if you want to retain some separation
// of concerns...
}

Categories

Resources