How to implement DateTimeAxis control template in System.Windows.Controls.DataVisualization.Toolkit - wpf

I want to override the default template but i have trouble implementing it.
I tried this:
<charting:Chart Title="{Binding Title}" Name="chChart" LegendStyle="{StaticResource LegendStyle1}">
<charting:Chart.Axes>
<charting:DateTimeAxis
x:Name="Abcisa"
Orientation="X"
ShowGridLines="True"
Title="{Binding Abscissa}">
<charting:DateTimeAxis.Template>
<ControlTemplate TargetType="{x:Type charting:DateTimeAxis}">
<Grid x:Name="AxisGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!--generate content for x axis-->
<datavis:Title x:Name="AxisTitle" Grid.Row="1" />
</Grid>
</ControlTemplate>
</charting:DateTimeAxis.Template>
</charting:Chart>
But i got this for visual tree:
What should i do to create template for DateTimeAxis control?

You should set the Style property of the Title to the TitleStyle of the Axis. This is what the default template looks like:
<ControlTemplate TargetType="charting:DateTimeAxis">
<Grid x:Name="AxisGrid" Background="{TemplateBinding Background}">
<datavis:Title x:Name="AxisTitle" Style="{TemplateBinding TitleStyle}" />
</Grid>
</ControlTemplate>
But you also need to add some data series to the chart for the axis to show up. Please refer to the following article for more information about this and an example: https://www.codeproject.com/Articles/196502/WPF-Toolkit-Charting-Controls-Line-Bar-Area-Pie-Co

Related

WPF ContentPresenter overrides othe Controls on the same level

As in my last question I'm about to re-create an expander + it's toggle button.
Expander Template:
<ControlTemplate TargetType="Expander">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="15"/>
</Grid.RowDefinitions>
<ContentPresenter x:Name="ContentPresenter" Grid.Row="0"/>
<ToggleButton Grid.Row="1" >
....
</ToggleButton>
</Grid>
Now when I use this Custom Control in my Main View and add a Control (e.g. a Button):
<custom:FullWidthExpander Width="200" HeaderBackground="Gray">
<Button />
</custom:FullWidthExpander>
The ToggleButton (which is defined in my Expander Template above) gets overridden by this Button.
Are you binding the UserControl.Content to the Expander.Content property?
<!-- define a custom Template for the UserControl FullWidthExpander -->
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<!-- be sure to include the Content binding to pass the UC.Content to Expander -->
<Expander Content="{TemplateBinding Content}">
<!-- create a custom Template for this Expander -->
<Expander.Template>
<ControlTemplate TargetType="Expander">
<Grid>
<Grid.RowDefinitions>
<RowDefinition x:Name="ContentRow" Height="*"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="0" Content="{TemplateBinding Content}"/>
<ToggleButton Grid.Row="1" Content="Test Toggle Button" />
</Grid>
</ControlTemplate>
</Expander.Template>
</Expander>
</ControlTemplate>
</UserControl.Template>
I did a quick test, and this works fine when using the control like this :
<local:FullWidthExpander>
<Button Content="Test Content Button"/>
</local:FullWidthExpander>
I also took a look at your other question, and if you have your ControlTemplate.Triggers here then you will also want to make sure to set Expander.IsExpanded to True in order to view your Content. Your trigger is hiding the top content row if IsExpanded=False, which is the default for an Expander.
When you do this, it means that the entire contents of the user control is replaced with the content you provided.
<custom:FullWidthExpander Width="200" HeaderBackground="Gray">
<Button />
</custom:FullWidthExpander>
To get around this you need to host the content little bit differently in your usercontrol
First add a dependency property for the user control
public object UserControlContent
{
get { return (object)GetValue(UserControlContentProperty); }
set { SetValue(UserControlContentProperty, value); }
}
public static readonly DependencyProperty UserControlContentProperty =
DependencyProperty.Register("UserControlContent", typeof(object), typeof(FullWidthExpander),
new PropertyMetadata(null));
Then bind this to the contentpresenter in the usercontrol's xaml also define a name for your usercontrol like x:Name="Root".
<Expander Header="My expander header">
<Expander.Template>
<ControlTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="15"/>
</Grid.RowDefinitions>
<ContentPresenter x:Name="ContentPresenter" Grid.Row="0" Content="{Binding UserControlContent, ElementName=Root}" />
<ToggleButton Grid.Row="1" Content="Togglebutton">
</ToggleButton>
</Grid>
</ControlTemplate>
</Expander.Template>
</Expander>
And finally you define the content content in maindwindow xaml as such
<custom:FullWidthExpander>
<custom:FullWidthExpander.UserControlContent>
<Button Content="Click me"/>
</custom:FullWidthExpander.UserControlContent>
</custom:FullWidthExpander>

