In Main.xaml I have these two menu items:
The first with the header = Disconnect from current
The second with the header = Quit
...
More menu items with different header texts...
In order to edit some colors of the first item I created a custom template in App.xaml:
<!--Template for Menu Items-->
<Style x:Key="MenuItemBaseStyle" TargetType="MenuItem">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="#0a99f3" />
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<Grid Background="{TemplateBinding Background}">
<MenuItem Header="DISCONNECT FROM CURRENT" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And in Main.xaml:
<MenuItem Header="CONNECTION">
<MenuItem Style="{StaticResource MenuItemBaseStyle}" Header="DISCONNECT FROM CURRENT" />
<MenuItem Header="QUIT"/>
</MenuItem>
Now I want to do the same for the second menu item. The problem is with the different header. If I delete the header from the template, it won't show any header even if the header text is still present in Main.xaml
How can I use this template for many menu items where the only thing that changes is the header text?
You could just use TemplateBinding on the Header property in the same way you've used it on the Background property:
<ControlTemplate TargetType="{x:Type MenuItem}">
<Grid Background="{TemplateBinding Background}">
<MenuItem Header="{TemplateBinding Header}" />
</Grid>
</ControlTemplate>
You can make an individual style for every MenuItem using a StyleSelector.
public class MyStyleSelector : StyleSelector
{
public override Style SelectStyle(object item, DependencyObject container)
{
var itemsControl = ItemsControl.ItemsControlFromItemContainer(container);
var index = itemsControl.ItemContainerGenerator.IndexFromContainer(container);
if (index == 0)
return (Style)itemsControl.FindResource("FirstItemStyle");
if (index == 1)
return (Style)itemsControl.FindResource("SecondItemStyle");
return base.SelectStyle(item, container);
}
}
And in your XAML
<Window x:Class="Menus.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Menus"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:MyStyleSelector x:Key="MyStyleSelector" />
<Style x:Key="FirstItemStyle" TargetType="MenuItem">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="#0a99f3" />
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="SecondItemStyle" TargetType="MenuItem">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Menu ItemContainerStyleSelector="{StaticResource MyStyleSelector}">
<MenuItem Header="Menu 1" />
<MenuItem Header="Menu 2" />
<MenuItem Header="Menu 3" />
</Menu>
</Grid>
See StyleSelector here: StyleSelector
Related
I have an an DataGrid in which I load Data from an ObservableCollection and each row has an CheckBox so that I can have a list of checked Rows. Now I wanted to add an new Column to the DataGrid which is an ComboBox and in the ComboBox is a list with Checkboxen. I want for each row that when I check one Row and then when I check other Items from the ComboBox that I can combine the selected row and the selected values from my ComboBox.
The problem is that if I check one Row of the Combobox item it will check for every other ComboBox that appears in the DataGrid.
I want only to check the value of the combobox for one row and combine it with the Value of the checked row of the datagrid.
Here is my Code of my DataGrid:
<DataGrid Style="{DynamicResource DataGridStyle}"
Margin="10" SelectionUnit="CellOrRowHeader" AutoGenerateColumns="False"
CanUserAddRows="False" CanUserDeleteRows="False" SelectionMode="Single" VerticalAlignment="Stretch"
x:Name="SpaltenGrid" ItemsSource="{Binding bischenanders, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
GridLinesVisibility="None" ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<DataGrid.Columns >
<DataGridCheckBoxColumn x:Name="selectedField" Binding="{Binding IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="Auswahl" CanUserSort="False">
<DataGridCheckBoxColumn.ElementStyle>
<Style TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}" />
</DataGridCheckBoxColumn.ElementStyle>
</DataGridCheckBoxColumn>
<DataGridTextColumn Header="Spaltenname" Binding="{Binding Spaltenname}" Width="1.5*"/>
<DataGridComboBoxColumn x:Name="cmbAdditionColume" Header="AdditionsSpalten" DisplayMemberPath="Spaltenname"
CanUserSort="False" Width="*">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox" BasedOn="{StaticResource ComboBoxStyle1 }" />
</DataGridComboBoxColumn.ElementStyle>
</DataGridComboBoxColumn>
<!--<DataGridTemplateColumn Header="Week Days" Width="*" x:Name="cmbTemplateColumn">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="cmbAdditionColume" Foreground="Black"
DisplayMemberPath="Spaltenname" Style="{StaticResource ComboBoxStyle1}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>-->
</DataGrid.Columns>
<DataGrid.Resources>
<!-- Select everything with orange... -->
<SolidColorBrush
Color="Transparent"
x:Key="{x:Static SystemColors.HighlightBrushKey}" />
<!-- ...all the time -->
<SolidColorBrush
Color="Transparent"
x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" />
<!--Design kopfzeile-->
<Style TargetType="{x:Type DataGridColumnHeader}" x:Name="test2" >
<Setter Property="Background" Value="Red"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Height" Value="30"/>
<Setter Property="FontSize" Value="15"/>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="Green"/>
<Setter Property="Padding" Value="10 0 0 0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid x:Name="insideHeader" Background="Transparent">
<Border x:Name="borderHeader" BorderThickness="0"
CornerRadius="10"
Background="White"
Padding="10,0,0,0"
>
<ContentPresenter />
</Border>
<!--<Thumb HorizontalAlignment="Right"
Grid.Column="1"
Name="PART_HeaderGripper"
Margin="0,4,0,4"
Width="2"/>-->
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="{DynamicResource PrimaryBlueColor}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="borderHeader" Property="Background" Value="{DynamicResource SecundaryGrayColor}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type DataGridRowHeader}">
<Setter Property="Content" Value=">" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryBlueColor}" />
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridRowHeader}">
<Grid x:Name="insideHeader" Background="Transparent">
<Border x:Name="borderHeader" BorderThickness="0"
CornerRadius="2"
Background="White"
Padding="0,10,0,0"
>
<TextBlock Text=">" FontSize="12" VerticalAlignment="Top" Margin="0 0 0 0" TextAlignment="Center" FontWeight="Bold" Width="20" Foreground="{DynamicResource PrimaryBlueColor}" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True" >
<Setter TargetName="borderHeader" Property="Background" Value="{DynamicResource PrimaryGrayColor}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="borderHeader" Property="Background" Value="{DynamicResource SecundaryGrayColor}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--Deaktivieren Des rowheader
<Style TargetType="{x:Type DataGridRowHeader}">
<Setter Property="Background" Value="Transparent"/>
</Style>-->
<!--Cellen Design-->
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="FontFamily" Value="sans-serif"/>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="#333333"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border x:Name="insideBorder" Background="Transparent" BorderThickness="0 2 0 1" BorderBrush="#dddddd">
<Border x:Name="BorderCell" BorderThickness="0"
CornerRadius="6"
Background="White"
Padding="8,5,0,5"
Margin="2">
<ContentPresenter/>
</Border>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="{DynamicResource PrimaryBlueColor}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
</DataGrid>
my itemtemplate of my ComboBox:
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Path=cmbIsChecked, Mode=TwoWay}" Width="20"/>
<TextBlock Text="{Binding Path=Spaltenname}" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
my "bischenanders" collection (sry for that bad name I will fix that in the future)
my outputColumns class:
public class OutputColumns
{
public string Spaltenname{ get; set; }
public bool IsChecked { get; set; }
public bool cmbIsChecked { get; set; }
}
}
thats the way I read the selected Items for the rows and for the Combobox rows
public List<OutputColumns> GetSelectedItems()
{
var selectedItems = new List<OutputColumns>();
foreach (OutputColumns item in View.bischenanders)
{
try
{
if (item.IsChecked)
{
selectedItems.Add(item);
}
}
catch
{
}
}
return selectedItems;
}
public List<OutputColumns> cmbGetSelectedItems()
{
var selectedItems = new List<OutputColumns>();
foreach (OutputColumns item in View.bischenanders)
{
try
{
if (item.cmbIsChecked)
{
selectedItems.Add(item);
}
}
catch
{
}
}
return selectedItems;
}
So that If this row is checked:
Picture
and in the combobox that 2 rows are checked:
Picture2
then I want that these 3 values are getting Combined
but when I check in one CombobBox every combobox in the DataGrid has the same checked Values
It looks like that every time I open a new ComboBox he getting the data from the class and then there will the programm find a version where it is checked, because ComboBoxs I already have open get there own checked values, only the new ones getting the checked one that are checked in the previous checkbox.
Thanks for help!
I want to define a style for the text box and within the style I want to bind to a property which the corresponding style applies to. Something like this:
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock Text="{Binding ????Bind to the textbox TEXT property????}">
</TextBlock>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Is this possible at all?
Here the full Window:
<Window x:Class="StyleBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:StyleBinding"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock Text="{Binding Text, RelativeSource={RelativeSource Self}}"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<TextBox HorizontalAlignment="Left" Height="34" Margin="235,140,0,0" TextWrapping="Wrap" IsEnabled="True"
Text="Just a simple text" VerticalAlignment="Top" Width="284">
</TextBox>
</Grid>
</Window>
You just have to use a RelativeSource binding to access the Text property of the TextBox.
<Setter Property="ToolTip" Value="{Binding Text, RelativeSource={RelativeSource Self}}"/>
In case you build a custom tool tip template in your style, you can do it like this.
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip>
<TextBlock Text="{Binding PlacementTarget.Text, RelativeSource={RelativeSource AncestorType={x:Type ToolTip}}}"/>
</ToolTip>
</Setter.Value>
</Setter>
</Style>
The PlacementTarget of the ToolTip is the TextBox here.
Here's a working example:
<Style BasedOn="{StaticResource {x:Type TextBox}}" TargetType="{x:Type TextBox}">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=Text}" />
</Style>
The key is to use a RelativeSource binding of Self.
There's no need to set a trigger on IsEnabled because a ToolTip will only display on an enabled control by default.
I'm using MaterialDesign and the Xceed IntegerUpDown control in a WPF project. I'm trying to display errors associated with the updown control as a tooltip when the mouse hovers over the control.
I've gotten this to work with TextBoxes and TextBlocks by using the following global style:
<Style TargetType="{x:Type TextBox}"
BasedOn="{StaticResource CustomizedMaterialDesignTextBox}" >
<Setter Property="Margin" Value="5"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}"
Background="{DynamicResource ValidationErrorBrush}">
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}"
DisplayMemberPath="ErrorContent"/>
</ToolTip>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
But when I tried to adapt this to the updown control as follows, no tooltip is displayed:
<Style TargetType="{x:Type xctk:IntegerUpDown}">
<Setter Property="Margin" Value="5"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}"
Background="{DynamicResource ValidationErrorBrush}">
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}"
DisplayMemberPath="ErrorContent"/>
</ToolTip>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
No error message about a failed binding or whatnot is displayed in the output window when the app is run in the VS 2017 debugger and an error condition is triggered.
Interestingly, a red border appears around the control when an error condition exists, even without the custom updown style.
You didn't show how exactly you're binding it but remember to 1) specify UpdateSourceTrigger and 2) actually hover over it ! Here's a MCVE showing that it actually works with no problem.
XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:xctk="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit"
xmlns:local="clr-namespace:WpfApp5"
x:Class="WpfApp5.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type xctk:IntegerUpDown}">
<Setter Property="Margin" Value="5"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}"
Background="{DynamicResource ValidationErrorBrush}">
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}"
DisplayMemberPath="ErrorContent"/>
</ToolTip>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Window.DataContext>
<local:SampleViewModel/>
</Window.DataContext>
<Grid>
<xctk:IntegerUpDown Text="{Binding MyInteger, UpdateSourceTrigger=PropertyChanged}"
FontSize="24"
Width="125"
Height="50"/>
</Grid>
<Border Grid.Row="1" Padding="15" Margin="15" BorderBrush="LightBlue" Background="AliceBlue" BorderThickness="1">
<ListBox ItemsSource="{Binding Configs}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Focusable" Value="False" />
<Setter Property="BorderThickness" Value="0" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<view:Config />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Border>
This is the code I've written in XAML. However, it doesn't appear to affect anything.
There are so many posts on SO with similar questions but all of their response are "use ListBox.ItemContainerStyle" which I've done :S Such as There is no ListBox.SelectionMode="None", is there another way to disable selection in a listbox? and WPF, XAML: How to style a ListBoxItem using binding on property of ListBox ItemsSource object?
What I would expect is that there is no background, no border and the item is not focusable.
What have I done wrong?
Redefine the ControlTemplate of your ListBoxItem. The sample code below uses a redish color just to make the point, but you can just replace it with Transparent:
<Window x:Class="WpfApplication235.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:WpfApplication235"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<x:Array x:Key="SampleData" Type="{x:Type sys:String}">
<sys:String>Item 1</sys:String>
<sys:String>Item 2</sys:String>
<sys:String>Item 3</sys:String>
<sys:String>Item 4</sys:String>
<sys:String>Item 5</sys:String>
</x:Array>
<Style x:Key="ListBoxItemStyle1" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<TextBlock Text="{Binding}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#1FFF0000"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ListBox x:Name="listBox" ItemsSource="{StaticResource SampleData}"
ItemContainerStyle="{StaticResource ListBoxItemStyle1}"
Height="150" Margin="0" Width="250"/>
</Grid>
and using a Transparent background, no focus, no highlighting, as required:
You can use style in resource like:
<Window.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="#D8D8D8"/>
<Setter Property="FontSize" Value="15"/>
<Setter Property="FontWeight" Value="400"/>
<Setter Property="Height" Value="30"/>
<!--and so on whatever you want...-->
</Style>
</Window.Resources>
And remove code like:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Focusable" Value="False" />
<Setter Property="BorderThickness" Value="0" />
</Style>
</ListBox.ItemContainerStyle>
And don't use any property in listBox which is used in style, other wise it will not behave which is described in style.
I have code (below) that should produce a styled context menu. Unfortunately the menu item also shows a "white" bit that shouldn't be there (see below). I have tried styling it out but it doesn't work. Any help would be appreciated
<Style TargetType="ContextMenu">
<Setter Property="Background" Value="{StaticResource backgroundDark}" />
<Setter Property="BorderBrush" Value="{StaticResource highlight}" />
<Style.Resources>
<Style TargetType="MenuItem">
<Setter Property="Foreground" Value="Black" />
<Setter Property="Background" Value="Transparent" />
<Style.Triggers>
<Trigger Property="IsHighlighted" Value="True">
<Setter Property="Foreground" Value="{StaticResource highlightLight}" />
</Trigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>
you will want to override the
StackPanel Margin of MenuItems
and then override with the same value the ItemsPanel
so basically you can just add 2 simple styles in addition to your style.
I have added a sample:
<Grid>
<Grid.Resources>
<ItemsPanelTemplate x:Key="GlobalMenuItemPanelTemplate">
<StackPanel Margin="-25,0,0,0" Background="White"/>
</ItemsPanelTemplate>
<Style TargetType="{x:Type ContextMenu}">
<Setter Property="ItemsPanel" Value="{StaticResource GlobalMenuItemPanelTemplate}"/>
</Style>
</Grid.Resources>
<Label Background="Bisque" Content="Right Click it" VerticalAlignment="Center" HorizontalAlignment="Center">
<Label.ContextMenu>
<ContextMenu>
<MenuItem Header="Menu item 1" />
<MenuItem Header="Menu item 2" />
<Separator />
<MenuItem Header="Menu item 3" />
</ContextMenu>
</Label.ContextMenu>
</Label>
</Grid>