I am building a webscaper to scrape torrents, backend is already done and now I am kind of stuck on the UI(using WPF).
I want to display the torrents on a ListBox but corresponding to the query (I call it term as in search term).
The data passed to the ListBox is:
List<SearchTermData>
This is the structure:
public class SearchTermData {
public string SearchTerm { get; set; }
public List<Torrent> Torrents { get; set; } = new List<Torrent>();
}
Torrent is this:
public class Torrent {
public string Name { get; set; }
public string Size { get; set; }
}
I generally want the ListBox to display a Grid. Column 1 will be the "SearchTerm" and column 2 will be a StackPanel of "Torrents" (List<Torrent>).
It displays the "SearchTermData" correctly, with the SearchTerm name and the general structure, but it fails to display the StackPanel of the Torrents.
This is my XAML style:
<Style x:Key="TorrentListbox" TargetType="ListBox">
<Setter Property="UseLayoutRounding" Value="True" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="{StaticResource Black}"/>
<Setter Property="Background" Value="Transparent" />
<Setter Property="FontFamily" Value="{StaticResource DefaultFont}" />
<Setter Property="FontWeight" Value="Regular" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="SelectionMode" Value="Multiple" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.CanContentScroll" Value="True" />
<Setter Property="ItemContainerStyle" Value="{DynamicResource TermItem}" />
</Style>
<Style x:Key="TermItem" TargetType="ListBoxItem">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="{StaticResource DSGray}"/>
<Setter Property="Foreground" Value="{StaticResource Black}" />
<Setter Property="FontFamily" Value="{StaticResource DefaultFont}" />
<Setter Property="FontWeight" Value="Regular" />
<Setter Property="FontSize" Value="16" />
<Setter Property="Margin" Value="0,0,0,4"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="True" />
<Setter Property="UseLayoutRounding" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="0" UseLayoutRounding="{TemplateBinding UseLayoutRounding}" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
<Grid Background="{TemplateBinding Background}" HorizontalAlignment="Stretch" UseLayoutRounding="{TemplateBinding UseLayoutRounding}" Visibility="Visible">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Content="{Binding Path=SearchTerm}" BorderThickness="0,0,2,0" BorderBrush="{StaticResource Black}" Style="{StaticResource KeyLabel}" Foreground="{StaticResource DSGreen}" FontWeight="Bold" VerticalContentAlignment="Top" Grid.Row="0" Grid.Column="0"/>
<StackPanel Grid.Row="0" Grid.Column="1">
<ItemsControl ItemsSource="{Binding Path=Torrents}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="{StaticResource DSGreen}">
<ItemsControl ItemsSource="{Binding Torrent}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch" UseLayoutRounding="{TemplateBinding UseLayoutRounding}" Visibility="Visible">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Content="{Binding Path=Name}" Style="{StaticResource PropertyLabel}" Grid.Row="0" Grid.Column="0"/>
<Label Content="Size:" Style="{StaticResource KeyLabel}" Grid.Row="0" Grid.Column="1"/>
<Label Content="{Binding Path=Size}" Style="{StaticResource PropertyLabel}" Grid.Row="0" Grid.Column="2"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
If anyone can help me figure out the issue I would appreciate it a lot!
In your items template for Torrent, there is a nested ItemsControl that is not needed and that is binding to a property Torrent on an item of type Torrent, which does not exist.
<ItemsControl ItemsSource="{Binding Torrent}">
The control template below should work. I removed the redundant ItemsControl and the StackPanel as well, because it only contains a single control, which is why you do not need it.
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="0" UseLayoutRounding="{TemplateBinding UseLayoutRounding}" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
<Grid Background="{TemplateBinding Background}" HorizontalAlignment="Stretch" UseLayoutRounding="{TemplateBinding UseLayoutRounding}" Visibility="Visible">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Content="{Binding Path=SearchTerm}" BorderThickness="0,0,2,0" BorderBrush="{StaticResource Black}" Style="{StaticResource KeyLabel}" Foreground="{StaticResource DSGreen}" FontWeight="Bold" VerticalContentAlignment="Top" Grid.Row="0" Grid.Column="0"/>
<ItemsControl Grid.Row="0" Grid.Column="1" ItemsSource="{Binding Path=Torrents}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="{StaticResource DSGreen}">
<Grid HorizontalAlignment="Stretch" UseLayoutRounding="{TemplateBinding UseLayoutRounding}" Visibility="Visible">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Content="{Binding Path=Name}" Style="{StaticResource PropertyLabel}" Grid.Row="0" Grid.Column="0"/>
<Label Content="Size:" Style="{StaticResource KeyLabel}" Grid.Row="0" Grid.Column="1"/>
<Label Content="{Binding Path=Size}" Style="{StaticResource PropertyLabel}" Grid.Row="0" Grid.Column="2"/>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Border>
</ControlTemplate>
An Alternative Using ListView with GridView
Since you want to display two columns, you could alternatively use a ListView in combination with a GridView. This way, you would actually have real columns.
<ListView ItemsSource="{Binding SearchTerms}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="{StaticResource DSGray}"/>
<Setter Property="Foreground" Value="{StaticResource Black}" />
<Setter Property="FontFamily" Value="{StaticResource DefaultFont}" />
<Setter Property="FontWeight" Value="Regular" />
<Setter Property="FontSize" Value="16" />
<Setter Property="Margin" Value="0,0,0,4"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="True" />
<Setter Property="UseLayoutRounding" Value="True" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="0" UseLayoutRounding="{TemplateBinding UseLayoutRounding}" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
<GridViewRowPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Search Term">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Label Content="{Binding Path=SearchTerm}" BorderThickness="0,0,2,0" BorderBrush="Black" Foreground="Green" FontWeight="Bold"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Torrents">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Torrents}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="Green">
<Grid HorizontalAlignment="Stretch" UseLayoutRounding="{TemplateBinding UseLayoutRounding}" Visibility="Visible">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Content="{Binding Path=Name}" Grid.Row="0" Grid.Column="0"/>
<Label Content="Size:" Grid.Row="0" Grid.Column="1"/>
<Label Content="{Binding Path=Size}" Grid.Row="0" Grid.Column="2"/>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Related
Is there a way on how to open the Calendar Window when clicking DatePickerTextBox ?
Currently, It will open when clicking the "PART_Button" button.
So I want to also open at DatePickerTextBox "PART_TextBox"
Below is my code.
<Style TargetType="{x:Type DatePicker}">
<Setter Property="CalendarStyle" Value="{StaticResource Calendar_Style}" />
<Setter Property="FontFamily" Value="/Fonts/#Poppins"/>
<Setter Property="FontSize" Value="15" />
<Setter Property="FontWeight" Value="Regular"/>
<Setter Property="BorderThickness" Value="1" />
<Setter Property="SelectedDateFormat" Value="Short"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="Focusable" Value="True" />
<Setter Property="IsHitTestVisible" Value="True" />
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Background" Value="{DynamicResource Background}"/>
<Setter Property="BorderBrush" Value="White"/>
<Setter Property="Foreground" Value="{DynamicResource Text}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DatePicker}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" CornerRadius="4">
<Grid x:Name="PART_Root" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<DatePickerTextBox x:Name="PART_TextBox" Grid.Column="0" Grid.Row="0" Focusable="True" HorizontalAlignment="Left" Padding="5,0,0,0" VerticalAlignment="Center" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"
IsReadOnly="True" Background="{DynamicResource Background}" Foreground="White"
Style="{StaticResource DatePickerTextBoxStyle}" Grid.ColumnSpan="2" />
<Button x:Name="PART_Button" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center" Width="40" Height="40" BorderBrush="{x:Null}">
<iconPacks:Octicons Kind="Calendar"/>
</Button>
<Grid x:Name="PART_DisabledVisual" Grid.ColumnSpan="2" Grid.Column="0" IsHitTestVisible="False" Opacity="0" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Rectangle Grid.Column="1" Fill="Black" RadiusY="1" Grid.Row="0" RadiusX="1"/>
<Rectangle Grid.Column="0" Fill="Black" Height="18" Margin="3,0,3,0" RadiusY="1" Grid.Row="0" RadiusX="1" Width="19"/>
<Popup x:Name="PART_Popup" AllowsTransparency="True" Placement="Bottom" PlacementTarget="{Binding ElementName=PART_TextBox}" StaysOpen="False"/>
</Grid>
</Grid>
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Source={x:Static SystemParameters.HighContrast}}" Value="false">
<Setter Property="Foreground" TargetName="PART_TextBox" Value="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="{DynamicResource MainBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
Thank you very much.
You should be able to add a mouse event where you're using the DatePicker to open the dropdown for the calendar using:
private void OnClick(object sender, RoutedEventArgs e)
{
datePicker.IsDropDownOpen = true;
}
Alternatively, you could implement a custom control over the top of the DatePicker to handle this from the control itself.
I'm trying set backcolor for all grid layout in my project using resource dictionary. This is code of file where i modify my grid.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Theme">
<SolidColorBrush x:Key="GridBackColor" Color="Red"/>
<Style TargetType="Grid">
<Setter Property="Background" Value="{StaticResource GridBackColor}"/>
<Setter Property="Opacity" Value="0.5"/>
</Style>
</ResourceDictionary>
After set Background property all controls on grid were disappear, but when i set opacity i can only say that all controls are under grid layout and any mouse events not work.
Here how it's look like:
this is my window code.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10*"/>
<ColumnDefinition Width="125"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="125"/>
<ColumnDefinition Width="10*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10*"/>
<RowDefinition Height="40"/>
<RowDefinition Height="40"/>
<RowDefinition Height="20"/>
<RowDefinition Height="30"/>
<RowDefinition Height="10*"/>
</Grid.RowDefinitions>
<Label Content="Name" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="3" FontSize="20"
HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
<TextBox Name="TbName" Grid.Column="1" Grid.Row="2" Grid.ColumnSpan="3" FontSize="20"
HorizontalAlignment="Stretch" />
<Button Content="Add" Name="BtAdd" Grid.Column="1" Grid.Row="4" IsDefault="True"
HorizontalAlignment="Right" VerticalAlignment="Center" Width="100" Click="BtAdd_Click"/>
<Button Content="Close" Name="BtClose" Grid.Column="3" Grid.Row="4" IsCancel="True"
HorizontalAlignment="Left" Width="100" Click="BtClose_Click"/>
</Grid>
When you applied you style globally to all the Grids in your application, the ones used inside other controls will also be affected. For instance take a look at the Window control (from the vs designer, left click on the window > Edit Template > Edit a copy)
<Window.Resources>
<ControlTemplate x:Key="WindowTemplateKey" TargetType="{x:Type Window}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
<Grid>
<AdornerDecorator>
<ContentPresenter/>
</AdornerDecorator>
<ResizeGrip x:Name="WindowResizeGrip" HorizontalAlignment="Right" IsTabStop="false" Visibility="Collapsed" VerticalAlignment="Bottom"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ResizeMode" Value="CanResizeWithGrip"/>
<Condition Property="WindowState" Value="Normal"/>
</MultiTrigger.Conditions>
<Setter Property="Visibility" TargetName="WindowResizeGrip" Value="Visible"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="WindowStyle1" TargetType="{x:Type Window}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
<AdornerDecorator>
<ContentPresenter/>
</AdornerDecorator>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="ResizeMode" Value="CanResizeWithGrip">
<Setter Property="Template" Value="{StaticResource WindowTemplateKey}"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
Notice the Grid defined in the Border inside the ControlTemplate.
An easy fix to your issue is to assign a key to your style and assign it to the Grid manually:
<Style TargetType="Grid" x:Key="GridStyle">
<Setter Property="Background" Value="{StaticResource GridBackColor}"/>
<Setter Property="Opacity" Value="0.5"/>
</Style>
To use it:
<Grid Style="{StaticResource GridStyle}">
...
</Grid>
I've formatted a ComboBox to display each item's details, please don't take the design as final, it's just an example:
But as you can see, the displayed item (Inside the box with the arrow) is broken:
So I need to format that component too, to display only the Server value in that box. I've tried to find the correct element, and even managed to find a way to reformat the whole combo box, but no way to add a template for the data display inside that box.
How do I edit the data template for that container? This is the result I'd expect:
<ComboBox x:Name="cboSourceMySql" Grid.Column="1" Margin="5,0,5,0" ItemsSource="{Binding OdbcDataSources, Mode=TwoWay}" Grid.Row="1" >
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Label Content="Server:" Grid.Column="0" Grid.Row="0" />
<TextBlock Text="{Binding Server}" VerticalAlignment="Center" Grid.Column="1" Grid.Row="0" />
<Label Content="Driver:" Grid.Column="0" Grid.Row="1" />
<TextBlock Text="{Binding Driver}" VerticalAlignment="Center" Grid.Column="1" Grid.Row="1" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
From the article WPF Combobox: Different template in textbox and drop-downlist
I think you can use the below style
<ComboBox
x:Name="cboSourceMySql"
Grid.Column="1" Margin="5,0,5,0"
ItemsSource="{Binding OdbcDataSources, Mode=TwoWay}"
Grid.Row="1" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Server}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Border
x:Name="Bd"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<StackPanel Orientation="Vertical">
<Label Content="{Binding Server}" />
<Label Content="{Binding Driver}" />
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
I am trying to create a context menu with two columns like this:
The text of the item is bound the Name property of the item and the shortcut key is bound to the GestureText property. However, the column definitions do not seem to be obeyed and I see this:
My XAML is as follows:
<Window x:Class="ContextMenu2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid Margin="0,2,0.4,-2.2">
<TextBlock Text="RightClickMe" HorizontalAlignment="Left" VerticalAlignment="Top">
<TextBlock.ContextMenu>
<ContextMenu ItemsSource="{Binding Items}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50*"/>
<ColumnDefinition Width="70*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Name}" />
<TextBlock Grid.Column="1" Text="{Binding GestureText}"/>
</Grid>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</Grid>
</Window>
C#
using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Windows;
using System.Windows.Input;
namespace ContextMenu2
{
public class CMenu
{
public String Name { get; set; }
public string GestureText { get; set; }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public ObservableCollection<CMenu> Items { get; set; }= new ObservableCollection<CMenu>
{
new CMenu()
{
Name = "Press me",
GestureText =
new KeyGesture(Key.Q, ModifierKeys.Control).GetDisplayStringForCulture(CultureInfo.CurrentUICulture)
},
new CMenu()
{
Name = "Press me too",
GestureText =
new KeyGesture(Key.R, ModifierKeys.Control).GetDisplayStringForCulture(CultureInfo.CurrentUICulture)
}
};
}
}
What's wrong here?
You can bind InputGestureText in ItemContainerStyle to GestureText:
<ContextMenu ItemsSource="{Binding Items}" HorizontalContentAlignment="Stretch">
<ContextMenu.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="InputGestureText" Value="{Binding GestureText}"/>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
Also note that setting HorizontalAlighnment or HorizontalContentAlignment is not going to help. Please note this part of the default style:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"
SharedSizeGroup="Icon" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto"
SharedSizeGroup="Shortcut" />
<ColumnDefinition Width="13" />
</Grid.ColumnDefinitions>
and the margin of the TextBlock in the third column which is Margin="5,2,2,2".
I haven't tested this, but my guess would be that the MenuItems that contain your columns are not taking up the full width themselves (they are probably left aligned). So maybe try changing their alignment using , e.g. something like this:
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
</Style>
</ContextMenu.ItemContainerStyle>
If you really want to create a custom looking ContextMenu you need to override the ControlTemplate of the MenuItem ItemContainer, i.e. define your Grid in the ControlTemplate instead of this one instead of in the ItemTemplate of the ContextMenu:
<TextBlock Text="RightClickMe" HorizontalAlignment="Left" VerticalAlignment="Top">
<TextBlock.ContextMenu>
<ContextMenu ItemsSource="{Binding Items}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<Border x:Name="templateRoot" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid Margin="-1">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="22" SharedSizeGroup="MenuItemIconColumnGroup" Width="Auto"/>
<ColumnDefinition Width="13"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="5*" SharedSizeGroup="a"/>
<ColumnDefinition SharedSizeGroup="MenuItemIGTColumnGroup" Width="Auto"/>
<ColumnDefinition Width="7*" SharedSizeGroup="b"/>
</Grid.ColumnDefinitions>
<ContentPresenter x:Name="Icon" Content="{TemplateBinding Icon}" ContentSource="Icon" HorizontalAlignment="Center" Height="16" Margin="3" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center" Width="16"/>
<Border x:Name="GlyphPanel" BorderBrush="#FF26A0DA" BorderThickness="1" Background="#3D26A0DA" ClipToBounds="False" HorizontalAlignment="Center" Height="22" Margin="-1,0,0,0" Visibility="Hidden" VerticalAlignment="Center" Width="22">
<Path x:Name="Glyph" Data="F1M10,1.2L4.7,9.1 4.5,9.1 0,5.2 1.3,3.5 4.3,6.1 8.3,0 10,1.2z" Fill="#FF212121" FlowDirection="LeftToRight" Height="11" Width="10"/>
</Border>
<ContentPresenter x:Name="menuHeaderContainer" ContentTemplate="{TemplateBinding HeaderTemplate}"
Content="{Binding Name}" Grid.Column="2" ContentStringFormat="{TemplateBinding HeaderStringFormat}" ContentSource="Header" HorizontalAlignment="Left" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
<TextBlock x:Name="menuGestureText" Grid.Column="4" Margin="{TemplateBinding Padding}"
Text="{Binding GestureText}" VerticalAlignment="Center" HorizontalAlignment="Right"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Icon" Value="{x:Null}">
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Visibility" TargetName="GlyphPanel" Value="Visible"/>
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter Property="Background" TargetName="templateRoot" Value="#3D26A0DA"/>
<Setter Property="BorderBrush" TargetName="templateRoot" Value="#FF26A0DA"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="#FF707070"/>
<Setter Property="Fill" TargetName="Glyph" Value="#FF707070"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsHighlighted" Value="True"/>
<Condition Property="IsEnabled" Value="False"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="templateRoot" Value="#0A000000"/>
<Setter Property="BorderBrush" TargetName="templateRoot" Value="#21000000"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
If you simply want to bind the InputGestureText property to your GestureText property you should refer to #Ron's answer.
Is it possible to create some sort of base expander style and override the background color of the header in a derived style?
In my application I'm using expanders a lot and I would like to change the background color of the header. I know I could just copy&paste my style and edit the color, but it would be nicer to just create a new style based on the "base style" and setting the header's background color.
But I do not know how to access this color.
It's the color of this line: below I'd like to change (the border in the header): Border Name="border"... I cannot access "border" in the setter of the derived style...
This is my (base) style:
<Style TargetType="Expander" x:Key="ExpanderStyle">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextColor}}"/>
<Setter Property="Template">
<Setter.Value>
<!-- Control template for expander -->
<ControlTemplate TargetType="Expander" x:Name="exp">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Name="ContentRow" Height="0"/>
</Grid.RowDefinitions>
<Border Name="border" Grid.Row="0" Background="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}" BorderThickness="1" CornerRadius="4,4,0,0" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<ToggleButton x:Name="tb" FontFamily="Marlett" FontSize="9.75" Background="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}" Foreground="Black" Grid.Column="1" Content="u" IsChecked="{Binding Path=IsExpanded,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}" />
<ContentPresenter x:Name="HeaderContent" Grid.Column="0" Margin="4" ContentSource="Header" RecognizesAccessKey="True" />
</Grid>
</Border>
<Border x:Name="Content" Grid.Row="1" BorderThickness="1,0,1,1" CornerRadius="0,0,4,4" >
<ContentPresenter Margin="4" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Setter TargetName="ContentRow" Property="Height" Value="{Binding ElementName=Content,Path=Height}" />
<Setter Property="Content" TargetName="tb" Value="t"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I would like to do something like this:
<Style x:Key="ExpanderStyleRed" BasedOn="{StaticResource ExpanderStyle}" TargetType="Expander">
<Setter Property="???" Value="Red"/>
<Style>
Use TemplateBinding:
<Style TargetType="Expander" x:Key="ExpanderStyle">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextColor}}"/>
<Setter Property="Template">
<Setter.Value>
<!-- Control template for expander -->
<ControlTemplate TargetType="Expander" x:Name="exp">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Name="ContentRow" Height="0"/>
</Grid.RowDefinitions>
<Border Name="border" Grid.Row="0" Background="{TemplateBinding Background}" BorderThickness="1" CornerRadius="4,4,0,0" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<ToggleButton x:Name="tb" FontFamily="Marlett" FontSize="9.75" Background="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}" Foreground="Black" Grid.Column="1" Content="u" IsChecked="{Binding Path=IsExpanded,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}" />
<ContentPresenter x:Name="HeaderContent" Grid.Column="0" Margin="4" ContentSource="Header" RecognizesAccessKey="True" />
</Grid>
</Border>
<Border x:Name="Content" Grid.Row="1" BorderThickness="1,0,1,1" CornerRadius="0,0,4,4" >
<ContentPresenter Margin="4" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Setter TargetName="ContentRow" Property="Height" Value="{Binding ElementName=Content,Path=Height}" />
<Setter Property="Content" TargetName="tb" Value="t"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ExpanderStyleRed" BasedOn="{StaticResource ExpanderStyle}" TargetType="Expander">
<Setter Property="Background" Value="#2fff0000"/>
</Style>
And then:
<Grid>
<Expander x:Name="expander1" Style="{DynamicResource ExpanderStyle}" Header="Expander" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="7,10,0,0" Height="108">
<TextBlock Width="250" Height="150" TextWrapping="Wrap">
asklsaklsa saaskklsaklas alsaklalkjd
asklsaklsaklsa saklsaklsakl jsajkjska
saklsaklsakl sasa
</TextBlock>
</Expander>
<Expander x:Name="expander2" Style="{DynamicResource ExpanderStyleRed}" Header="Expander" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="12,126,0,0" Height="133">
<TextBlock Width="250" Height="150" TextWrapping="Wrap">
asklsaklsa saaskklsaklas alsaklalkjd
asklsaklsaklsa saklsaklsakl jsajkjska
saklsaklsakl sasa
</TextBlock>
</Expander>
</Grid>