Add ControlTemplate to AnimatedTabControl without overwriting animation behavior

I am using MahApps AnimatedTabControl and I need to create a ControlTemplate to add a ScrollViewer for header tabs. Here is my template:
<TabControl.Template>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ScrollViewer x:Name="_MainTabControlScrollViewer" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Disabled">
<TabPanel x:Name="HeaderPanel" IsItemsHost="True" Margin="0,4,0,0"/>
</ScrollViewer>
<ContentPresenter x:Name="PART_SelectedContentHost" Margin="4" ContentSource="SelectedContent" Grid.Row="1"/>
</Grid>
</ControlTemplate>
</TabControl.Template>
However, this kills the animation. Is there a way to inherit the default AnimatedTabControl behavior?
Instead overriding the TabControl just use the MetroAnimatedSingleRowTabControl.
<Controls:MetroAnimatedSingleRowTabControl x:Name="AnimatedTabControl">
<TabItem Header="tab test"></TabItem>
</Controls:MetroAnimatedSingleRowTabControl>
with xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
Hope that helps.

Nested ContentControls with template

I have a custom WindowStyle, the XAML looks like this:
<Style TargetType="{x:Type Window}"
x:Key="WindowStyle">
/** Some setters **/
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<AdornerDecorator>
<Grid Background="#88000000"
x:Name="WindowBackgroundGrid">
<Border x:Name="WindowContentBorder"
Background="{DynamicResource WindowBackground}"MaxHeight="{Binding Source={x:Static SystemParameters.FullPrimaryScreenHeight}}"
MaxWidth="{Binding Source={x:Static SystemParameters.FullPrimaryScreenWidth}}"
Margin="20">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Header -->
<Border BorderBrush="{DynamicResource BorderBrushColor}"
Background="{DynamicResource PaneHeader_Background}"
Grid.Row="0">
<TextBlock Text="Title"Foreground="{DynamicResource DefaultForeground}"
FontSize="16"
FontWeight="Bold"
Margin="5,5,2,5" />
</Border>
<!-- Content -->
<ScrollViewer Grid.Row="1"
Margin="5">
<ContentPresenter Content="{TemplateBinding Content}" />
</ScrollViewer>
</Grid>
</Border>
</Grid>
</AdornerDecorator>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now I want the inner Grid in a seperate Style so that I can use it elsewhere.
<Style x:Key="WindowContentStyle"
TargetType="{x:Type ContentPresenter}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Header -->
/** Border control **/
<!-- Content -->
<ScrollViewer Grid.Row="1"
Margin="5">
<ContentPresenter Content="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}" />
</ScrollViewer>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
And I use a ContenPresenter in my WindowStyle to present it:
<ContentPresenter>
<ContentPresenter.Style>
<Style TargetType="{x:Type ContentPresenter}"
BasedOn="{StaticResource WindowContentStyle}" />
</ContentPresenter.Style>
</ContentPresenter>
Problem
The edit above didn't give me any errors, but it doesn't present my WindowContentStyle.
When I set the Content property of the Window control and load the style
this.window.Content = view;
this.window.Style = (Style)Application.Current.TryFindResource("WindowStyle");
the content is shown in the ContentPresenter in the WindowStyle and not in WindowContentStyle. Because of this, the Template is not used and I don't have a header with a title.
How can I make my outer ContentPresenter pass on the Content to my inner ContentPresenter (the one in WindowContentStyle)?
Thanks in advance!
Greetings
Loetn
You should use a ContentControl to display your content, not a ContentPresenter. From the ContentPresenter Class page on MSDN:
You typically use the ContentPresenter in the ControlTemplate of a ContentControl to specify where the content is to be added.
From the ContentControl Class page on MSDN:
A ContentControl has a limited default style. If you want to enhance the appearance of the control, you can create a new DataTemplate.

