Grid ColumnDefinition.Width in DataTemplate - wpf

In my project, I've made a control that inherits from Control. It is called DialogHeader and, as its name stands, is for displaying a header on modal, non-resizable dialogs. In truth, it binds by default to its parent Window. The control has a property called IconLocation, i.e. whether the image should be displayed on the left or right side of the control's label:
[Image] [Label] -- or -- [Label] [Image]
The template used with DialogHeader is basically the following:
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="COLN_Left" Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition x:Name="COLN_Right" Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Name="PART_Image" />
<Separator Grid.Column="1"
Visibility="Collapsed" Width="{TemplateBinding SpacerWidth}" />
<TextBlock Grid.Column="2" Name="PART_Text" />
</Grid>
<ControlTemplare.Triggers>
<Trigger Property="ImageLocation" Value="Right">
<Setter TargetName="PART_Image" Property="Grid.Column" Value="2" />
<Setter TargetName="PART_Text" Property="Grid.Column" Value="0" />
<!-- The following doesn't work! Help! -->
<Setter TargetName="COLN_Left" Property="Width" Value="*" />
<Setter TargetName="COLN_Right" Property="Width" Value="auto" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Simply put, when the ImageLocation property is set to Location.Right, the widths of COLN_Left and COLN_Right should be exchanged. So instead of [auto][auto][*], I should have [*][auto][auto].
How can I make this work from the ControlTemplate? If not, is there are way that doesn't involve using C# code?
Thank you in advance.

That part does work, it possibly is just not what you want i presume. Try to remove it and the result should be different.

Related

WPF Textblock Tooltip does not wrap

I am trying to create a tooltip that wraps automatically (and also has an advanced mode that takes normal content, but that's later). Anyway, I'm setting the content as a string and making the content just a textblock with wrapping. However I can't figure out why this isn't working. Here is the style I'm working on:
<Style x:Key="StHelpLinkBase" TargetType="{x:Type graphicElements:MyHelpLink}">
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Background" Value="{StaticResource BrHelpLinkBackground}" />
<Setter Property="Width" Value="12" />
<Setter Property="Height" Value="12" />
<Setter Property="Margin" Value="5" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type graphicElements:MyHelpLink}">
<Grid x:Name="templateRoot">
<Image Source="Images/Icon_16_Help.png" Stretch="UniformToFill" MaxHeight="16" MaxWidth="16"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
x:Name="PART_Image">
<Image.ToolTip>
<ToolTip Background="{TemplateBinding Background}" BorderThickness="0"
DataContext="{Binding DataContext, ElementName=PART_Image}"
TextElement.Foreground="{TemplateBinding Foreground}"
ContentTemplate="{StaticResource DtTooltipAdvanced}"
MaxWidth="150"
x:Name="PART_Tooltip">
<ContentPresenter />
</ToolTip>
</Image.ToolTip>
</Image>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here is the basic template referenced:
<DataTemplate x:Key="DtTooltipBasic">
<Grid>
<TextBlock Text="{Binding Content, RelativeSource={RelativeSource AncestorType=ToolTip}}"
TextWrapping="Wrap"
Foreground="White"
Margin="15"
FontFamily="Resources/#Artifakt Element"
FontSize="9pt" />
</Grid>
</DataTemplate>
And here is the usage (MyHelpLink inherits from ContentControl):
<graphicElements:MyHelpLink Content="This is some help text that is long and is just set as straight string in content but it should wrap I hope." />
I've tried setting the MaxWidth on the tooltip as I have it now, I've tried setting it on the Grid that is in the DataTemplate, and I've tried setting it on the textblock itself and all just cut off the text. I also tried setting the Width property of the textblock directly and same thing...
So why doesn't this wrap?
Ok well I still don't know why this didn't work but I ended up with another solution. Through some experimenting I found that if I put the textblock directly inside the control template instead of a data template it worked and wrapped correctly. However in order to switch it I couldn't use it that way.
So what I did was make two control templates; one with a wrapping textblock for generic content and one with ContentPresenter for non-string content. I then made the style with a trigger on the content type (I made a custom readonly dependency property in my class denoting to trigger the change if the content is anything except a string). The trigger changes the template from the wrapping textblock to the content presenter depending on the type of content set.
If anyone knows why it doesn't work inside a DataTemplate I would love to know and will mark as the answer...

Why is my Fluent Window title staying centered?

