How to have a GridView as a ContextMenu - wpf

Is it possible (if so how) to have a GridView control appear as a ContextMenu? When I tried following patterns which use a StackPanel as the ItemsPresenter, and naively used a ListView/GridView in its place, like the below, I receive the error "VisualTree of ItemsPanelTemplate must contain a Panel. 'System.Windows.Controls.ListView' is not a Panel." which specifies the problem, but how can I fix it/achieve what I want to do?
<Button.ContextMenu>
<ContextMenu ItemsSource="{Binding Source={x:Static local:Data.CurrentTimetabling},
Path=TheSemesters[0].SharedViews}">
<ContextMenu.Template>
<ControlTemplate TargetType="ContextMenu">
<ItemsPresenter Margin="0,5"/>
</ControlTemplate>
</ContextMenu.Template>
<ContextMenu.ItemsPanel>
<ItemsPanelTemplate>
<ListView>
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</ListView.View>
</ListView>
</ItemsPanelTemplate>
</ContextMenu.ItemsPanel>
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<ContentPresenter ContentSource="Header"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
<Button.ContextMenu>

Related

How to set DataTemplate width to the width of the Listbox?

Here's the example from MSDN.
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" BorderBrush="#FFA4B97F"
BorderThickness="0,0,0,1">
<Expander.Header>
<DockPanel>
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}"
Margin="5,0,0,0" Width="100"/>
<TextBlock FontWeight="Bold"
Text="{Binding Path=ItemCount}"/>
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
How can I make it occupy the whole width of the listbox? (HorizontalScrollBar is disabled)?
What I exactly need is DockPanel to be streched.
You have to include the reference of PresentationFramework.Aero in your project.
After this in your ListBox you have to insert this attribute:
<ListBox
xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
HorizontalContentAlignment="Stretch"
>
</ListBox>

How To Wpf TabItem Style HeaderTemplate Binding?

How To do Wpf TabItem Style HeaderTemplate Binding?
Code:
<TabControl x:Name="tabCtrlMain" ItemsSource="{Binding Items}" >
<TabControl.Resources>
<Style TargetType="TabItem">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type TabItem}">
<TextBlock Text="{Binding FileName}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
</TabControl>
this code is not working when binding:
<TextBlock Text="{Binding FileName}"/>
Try this Instead,
<TabControl x:Name="tabCtrlMain" ItemsSource="{Binding Items}" >
<TabControl.Resources>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding FileName}" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type TabItem}">
<Border x:Name="grid">
<ContentPresenter>
<ContentPresenter.Content>
<TextBlock Text="{TemplateBinding Content}"/>
</ContentPresenter.Content>
</ContentPresenter>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
</TabControl>
I know this is awfully old now, but I thought I'd throw my two cents in just for the sake of completeness and historical accuracy :)
I prefer to use the ItemContainerStyle to do the same thing just because it feels a little cleaner to me because it states the purpose exactly:
<TabControl ItemsSource="{Binding Items}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding FileName}" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<Border>
<TextBlock Text="{Binding Content}" />
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
Also, if the only goal is to get the FileName into the tabs then it can be much simpler:
<TabControl ItemsSource="{Binding Items}" DisplayMemberPath="FileName" />

How can I change the fontsize of a GridviewColumnHeader?

I included everything below since it's not that much. I wasn't sure if something I put elsewhere was causing my setter to not work properly.
<ListView x:Name="lvReports"
SelectionMode="Single"
ItemsSource="{Binding reportsCollection}" Height="432" ScrollViewer.HorizontalScrollBarVisibility="Hidden">
<ListView.Resources>
<Style x:Key="myHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="TextElement.FontSize" Value="30pt"/>
<Setter Property="Width" Value="800"/>
</Style>
</ListView.Resources>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<DockPanel>
<DockPanel Height="30" VerticalAlignment="Bottom">
<Image Source="\Images\ProductivityByEmployeesReport.png"/>
<TextBlock FontWeight="Bold" FontSize="18pt" Text="{Binding Path=Name}"/>
</DockPanel>
</DockPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
<ListView.View>
<GridView>
<GridViewColumn x:Name="colName" HeaderContainerStyle="{StaticResource myHeaderStyle}" Header="Reports">
<GridViewColumn.CellTemplate>
<DataTemplate>
<DockPanel>
<Rectangle Width="18"/>
<CheckBox>
<TextBlock Text="{Binding displayName}"/>
</CheckBox>
</DockPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Thanks in advance.
Add this to <ListView.Resources>
<Style TargetType="GridViewColumnHeader" x:Key="ColumnHeaderLarge">
<Setter Property="FontSize" Value="14"/>
</Style>
To set Fontsize to 14, use the style as:
<GridView ColumnHeaderContainerStyle="{StaticResource ColumnHeaderLarge}">

