How to wrap text in GroupBox header? - c#

How to wrap text in GroupBox header? This code doesn't work.
<GroupBox>
<GroupBox.Header>
<TextBlock Text="qwertyuiopasdfghjklqwertyuiopasdfghjkl" TextWrapping="Wrap"/>
</GroupBox.Header>

In-order to get the text content wrapped,You have to specify the width, other wise the with of the textblock automatically set to the length of content in the text block.
<TextBlock Width="150" Text="qwertyuiopasdfghjklqwertyuiopasdfghjkl" TextWrapping="Wrap"/>

While the solution to set the header's width by explicitly specifying the value or binding with another element works perfectly, delving into the default style of GroupBox, I found that making small modifications into the style will solve this issue.
<BorderGapMaskConverter x:Key="BorderGapMaskConverter"/>
<Style TargetType="{x:Type GroupBox}">
<Setter Property="BorderBrush" Value="#D5DFE5"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupBox}">
<Grid SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6"/>
<!-- <ColumnDefinition Width="Auto"/> is removed because its Width="Auto" is problematic. -->
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="6"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="6"/>
</Grid.RowDefinitions>
<!-- The value of Grid.ColumnSpan is changed from 4 to 3. -->
<Border Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="1" Grid.RowSpan="3"
BorderBrush="Transparent"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
CornerRadius="4"/>
<!-- The value of Grid.ColumnSpan is changed from 4 to 3. -->
<Border Grid.ColumnSpan="3" Grid.Row="1" Grid.RowSpan="3"
BorderBrush="White"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4">
<Border.OpacityMask>
<MultiBinding Converter="{StaticResource BorderGapMaskConverter}"
ConverterParameter="7">
<Binding ElementName="Header" Path="ActualWidth"/>
<Binding RelativeSource="{RelativeSource Self}" Path="ActualWidth"/>
<Binding RelativeSource="{RelativeSource Self}" Path="ActualHeight"/>
</MultiBinding>
</Border.OpacityMask>
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="3">
<Border BorderBrush="White"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="2"/>
</Border>
</Border>
<!-- HorizontalAlignment="Left" is added to adjust the surrounding line. -->
<Border x:Name="Header"
Grid.Column="1" Grid.Row="0" Grid.RowSpan="2"
HorizontalAlignment="Left"
Padding="3,1,3,0">
<ContentPresenter ContentSource="Header"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<!-- Grid.ColumnSpan="2" is removed because it is no longer necessary. -->
<ContentPresenter Grid.Column="1" Grid.Row="2"
Margin="{TemplateBinding Padding}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The root cause of this issue is Width="Auto" of the 2nd ColumnDefinition of Grid. So remove the ColumnDefinition so that the header's Border is assigned to the original 3rd ColumnDefinition. Then add HorizontalAlignment="Left" to the header's Border. Some trivial edits of ColumnSpan. That's it.
This modified style lets WPF's layout engine determine the header's width automatically depending on actual width of GroupBox. No need to care about the width each time. As far as I know, there is no noticeable degradation from the default one.

Related

How to change the toggle of a TreeView

I have a treeview working, it has a toggle button that can expand it's contents. When I do, each column is too far to the right from where I want it due to the toggle expansion width. I'd like to override that behaviour but I don't know how, I understand it's something to do with defining the control template of the TreeView?
This is my code
c#
Class MyList
{
double someDouble;
double somestring;
souble anotherString;
bool thisOnesABool;
}
Class MyContainer
{
string headerText1;
string headerText2;
List<MyList> SomeList;
}
List<MyContainer> SomeContainerInCodeBehind = new List<MyContainer>();
WPF
<UserControl.Resources>
<DataTemplate x:Key="level2">
<Grid>
//the content of 'MyList'
</Grid>
</DataTemplate>
<HierarchicalDataTemplate x:Key="level1"
ItemsSource="{Binding SomeListWithinContainer}"
ItemTemplate="{StaticResource level2}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding HeaderText}" />
<TextBox Grid.Column="1" Text="{Binding MoreHeaderText}" />
</Grid>
</HierarchicalDataTemplate>
</UserControl.Resources>
<Grid>
<TreeView Name="TheTreeView"
Grid.Row="1"
ItemTemplate="{StaticResource level1}"
ItemsSource="{Binding SomeContainerInCodeBehind}">
</TreeView>
</Grid>
In order to change the position of the expander (or expanded child items), you have to override the ControlTemplate of the TreeViewItem.
The following Style is taken from Microsoft Docs: TreeView Styles and Templates and shortened to show the relevant code. Visit the link to get the full code.
<Style x:Key="{x:Type TreeViewItem}"
TargetType="{x:Type TreeViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="19"
Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
...
</VisualStateManager.VisualStateGroups>
<!-- Use Margin to modify the position of the "Expander" ToggleButton -->
<ToggleButton x:Name="Expander"
Style="{StaticResource ExpandCollapseToggleStyle}"
ClickMode="Press"
IsChecked="{Binding IsExpanded,
RelativeSource={RelativeSource TemplatedParent}}"/>
<Border x:Name="Bd"
Grid.Column="1"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<!-- Modify e.g. Margin to change the position of the Header (parent item) -->
<ContentPresenter x:Name="PART_Header"
ContentSource="Header"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</Border>
<!-- Modify e.g. using Margin to reposition the expanded child items -->
<ItemsPresenter x:Name="ItemsHost"
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="2"
Visibility="Collapsed" />
</Grid>
...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