WPF - Hosting content inside a UserControl

I'm trying to create a user control that has a Grid with two rows.
the first row for a title and the second one for a content that will be defined outside the user control such as a Button in our example.
Somehow I didn't get it to work.
UserControl1 xaml:
<Grid Background="LightBlue">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="Title" FontSize="30" Margin="10,0,0,0"/>
</Grid>
MainWindow xaml:
<Grid>
<local:UserControl1>
<Button>Click me</Button>
</local:UserControl1>
</Grid>
The picture below should explain what's my problem:
The following code
<local:UserControl1>
<Button>Click me</Button>
</local:UserControl1>
Means that you set UserControl1's Content property to be that button. This button simply replaces that UserControls1's markup. So all the things that you have in UserControl1.xaml are not there any more.
EDIT
If you want your UserControl to host some markup that will be set somewhere outside of it, you can add a DependencyProperty to it, for example:
/// <summary>
/// Gets or sets additional content for the UserControl
/// </summary>
public object AdditionalContent
{
get { return (object)GetValue(AdditionalContentProperty); }
set { SetValue(AdditionalContentProperty, value); }
}
public static readonly DependencyProperty AdditionalContentProperty =
DependencyProperty.Register("AdditionalContent", typeof(object), typeof(UserControl1),
new PropertyMetadata(null));
And add some element to it's markup to host that additional content. Here's an example extending the markup you provided:
<UserControl ... Name="userControl">
<Grid Background="LightBlue">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="Title" FontSize="30" Margin="10,0,0,0"/>
<ContentPresenter Content="{Binding AdditionalContent, ElementName=userControl}" />
</Grid>
</UserControl>
Now you can use it as following:
<local:UserControl1>
<local:UserControl1.AdditionalContent>
<Button>Click me</Button>
</local:UserControl1.AdditionalContent>
</local:UserControl1>
You have to set the ControlTemplate:
<UserControl>
<UserControl.Resources>
<Style TargetType="{x:Type local:UserControl1}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:UserControl1}">
<Grid Background="LightBlue">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Title" FontSize="30" Margin="10,0,0,0"/>
<ContentPresenter Grid.Row="1" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
</UserControl>
You can template the user control to add additional visuals like the TextBlock.
<UserControl>
<UserControl.Style>
<Style TargetType="{x:Type UserControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="LightBlue">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="Title" FontSize="30" Margin="10,0,0,0"/>
<ContentPresenter Grid.Row="1" Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Style>
<Button>
Click me!
</Button>
</UserControl>
Use template with
< ContentControl />
Instead of using Content Presenter
So place this:
<UserControl.Style>
<Style TargetType="{x:Type UserControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type UserControl}" >
<Grid Background="LightBlue">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="Title" FontSize="30" Margin="10,0,0,0"/>
<ContentControl Grid.Row="1" Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Style>
to your userControl
This is the simple general template for a user control (without using styles or properties to set the content):
<UserControl ...>
<UserControl.Template>
<ControlTemplate TargetType="{x:Type UserControl}">
<!-- control contents here -->
<ContentPresenter/><!-- outside contents go here -->
<!-- control contents here -->
</ControlTemplate>
</UserControl.Template>
</UserControl>
The <ControlTemplate> represents the user control's XAML duplicated for each control.
The <ContentPresenter> is where the Content gets put when consuming the control.

