Mahapps's DropDownButton customize appearence - c#

I am using DropDownButton control of Mahapps.Metro components pack.
I want to highlight the whole line in ContextMenu (this is a part of this control).
XAML
<controls:DropDownButton x:Name="ddbPlaylist" Grid.Column="1" BorderThickness="0" ArrowBrush="{x:Null}" ItemsSource="{Binding PlaylistVM}"
HorizontalContentAlignment="Stretch" VerticalContentAlignment="Bottom" Grid.Row="0">
<controls:DropDownButton.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</controls:DropDownButton.ItemContainerStyle>
<controls:DropDownButton.Content>
<TextBlock Text="{Binding Title}" TextTrimming="CharacterEllipsis" Style="{StaticResource DetailsTextStyle}" VerticalAlignment="Bottom"/>
</controls:DropDownButton.Content>
</controls:DropDownButton>
As the MenuItems contains left and the right margin, reserved in order to show icon and glyph. I have found a solution for ContextMenu System.Windows.Controls.MenuItem without icon area but can not understand how to apply it in my case. Becouse ContextMenu lies in very depths of DropDownButton template, i ca not find a way to change it's style.

Related

Horizontal alignment in control seems to be ignored on all but the last item

I have a custom radio button based on togglebutton:
<Style TargetType="{x:Type local:ToolbarRadioButton}" BasedOn="{StaticResource {x:Type ToggleButton}}">
<Setter Property="Width" Value="60"/>
<Setter Property="Height" Value="60"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Vertical">
<iconPacks:PackIconModern Kind="{Binding TbIcon, RelativeSource={RelativeSource AncestorType=RadioButton}}"
Height="30" Width="35" HorizontalAlignment="Center"/>
<TextBlock Text="{Binding TbText, RelativeSource={RelativeSource AncestorType=RadioButton}}" FontSize="12"
HorizontalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
I use this control to create four toggle/radio buttons. I've horizontal centered the items in datatemplate, but I end up with this:
Forecast and its icon seem to be centered, but the others are partially left-aligned. They all use the same control so shouldn't they all be centered?
EDITS FOR CLARITY:
It doesn't matter which order I put them in, Forecast is always the one that's aligned correctly.
There is no whitespace in the text nor is there whitespace in the images and all images are sized according to the control defined above. Here's the implementation portion in case it's useful, though they're all the exact same:
<StackPanel Orientation="Horizontal" Grid.Column="0" Grid.Row="0">
<customs:ToolbarRadioButton TbText="Day" TbIcon="CalendarDay" GroupName="calViewType" x:Name="dayOnOff"/>
<customs:ToolbarRadioButton TbText="Week" TbIcon="CalendarWeek" GroupName="calViewType" x:Name="weekOnOff"/>
<customs:ToolbarRadioButton TbText="Month" TbIcon="CalendarMonth" GroupName="calViewType" x:Name="monthOnOff" IsChecked="True"/>
<customs:ToolbarRadioButton TbText="Forecast" TbIcon="PeopleMultiple" GroupName="calViewType" x:Name="forecastOnOff"/>
</StackPanel>
For future readers: I figured out the answer by digging into the documentation on Button. There is a property on buttons called HorizontalContentAlignment (and vertical, of course) that apparently needs to be set to align the visual content. You can't set the HorizontalAlignment property of the item that is the content explicitly; apparently, the button wants to do that for you.

Listbox Vertical Gap between Items (Remove??)