Is there any problem with having a ContentPresenter in ListBoxItem.ContentTemplate?

It seems like having a ContentPresenter in my ListBoxItem.ContentTemplate is causing Visual Studio to crash?
<ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<DockPanel>
<TextBlock><ContentPresenter /></TextBlock>
</DockPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBoxItem Content="Hello" />
<ListBoxItem Content="World" />
</ListBox>
Or maybe I am using ContentPresenter wrong? Basically, I want the text hello, world to go into those content presenters
The ItemTemplate of a ListBox is copied to the ContentTemplate of a ListBoxItem during UI generation. Meaning that your code is equivalent to the following.
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel>
<TextBlock><ContentPresenter /></TextBlock>
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBoxItem Content="Hello" />
<ListBoxItem Content="World" />
</ListBox>
However, you're adding the ListBoxItems directly so this is not 100% true.
(ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='ListBoxItem')
To elaborate on why Visual Studio crashes. First, it only crashes once the ListBox is being populated so this will only happend when adding ListBoxItem's directly in Xaml (Your app will still crash but not VS). The ContentPresenter is the place where the Template for the ListBox is inserting the ContentTemplate. So if we have this
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock><ContentPresenter /></TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
and we don't change the Template so it looks something like this (shortend version)
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
We will get
<ContentPresenter/> -> <TextBlock><ContentPresenter /></TextBlock> ->
<TextBlock><TextBlock><ContentPresenter /></TextBlock></TextBlock>
and so on. It never stops, and Visual Studio crashes. If we change the Template to this
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<TextBlock Text="No ContentPresenter Here"/>
</ControlTemplate>
</Setter.Value>
</Setter>
we get no crash since the ContentPresenter is never used.
(Think I crashed Studio a dozen times while trying this out :)
So in your case, you should use Template instead of ContentTemplate.
<ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<DockPanel>
<TextBlock><ContentPresenter /></TextBlock>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBoxItem Content="Hello" />
<ListBoxItem Content="World" />
</ListBox>

Hierarchical data binding with nested ListViews in WPF

I have some data that has a detail table. I want the data to be presented in a ListView. I want the detail data to appear as a nested ListView when you select an item in the original list. I can't seem to figure out how to get the data binding to work.
Here's what I have so far, (the problem is the {Binding Path=FK_History_HistoryItems}):
<ListView Name="lstHistory" ItemsSource="{Binding Source={StaticResource History}}" SelectionChanged="lstHistory_SelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=Name}" Header="Name" Width="100" />
<GridViewColumn DisplayMemberBinding="{Binding Path=Description}" Header="Description" Width="150" />
<GridViewColumn DisplayMemberBinding="{Binding Path=Total, Converter={StaticResource moneyConvert}}" Header="Total" Width="100" />
<GridViewColumn DisplayMemberBinding="{Binding Converter={StaticResource categoryAggregate}}" Header="Categories" Width="100" />
</GridView>
</ListView.View>
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border>
<StackPanel>
<Border Name="presenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<GridViewRowPresenter />
</Border>
<Border Name="details" Visibility="Collapsed" Margin="5"
BorderBrush="Black" BorderThickness="2">
<StackPanel Margin="5">
<ListView ItemsSource="{Binding Path=FK_History_HistoryItems}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=Ammount}" Header="Ammount" Width="100" />
<GridViewColumn DisplayMemberBinding="{Binding Path=Category}" Header="Category" Width="100" />
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</Border>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="details" Property="Visibility" Value="Visible" />
<Setter TargetName="presenter" Property="Background" Value="Navy"/>
<Setter TargetName="presenter" Property="TextElement.Foreground" Value="White" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.Resources>
</ListView>
If I understand your question correctly you need to bind to the SelectedItem of the original list:
<ListView ItemsSource="{Binding ElementName=lstHistory, Path=SelectedItem}">
And then set the datatemplate/view as needed. If you don't want to use ElementName for the binding you could also use RelativeSource but I find ElementName is easier to read and understand.
You need to change your problem line to the following:
<ListView ItemsSource="{Binding FK_History_HistoryItems}">
With that change, the control works beautifully. I have been working on something similar to no avail. I really like your work on this.
In order to get the Trigger to work, You will need to set the ControlTemplate TargetType:
<ControlTemplate TargetType="{x:Type ListViewItem}">
Without the TargetType being specified (as a Selectable type), the XAML rendering will be confused...

Resources