How to 'call' my styled button(xaml) from code behind

I have a button in XAML which i styled the way I need it. This is XAML code of that button:
<Button x:Name="btnAddNewItem"
Grid.Column="0" Grid.Row="0"
FontSize="15"
BorderThickness="1.5"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Foreground="White"
Background="White"
BorderBrush="#0091EA" Margin="5,0,0,0" Height="90" Width="90">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate>
</Button.Template>
And I would like to achieve something like this, so I would like to delete xaml button, and create same button programatically when its needed, with same style and everything like I did in xaml, example how I would like to create it:
private void AddSubmenuButton(string name)
{
MyButton button = new MyButton();
button.ButtonText = name;
}
Is this possible and if so: how?
P.S I tried classic way, like this:
Button a = new Button();
a.BorderThickness = new Thickness(1);
a.Foreground = new SolidColorBrush(Colors.Black);
a.BorderBrush = mySolidColorBrush;
a.Content = "Button1";
a.Width = 90;
a.Height = 90;
But I get this:
It's possible to notice that thickness it not 1 at all, it has some weird value
and I don't know how to change it.. So that is reason why I created button in xaml which looks much more nice and I want to call it/create it from code behind.
EDIT:
#mm8 THANK YOU A LOT!
THAT'S IT!
This is awesome mate, but what about that If I would like to place icon + text in my button, I would ussualy
add something like this and its fine for me:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="80*">
<RowDefinition Height="20*"/>
</Grid.RowDefinitions>
<Image Source="/MyProject.Wpf;component/Icons/customer-icon.png" Margin="10" Grid.Row="0" Width="Auto"/>
<TextBlock Foreground="Black" Margin="0,0,0,3" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" >Izlaz</TextBlock>
</Grid>
as you can see I would add Grid to my button and it would look like this:
<Button x:Name="btnAddNewItem"
Grid.Column="0" Grid.Row="0"
FontSize="15"
ToolTip="Podaci"
BorderThickness="1.5"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Foreground="White"
Background="White"
BorderBrush="#0091EA" Margin="5,0,0,0" Height="90" Width="90">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate>
</Button.Template>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="80*">
<RowDefinition Height="20*"/>
</Grid.RowDefinitions>
<Image Source="/MyProject.Wpf;component/Icons/customer-icon.png" Margin="10" Grid.Row="0" Width="Auto"/>
<TextBlock Foreground="Black" Margin="0,0,0,3" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" >Izlaz</TextBlock>
</Grid>
</Button>
So could I somehow achieve this (image + text IN MY button ) also to create it programatically.
Define a style in your App.xaml:
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style x:Key="theStyle" TargetType="Button">
<Setter Property="FontSize" Value="15" />
<Setter Property="BorderThickness" Value="1.5" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<!-- and so on for each property...-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>
You can then apply this style to any Button in your application, either in XAML:
<Button x:Name="btnAddNewItem" Style="{StaticResource myStyle}"/>
...or programmatically:
Button button = new Button();
button.Style = Application.Current.Resources["myStyle"] as Style;

Set Textbox Focus within a Control Template