WPF tabitem positioning

What is the proper way of positioning for example three tabitems at the very top left corner and one at the very top right corner of a tab control using WPF?
I have tried to move the fourth tabitem to the right by changing its margin but this doesn't produce a good result; first of all it is cut short and second of all it does not display correctly when selected.
The problem is that the TabPanel, which is used internally by the TabControl to lay out the tabs, does not seem to support what you want. A quick workaround would be to replace the TabPanel by something else, for example, a DockPanel:
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<TabControl>
<TabControl.Template>
<ControlTemplate TargetType="TabControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border BorderThickness="0,0,1,1" BorderBrush="#D0CEBF" Grid.Row="1">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter ContentSource="SelectedContent"/>
</Border>
</Border>
</Border>
<DockPanel IsItemsHost="True" LastChildFill="False" Margin="2,2,2,0" />
</Grid>
</ControlTemplate>
</TabControl.Template>
<TabItem Header="Item 1" />
<TabItem Header="Item 2" />
<TabItem Header="Item 3" />
<TabItem Header="Item 4" DockPanel.Dock="Right" />
</TabControl>
</Window>
(Reference: This is a modified version of an MSDN example for styling a TabControl.)
The simple DockPanel doesn't work as smooth as the TabPanel -- the tabs "jump" a bit when switching between them, but this might get you started. Maybe subclassing the TabPanel and overriding the relevant parts would give you a more accurate result; I guess it depends on how much effort you want to put into this.
I found that by inserting an "invisible" tab I could adjust the spacing, (i.e. move the tabs down from the top)
For example:
TabItem Height="100" Visibility="Hidden" <br>
TabItem..... <br>
TabItem.... <br>
You would need to swap out the TabPanel within the TabControl to something custom which provided the desired behavior. None of the default panels are going to provide your desired behavior out of the box.
This will most likely need to involve overriding MeasureOverride and ArrangeOverride to provide the custom placement within the panel that is desired based on the number of items it contains.
This will involve a custom ControlTemplate for the TabControl. I tried an example using a DockPanel as the items host rather than the default TabPanel.
<Style TargetType="{x:Type TabControl}">
<Setter Property="OverridesDefaultStyle"
Value="True" />
<Setter Property="SnapsToDevicePixels"
Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid KeyboardNavigation.TabNavigation="Local">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<DockPanel Name="HeaderPanel"
LastChildFill="False"
Grid.Row="0"
Panel.ZIndex="1"
Margin="0,0,4,-1"
IsItemsHost="True"
KeyboardNavigation.TabIndex="1"
Background="Transparent" />
<Border Name="Border"
Grid.Row="1"
Background="WhiteSmoke"
BorderBrush="Black"
BorderThickness="1"
CornerRadius="2"
KeyboardNavigation.TabNavigation="Local"
KeyboardNavigation.DirectionalNavigation="Contained"
KeyboardNavigation.TabIndex="2">
<ContentPresenter Name="PART_SelectedContentHost"
Margin="4"
ContentSource="SelectedContent" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The problem is that I don't know of a way of exposing the DockPanel.Dock property to the TabItems outside of the ControlTemplate E.G.
<TabControl Margin="10">
<TabItem Header="Tab One" DockPanel.Dock="Left"/>
<TabItem Header="Tab Two" DocKPanel.Dock="Left"/>
<TabItem Header="Tab Three" DocKPanel.Dock="Left"/>
<TabItem Header="Tab Four" DocKPanel.Dock="Right"/>
</TabControl>
// Note: This does not work!!
I guess you will need to write your own Panel to host the TabItems; Note that this will be quite a lot of work as you will need to handle things like overflow behaviour which is built into the TabPanel.
Even if you did try this I think you would have to write a custom TabControl if you wanted to expose this functionality outside of the ControlTemplate.
If you want to go down this road then see my answer in this post

Resources