My listboxes are data driven from Lists of objects with databinding using a DataTemplate eg:
<ListBox x:Name="TheMainListBox"
ScrollViewer.IsVerticalRailEnabled="True"
ScrollViewer.IsHorizontalRailEnabled="False"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Height="540"
ItemsSource="{Binding}"
Width="Auto"
Margin="0"
Padding="0"
Background="Yellow"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto"
SelectionChanged="TheMainListBox_SelectionChanged"
DoubleTapped="TheMainListBox_DoubleTapped"
>
The template:
<ListBox.ItemTemplate>
<DataTemplate>
<Grid or Stackpanel Background="Blue"
Padding="0"
BorderBrush="Black"
BorderThickness="1"
Margin="0"
>
.... Binding Textboxes/blocks
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
I end up with a yellow container, the ListBox, .. with blue rectangles inside, the ListBox items but there is a vertical gap between them. I can set a negative vertical-top margin but that is cruddy and doesn't work for the top item. How can I reduce the vertical gap between items to zero.
If a create a ListBox with static items, each in a ListBoxItem container, eg:
<ListBoxItem BorderThickness="1" Width="100" Height="50"
BorderBrush="Black" Background="Red"/>
It all works as required.
So how can I get rid of the vertical spacing between items with the ItemTemplate/DataBinding?
This is mission critical, thx in advance.
I don't have time to load up a proj to test but you should be able to just kill the margin/padding that could cause it. So add;
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0"/>
</Style>
</ListBox.ItemContainerStyle>
I haven't thought a lot of why this could be happening, haven't digged into styles ither, and my answer doesn't look nice, but try Margin="0,-2,0,-2"
<DataTemplate>
<Grid or Stackpanel Background="Blue"
Padding="0"
BorderBrush="Black"
BorderThickness="1"
Margin="0,-2,0,-2"
>
.... Binding Textboxes/blocks
</Grid>
</DataTemplate>
properly setting the height of the ListBoxItem will solve the issue. Here is the code snippet
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Height" Value="Your_Desired_Height"/>
</Style>
</ListBox.ItemContainerStyle>
For listbox please use Height property and for listview use MinHeight property. Replace the required height value in the Your_Desired_Height placeholder.

Border fail to size to Textblock

In an attempt to go around the problem described in this other question: Segoe UI Symbol smiley is sometimes colorful, sometimes not (WP8.1 + XAML), I tried the following: wrapping my Textblock with a Border element with rounded-corners (high CornerRadius). This way I can change the background color of the border and it looks pretty much as if the smiley had a background color itself... almost.
There is still a small gotcha I cannot wrap my head around: the height of the TextBlock seems to be out of my control. The "Segoe UI Symbol" (smiley) I want to display acts as if it had some kind of padding that prevented the border to fit the icon exactly. I end up with some kind of oval shape around my round smiley... not quite what I had in mind.
I stripped the XAML to its bare essence and played with it in a new blank app (just paste this in a new app, you should see exactly the screenshot below):
<Grid>
<Border Background="Red" Grid.Column="0"
CornerRadius="50" BorderThickness="0"
HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="😠"
FontFamily="Segoe UI Symbol" FontSize="50"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</Grid>
This gives you that:
Any idea what I can tweak there?
The problem is that the text (emoticon) has not the same height and width. You can do a custom fix by applying a custom style to the textbox and change its padding until you achieve the result you want. It's not a dynamic solution but if the size of the icon is standard this solution i think will work.
First of all create a new style:
<phone:PhoneApplicationPage.Resources>
<Style x:Key="CustomTextBlockStyle" TargetType="TextBlock">
<Setter Property="Padding" Value="10,0,10,3"/>
</Style>
</phone:PhoneApplicationPage.Resources>
Then apply it to the TextBlock
<Grid>
<Border Background="Red" Grid.Column="0"
CornerRadius="50" BorderThickness="0"
HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="😠"
FontFamily="Segoe UI Symbol" FontSize="50"
HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource CustomTextBlockStyle}" />
</Border>
</Grid>
The result:
If you want something like this:
Try to play around with padding and margin too
<Style x:Key="CustomTextBlockStyle" TargetType="TextBlock">
<Setter Property="Margin" Value="-2,-13,-2,-9"/>
<Setter Property="Padding" Value="0,0,0,0"/>
</Style>

Getting a separator to fill up the remaining space

