WPF: HierarchicalDataTemplate ItemsPanel - wpf

I have a ``TreeViewwhich uses a customItemsPanelto show the first level of items in aStackPanel, but I need to show subitems in aStackPaneltoo. The problem is, the second level of items are shown in aWrapPanel, and asHierarchicalDataTemplatedoesn't have anItemsPanel` property I'm not sure how to do this. This is my xaml:
<TreeView x:Name="treGlobalCards">
<TreeView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True" Orientation="{Binding Orientation,RelativeSource={x:Static RelativeSource.TemplatedParent}}"
MaxWidth="{Binding ActualWidth,RelativeSource={RelativeSource AncestorType={x:Type ScrollContentPresenter}}}"/>
</ItemsPanelTemplate>
</TreeView.ItemsPanel>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate x:Key="CardTypeTemplate" ItemsSource="{Binding Cards}">
<TextBlock Text="{Binding Path=CardType}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>

Create a new DataTemplate that uses a StackPanel and set the HierachicalDataTemplate's "ItemTemplate" to that new DataTemplate.
i.e.
<DataTemplate x:Key="someTemp">
<StackPanel />
</DataTemplate>
<HierarchicalDataTemplate x:Key="hierTemp" ItemSource="{Binding}" ItemTemplate="{StaticResource someTemp}" />

Related

How to find datacontext of parent's parent for dynamic control

We have following xaml code to display context menu and fire command when delete menu is clicked.
For the context menu item, I would like to bind command which is present in DataContext of ItemsControl. We tried with RelativeSource={RelativeSource TemplatedParent} but as the tree is created dynamically (using dataContext) it is not able to find DeleteCommand.
<Grid x:Name="MyGrid" >
<ItemsControl ItemsSource="{Binding Path=TreeRoot.Children}">
<ItemsControl.ItemTemplate>
<HierarchicalDataTemplate>
<StackPanel>
<Label Background="Black" Content="{Binding Path=DisplayText}"/>
<TreeView ItemsSource="{Binding Converter={StaticResource myCompositeNodeConverter}}" >
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:CompositeNode}" ItemsSource="{Binding Path=Children}" >
<TextBlock Text="{Binding Path=DisplayText}" Foreground="Black"></TextBlock>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:LeafNode}" ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=DisplayText}"></TextBlock>
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeView.ContextMenu>
<ContextMenu >
<MenuItem Header="Delete" Command="{Binding DeleteCommand}" />
</ContextMenu>
</TreeView.ContextMenu>
</TreeView>
</StackPanel>
</HierarchicalDataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
How do we bind DeleteCommand for context menu item to DataContext of ItemsControl?

Change element inside Template

I want to reuse the the ItemsControl from my ListView and its not really hard to put the ItemsControle into an Template.
The problem is, I want to change the DataTemplate when I use my ItemsControlTemplate.
<ListView DataContext="{Binding Input}">
<ItemsControl ItemsSource="{Binding Columns}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<Label Content="{Binding ColumnHeader}"></Label>
</StackPanel>
<ListView Grid.Row="1">
<ItemsControl ItemsSource="{Binding ColumnData}">
<ItemsControl.ItemTemplate>
<!--This should be changed when I reuse my ItemsControl-->
<DataTemplate>
<Button Content="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ListView>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ListView>
You can use a Resource to set that ItemTemplate dynamically. Just provide a default Resource of DataTemplate, when you need to change it, override that resource (using the same key and place in a closer place to the control).
<ListView Grid.Row="1">
<ItemsControl ItemsSource="{Binding ColumnData}"
ItemTemplate="{StaticResource templateKey}"/>
</ListView>
Then define a resource with x:Key of templateKey like this:
<Window.Resources>
<DataTemplate x:Key="templateKey">
<Button Content="{Binding}"/>
</DataTemplate>
<Window.Resources>
Here is an example of overriding the template, in which we place another DataTemplate inside the ListView's Resources:
<ListView DataContext="{Binding Input}">
<ListView.Resources>
<DataTemplate x:Key="templateKey">
<CheckBox Content="{Binding}"/>
</DataTemplate>
</ListView.Resources>
<!-- ... -->
</ListView>
If you want to update the template at runtime, you need to use DynamicResource instead of StaticResource.

Scrolling of a listbox inside another listbox