I'm using the latest version of Fluent.Ribbon. I've been doing some styling, most of which requires completely replacing the Styles and ControlTemplates, but I've hit a snag. The title of my app is centered in the header bar and I can't get it to move to the left.
My visual tree looks like this:
MainWindow
Grid
Adorner
Grid
DockPanel
PART_Icon
PART_RibbonTitleBar
Grid
PART_HeaderHolder [ContentPresenter]
TextBlock
PART_ItemsContainer
PART_QuickAccessToolbarHolder
I copied the current version of the Fluent:RibbonTitleBar ControlTemplate and Style into my override xaml for modification, but nothing I do makes any difference (yes it is loading my overriding styles.)
When I use the inspector tool in the app, the only elements I can highlight are the innermost TextBlock, which fits the text exactly with no stretch, and the DockPanel several levels above, which stretches the full window width. In the original window ControlTemplate, which you can see here, The RibbonTitleBar is the last element of the DockPanel which has LastChildFill set. The RibbonTitleBar does have a RenderSize of the full width, but then the Grid below it has a RenderSize of 0,0. Then PART_HeaderHolder inside that has a RenderSize that exactly covers the title text.
It doesn't seem to matter if I set HorizontalAlignment on various elements to Left or Stretch. I also tried changing the innermost Grid to other container types such as DockPanel and StackPanel. Nothing changes anything about the layout.
Here's my style overrides for the RibbonTitleBar. The only change I've made is that I moved the QuickAccessToolbar to the end and permanently collapsed it (if I try deleting it, the app crashes looking for it) and I tried defining some columns on the inner Grid to no avail.
<Style TargetType="{x:Type Fluent:RibbonTitleBar}">
<Setter Property="Template"
Value="{DynamicResource RibbonTitleBarControlOverride}" />
<Setter Property="Focusable"
Value="False" />
<Setter Property="VerticalAlignment"
Value="Top" />
<Setter Property="HorizontalAlignment"
Value="Stretch" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Margin="-2,0"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Text="{Binding}"
TextWrapping="NoWrap"
TextTrimming="CharacterEllipsis" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="RibbonTitleBarControlOverride"
TargetType="{x:Type Fluent:RibbonTitleBar}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0" x:Name="PART_HeaderHolder"
HorizontalAlignment="Left"
ContentSource="Header"
IsHitTestVisible="False" />
<Fluent:RibbonContextualGroupsContainer Grid.Column="1" x:Name="PART_ItemsContainer"
IsItemsHost="True" />
<ContentPresenter x:Name="PART_QuickAccessToolbarHolder"
ContentSource="QuickAccessToolBar" Visibility="Collapsed" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsCollapsed"
Value="True">
<Setter Property="Visibility"
Value="Collapsed"
TargetName="PART_ItemsContainer" />
</Trigger>
<Trigger Property="HideContextTabs"
Value="True">
<Setter Property="Visibility"
Value="Collapsed"
TargetName="PART_ItemsContainer" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

How To Find ScrollViewer Inside of WPF ContentControl?

WPF 4.5 / C#
I've got an app where I have several WPF Windows each utilizing this custom content control. I use it in the XAML like this:
<ContentControl Name="myControl" Style="{StaticResource ReservedSpaceScrollBar}"
In the code behind, I need to be able to access the ScrollViewer inside, so I can call .ScrollToTop()
I've tried this, but it doesn't work:
((ScrollViewer)this.myControl.FindName("Scroll")).ScrollToTop();
...but .FindName doesn't find the ScrollViewer. What am I doing wrong? How make this work?
The XAML for the Style is below...
<Style TargetType="{x:Type ContentControl}" x:Key="ReservedSpaceScrollBar">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<ScrollViewer PanningMode="Both" VerticalScrollBarVisibility="Auto" x:Name="Scroll" FocusVisualStyle="{x:Null}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter />
<Border Width="{x:Static SystemParameters.VerticalScrollBarWidth}" x:Name="Placeholder" Grid.Column="1" />
</Grid>
</ScrollViewer>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding ComputedVerticalScrollBarVisibility, ElementName=Scroll}" Value="Visible">
<Setter TargetName="Placeholder" Property="Visibility" Value="Collapsed" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Look into the VisualTreeHelper
Using that class you can look into children of elements; for example:
var childCount = VisualTreeHelper.GetChildrenCount(this.myControl);
for (int i = 0; i < childCount; i++)
{
var child = VisualTreeHelper.GetChild(this.myControl, i);
if (child.GetValue(NameProperty).ToString() == "Scroll")
{
((ScrollViewer)child).ScrollToTop();
}
}

WPF Style All Controls in One Instance UserControl

Is it possible to have say one UserControl with couple of Controls on it, but when reusing the UserControl to only apply on some of the a style or template for all those controls?
For example local:UserControl1 Grid.Column="1"'s Controls have a style/template applied?
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<local:UserControl1 />
<local:UserControl1 Grid.Column="1" />
</Grid>
You can not selectively apply a style based on some condition of the styled control without implementing an according behavior. Still, you can achieve the same thing with style triggers. You can set the template of the control in a style trigger, so applying a certain template based on some condition of the templated control is possible with out of the box features. In the example the background is set selectively:
<Grid>
<Grid.Resources>
<!-- Defining the TargetType but no x:Key will apply the style
to ALL children of this grid of the specified type -->
<Style TargetType="{x:Type local:UserControl1}">
<Style.Triggers>
<Trigger Property="Grid.Column" Value="1">
<!-- All setters here get applied only when
trigger condition is met -->
<Setter Property="Background" Value="Blue" />
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<local:UserControl1 />
<local:UserControl1 Grid.Column="1" />
</Grid>

WPF, Font style for multiple controls

ok, I might be missing something really easy, But I want to use the same Font family, Font Size, and color for multiple controls.
Is there a way to create one style for this and apply it different controls?
Sorry if this has been asked before.
Thanks
Are the controls all in the same container? For example, in the same Window or StackPanel? If so, you can make set those properties on the parent container and they'll apply to any children. For example:
<StackPanel TextBlock.FontFamily="Comic Sans"
TextBlock.FontSize="14"
TextBlock.Foreground="Purple">
<TextBlock Text="Yeah, baby! I love me some Comic Sans!" />
<Button Content="Me too!" />
</StackPanel>
If you want to standardize the font across your entire app, you can use an implict style in your App.xaml file, like this:
<Style TargetType="TextBlock">
<Setter Property="FontFamily" Value="Comic Sans" />
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="Purple" />
</Style>
I wanted to add this for the newbies (like myself).
If you want to set a property for multiple items within a container:
You can set a "style" within the "resources" for a control like so:
<Grid>
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="22"/>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="hello text" />
<TextBlock Grid.Row="1" Text="hello text1" />
<TextBlock Grid.Row="2" Text="hello text2" />
</Grid>

Resources