I'm sure this is dead simple, but I can't seem to figure it out.
I have a ListBox to display items, and these are displayed with a DataTemplate. I now want to group these items, so have added a group based on the manufacturer property. This is done in code behind.
ICollectionView view = CollectionViewSource.GetDefaultView(Items);
PropertyGroupDescription groups = new PropertyGroupDescription("Manufacturer");
view.GroupDescriptions.Add(groups);
I wanted to have each group in an expander, so they can be hidden. I have got this working by looking at GroupTemplates at MSDN This involves, having an expander, textblock and then a seperator to rule off the extra space like in Windows Vista/7 Groups. As Below.
The problem I am having is I cannot get the separator to fill up the remaining space correctly. If I use a MinWidth value, all my expanders have the same width. If I use the {binding ActualWidth, ElementName=MyListBox}, then the separator is too wide, as its as wide as the control that contains it. So it sets the scroll bars to be visible, (see screenshot below). If i leave width blank, then the seperator is not drawn at all.
My gut feeling is the stackpanel should have expanded the seperator to use the remaining space but it didn't. So i tried a DockPanel as in the XamlCode below, yet this also fails. I have a few other problems with getting controls to fill up the remaining space, by using a suitable width so if you can help me resolve this, it would be great.
My current WPF Xaml Markup. You will need to add elements to get this to display something.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel x:Name="myStackPanel">
<ListBox x:Name="MyListBox">
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True">
<Expander.Header>
<DockPanel HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Height="Auto"
Width="{Binding ActualWidth, ElementName=MyListBox}"
Margin="10">
<TextBlock DockPanel.Dock="Left" Margin="0" FontSize="14" FontWeight="Bold" Foreground="Black" Text="{Binding Path=Name}"/>
<Separator DockPanel.Dock="Right" Margin="4,0,4,0"></Separator>
</DockPanel>
</Expander.Header>
<ItemsPresenter Margin="5,0,0,0" />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<!-- Data Template Here -->
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</ScrollViewer>
It is in fact not trivial, the control template of the Expander consists of a ToggleButton as the Header and a ContentPresenter for the content. The problem is that the ToggleButton itself has a special style & template which contains the arrow that has the alignment hard-coded into it, the default one looks something like this:
<Style x:Key="ExpanderDownHeaderStyle"
TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Padding="{TemplateBinding Padding}">
<Grid Background="Transparent"
SnapsToDevicePixels="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="19"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- ... -->
<!-- The HorizontalAlignment needs to be set to stretch here -->
<ContentPresenter Grid.Column="1"
Margin="4,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
SnapsToDevicePixels="True"
RecognizesAccessKey="True"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<!-- ... -->
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
To get your style to work you need to modify the default Expander template (get default templates on MSDN - Default WPF Themes link). Not nice but you don't really have much of a choice.

How can I show grouping in a WPF Data Grid with multiple levels?

I am relatively new to WPF, so I understand about Styles and setters, but I am having trouble on this one.
I am using a WPF Data Grid and need to show multiple levels of grouping. I would like the 2nd and 3rd group levels to be more indented than the top level.
The following code will show group levels, but it shows them one right on top of the other and makes the fact that they are nested group levels impossible to tell.
<Style x:Key="GroupHeaderStyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True">
<Expander.Header>
<TextBlock Text="{Binding Path=Name}"/>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
How can I get the group header to indent based on level?
In case anyone from the future comes across this. I was able to have nested groups and style them so they weren't stacked on top of each other by doing the following.
Add property to the CollectionViewSource:
<Window.Resources>
<CollectionViewSource x:Key="cvs" Source="{Binding TestData}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="TopProperty"/>
<PropertyGroupDescription PropertyName="SubProperty"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
Then in the DataGrid XAML you have to specify 2 GroupStyles, and the second one will be used for the nested group. I added margins to the StackPanel of the second group to push the text to the right to make it seem like it was in the appropriate column.
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<StackPanel>
<Border Background="#FF959595" BorderBrush="#FF727272" BorderThickness="0,0,0,1" Margin="5,0,0,0">
<StackPanel Height="23" Orientation="Horizontal" Margin="3,0,0,0" Background="#FFE6E6E6">
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}" Margin="5,0,0,0" Width="100" VerticalAlignment="Center"/>
</StackPanel>
</Border>
<ItemsPresenter />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel>
<Border Background="#FF959595" BorderBrush="#FF727272" BorderThickness="0,0,0,1" Margin="5,0,0,0">
<StackPanel Height="23" Orientation="Horizontal" Margin="3,0,0,0" Background="#FFF3F3F3">
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}" Margin="55,0,0,0" Width="100" VerticalAlignment="Center"/>
</StackPanel>
</Border>
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</DataGrid.GroupStyle>
I was able to find more on this here:
https://msdn.microsoft.com/en-us/library/ff407126%28v=vs.110%29.aspx
I had the same problem and found an imperfect workaround. If you add a margin on the left of your ItemsPresenter, every level is indented as you'd expect. Unfortunately, the column headers are no longer aligned with the content columns. I'm still looking for a fix for that...
As far as I know (or the last time I checked), the WPF Datagrid does not support hierarchical grouping.
The closest I could find was this.
This is why we went with the Xceed DataGrid in our app. Unfortunately, it's not free so that might not be suitable for you.
I already make use of ICollectionView and PropertyGroupDescription in order to add grouping, however, you must still use XAML to describe how the grouping will be displayed, otherwise you will not get any UI indication of grouping.
I am interested in how to setup the XAML so that I can represent multiple levels of grouping, preferably with some kind of indentation per group level or something like that....
This tutorial goes in the right direction: Multi Grouping in DataGrid
But sadly 'PagedCollectionView' is Silverlight.

Categories

Resources