I have a listbox (with normal vertical orientation), each element of which is a listbox with horizontal orientation.
I want to have a ScrollBar inside of internal listbox. So, my problem is how to set width of internal listbox according to real current width of external.
My current code is:
<Window.Resources>
<HierarchicalDataTemplate x:Key="ItemTemplateSchedule">
<ListBox>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBoxItem>My-Very-Long-Item-Nimber-1___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-2___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-3___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-4___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-5___</ListBoxItem>
</ListBox>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemTemplate="{StaticResource ItemTemplateSchedule}" >
>
</ListBox>
</Grid>
Current screenshot:
.
UPD1
Ok, answer to my question is setting of width for internal listbox, thanks to #sa_ddam213:
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=ActualWidth}"
Now I want add some new control in each row of external listbox:
<HierarchicalDataTemplate x:Key="ItemTemplateSchedule">
<StackPanel Orientation="Horizontal" Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=ActualWidth}">
<TextBlock Text="This is Text in a TextBlock"/>
<ListBox >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBoxItem>My-Very-Long-Item-Number-1___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Number-2___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Number-3___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Number-4___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Number-5___</ListBoxItem>
</ListBox>
</StackPanel>
</HierarchicalDataTemplate>
And it doesn't work now! Is it possible to solve this problem? Current screenshot:
You can use a FindAncestor to bind to the parent ListBox ActualWidth
Example:
<Window.Resources>
<HierarchicalDataTemplate x:Key="ItemTemplateSchedule">
<ListBox Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=ActualWidth}" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBoxItem>My-Very-Long-Item-Nimber-1___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-2___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-3___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-4___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-5___</ListBoxItem>
</ListBox>
</HierarchicalDataTemplate>
</Window.Resources>
Result:

How to bind AccordionItem Visibility when using Accordion.ItemTemplate in Silverlight?

Accordion item Visibility property can be bound like this:
<layoutToolkit:Accordion x:Name="MyAccordion">
<layoutToolkit:AccordionItem Visibility="{Binding IsVisible, Converter={StaticResource VisibilityConverter}}">
...
</layoutToolkit:AccordionItem>
</layoutToolkit:Accordion>
But how to bind it when using Accordion.ItemTemplate?
<layoutToolkit:Accordion ItemsSource="{Binding AcordionItems}" x:Name="MyAccordion">
<layoutToolkit:Accordion.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</layoutToolkit:Accordion.ItemTemplate>
<layoutToolkit:Accordion.ContentTemplate>
<DataTemplate>
...
</DataTemplate>
</layoutToolkit:Accordion.ContentTemplate>
</layoutToolkit:Accordion>
I can bind IsVisible to elements inside DataTemplate, but then an empty accordion item is displayed. I need to be able to show/hide the whole accordion item.
I ended up using StackPanel with multiple Accordions:
<StackPanel Orientation="Vertical">
<ItemsControl ItemsSource="{Binding AcordionItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<layoutToolkit:Accordion Visibility="{Binding IsVisible, Converter=
{StaticResource VisibilityConverter}}">
<layoutToolkit:AccordionItem>
...
</layoutToolkit:AccordionItem>
</layoutToolkit:Accordion>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>

DataBind string to DataTemplated checkbox

I want to create a ListBox filled with checkboxes in WPF, and I want to databind the "Content" value with a simple string value. However when I try <CheckBox Margin="5" Content="{Binding}" /> the app crashes.
This is what I have. ( I'm sure I am missing something simple )
<ListBox Grid.Row="1" IsSynchronizedWithCurrentItem="True" x:Name="drpReasons">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" >
</WrapPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.Resources>
<DataTemplate DataType="{x:Type System:String}">
<CheckBox Margin="5" Content="{Binding}" />
</DataTemplate>
</ListBox.Resources>
</ListBox>
You created an infinitely recursive DataTemplate. By setting the DataTemplate for String, and then setting the Content of CheckBox to a String, the CheckBox will use the DataTemplate itself, so you'll have CheckBoxes within CheckBoxes and so on.
You can fix it by putting a TextBlock inside the CheckBox explicitly:
<ListBox x:Name="drpReasons" Grid.Row="1" IsSynchronizedWithCurrentItem="True">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal">
</WrapPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.Resources>
<DataTemplate DataType="{x:Type sys:String}">
<CheckBox Margin="5">
<TextBlock Text="{Binding}"/>
</CheckBox>
</DataTemplate>
</ListBox.Resources>
</ListBox>

Resources