I have a control template that defines a custom floating text box.
It consists of a label, a border that serves as the visual boundary for the text box, and a text box inside that border.
The border of the text box itself is made invisible.
My problem is this: when the custom control is "tabbed" to in the UI, the control gets KeyboardFocus, but the Textbox itself does not. This causes the blinking cursor not to show.
I need to know how to pass focus to the Textbox contained within the border, named DisplayText, from a trigger in the control template.
I tried using the FocusManager to set DisplayText to be the focused element, but that didn’t work.
Any ideas, thoughts or advice would be much appreciated. If you need any more information, please let me know.
Control Template:
<Grid SnapsToDevicePixels="True"
UseLayoutRounding="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label x:Name="floatingLabel"
Template="{DynamicResource LabelControlTemplate1}"
Content="{Binding LabelText, RelativeSource={RelativeSource Mode=TemplatedParent}}"
IsHitTestVisible="False"
Panel.ZIndex="2"
Background="White"
Height="15"
VerticalContentAlignment="Center"
Padding="3,0,3,0"
HorizontalAlignment="Left"
FontFamily="Segoe UI"
FontSize="{Binding LabelFontSize, RelativeSource={RelativeSource TemplatedParent}}"
Foreground="{DynamicResource FloatingLabelTextBox.Label.Foreground}"
VerticalAlignment="Center">
<Label.Tag>
<sys:Double>0.0</sys:Double>
</Label.Tag>
<Label.Margin>
<MultiBinding Converter="{StaticResource floatingLabelMarginConverter}">
<Binding Path="Tag"
RelativeSource="{RelativeSource Self}" />
<Binding ElementName="Border"
Path="ActualHeight" />
</MultiBinding>
</Label.Margin>
</Label>
<Border x:Name="Border"
Height="{Binding TextBoxHeight, RelativeSource={RelativeSource TemplatedParent}}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
CornerRadius="3"
SnapsToDevicePixels="True"
Panel.ZIndex="0"
VerticalAlignment="Bottom">
<Grid x:Name="GridContainer" Width="{Binding ElementName=Border, Path=ActualWidth}" Margin="10,0,0,0">
<TextBox x:Name="DisplayText"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=FormattedPhoneNumber, StringFormat={}{0:(###)###-####}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}"
Width="{Binding ElementName=Border, Path=ActualWidth}">
<TextBox.Template>
<ControlTemplate TargetType="{x:Type TextBox}">
<ScrollViewer x:Name="PART_ContentHost"
HorizontalAlignment="Stretch"
Margin="{TemplateBinding Padding}"
Uid="ScrollViewer_1"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>
</TextBox.Template>
</TextBox>
</Grid>
</Border>
</Grid>
Trigger:
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=DisplayText}" />
</Trigger>
Try adding Focusable="False" to the Label.
I tried to copy your XAML into a Window and run it, but there's obviously a bunch of other stuff that I would need in order to get it to work.

Is there any "line with text" control in WPF?

I just need to separate two grous of buttons inside StackPanel with something like:
---------Another Buttons--------
but I need a solid line, note --
I made a custom control for this.
The code for the Generic.xaml
<Style TargetType="{x:Type local:LineControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:LineControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Separator Grid.Column="0" VerticalAlignment="Center"></Separator>
<ContentPresenter Grid.Column="1" Content="{TemplateBinding Content}" VerticalAlignment="Center"></ContentPresenter>
<Separator Grid.Column="2" VerticalAlignment="Center"></Separator>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
The C# code:
public class LineControl : ContentControl
{
static LineControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(LineControl), new FrameworkPropertyMetadata(typeof(LineControl)));
}
}
And you use it like this
<local:LineControl>
<TextBlock>test</TextBlock>
</local:LineControl>
The TextBlock can be any control. You can even put a StackPanel with buttons in it if you want.
<StackPanel Orientation="Horizontal">
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
</StackPanel>
try this

Ribbon with templates causes transparent background

I have finally managed to template my ribbon and adding everything with databinding.
However I have a very ugly "dropdownmenu" which background have become transparent (The shadowing remains though!)
1st of all what is this "dropdownmenu" called? Lastly which properties shall I edit for providing a proper background to this "dropdownmenu"?
Best Regards!
That menu is a drop-down menu of a collapsed group. Collapsed group is a combination of RibbonToggleButton + Popup. In template, the Popup looks like this:
<Popup x:Name="PART_Popup"
AllowsTransparency="true"
Placement="Bottom"
PlacementTarget="{Binding ElementName=PART_ToggleButton}"
IsOpen="{Binding Path=IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"
Focusable="false"
PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}">
<classic:SystemDropShadowChrome Name="Shdw"
Color="Transparent"
SnapsToDevicePixels="true"
CornerRadius="2"
Focusable="True"
FocusVisualStyle="{x:Null}"
controls:KeyTipService.IsKeyTipScope="True"
RenderOptions.ClearTypeHint="Enabled"
>
<Grid Name="PopupGrid" Height="{TemplateBinding ActualHeight}" Margin="0,1.5,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" MinHeight="16" />
</Grid.RowDefinitions>
<Border Name="PopupBorder" Grid.RowSpan="2"
Background="{TemplateBinding Background}"
BorderBrush="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Ribbon.BorderBrush}"
BorderThickness="1"/>
<Border Name="PART_HotBackground"
Background="{TemplateBinding MouseOverBackground}"
BorderBrush="{TemplateBinding MouseOverBorderBrush}"
Opacity="0"
Grid.RowSpan="2"
CornerRadius="2"
BorderThickness="1"
SnapsToDevicePixels="True"/>
<Border Margin="2,3.5,2,0" Padding="3,0,3,0" x:Name="PART_RibbonControlsHostBorder">
<Grid>
<ItemsPresenter Name="ItemsPresenter" KeyboardNavigation.TabNavigation="Cycle"
KeyboardNavigation.DirectionalNavigation="Cycle"
SnapsToDevicePixels="True"
Grid.IsSharedSizeScope="true"/>
<ContentControl Name="TemplateContentControl" Visibility="Collapsed" Focusable="False"/>
</Grid>
</Border>
<Grid Margin="2,0,2,1" Grid.Row="1">
<ContentPresenter Name="PART_Header"
TextElement.Foreground="{StaticResource Ë}"
ContentSource="Header"
Margin="2,0,2,0"
MaxHeight="15"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Grid>
</classic:SystemDropShadowChrome>
</Popup>
As you can see, the Background is inherited from RibbonGroup.
So, you have few variants to fix it:
Set the Background property for your RibbonGroup that is not transparent
Retemplate

Categories

Resources