How do I correctly format the DatePicker StyleTemplate - c#

I need to format an UWP-DatePicker. What I'd like to get would be a common DatePicker which fits inside a grid propperly.
Here is how I embedded the DatePicker inside my GridColumn:
<Grid Grid.Row="1" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<DatePicker Grid.Column="0"
HorizontalAlignment="Left"
MonthFormat="{}{month.abbreviated(3)}"
Date="{Binding AppointmentStartDateProxy, Mode=TwoWay}"
DateChanged="DatePicker_DateChanged"
Style="{StaticResource DatePickerStyle1}">
<DatePicker.IsEnabled>
<Binding Path="Closed" Converter="{StaticResource negationConverter}"/>
</DatePicker.IsEnabled>
</DatePicker>
</Grid>
Here are the "crucial" changes to the StyleTemplate:
<Style x:Key="DatePickerStyle1" TargetType="DatePicker">
<.../>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DatePicker">
<StackPanel x:Name="LayoutRoot" Margin="{TemplateBinding Padding}" HorizontalAlignment="Stretch" >
<ContentPresenter x:Name="HeaderContentPresenter"
x:DeferLoadStrategy="Lazy"
Visibility="Collapsed"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
Margin="0,0,0,8"
Foreground="{ThemeResource SystemControlForegroundBaseHighBrush}"
AutomationProperties.AccessibilityView="Raw" />
<Button x:Name="FlyoutButton"
HorizontalAlignment="Left"
Style="{StaticResource DatePickerFlyoutButtonStyle}"
Foreground="{TemplateBinding Foreground}"
Background="{TemplateBinding Background}"
IsEnabled="{TemplateBinding IsEnabled}"
HorizontalContentAlignment="Stretch" />
When setting Style.Setter.Value.ControlTemplate.StackPanel.Button.HorizontalAlignment="Left"
my DatePicker does not fill its parent control:
When setting Style.Setter.Value.ControlTemplate.StackPanel.Button.HorizontalAlignment="Strech" my DatePicker is overlapping its parent control:
This behavior also stays the same when I'm changing the StyleTemplates LayoutRoot from StackPanel to Grid.
In my understanding, the RootLayout-Control should inherit its size from the Grid containing the DatePicker, and the Button should get its size from RootLayout with an result in fitting inside my GridColumn.
EDIT:
When changing only the DatePickers HorizontalAlignment to Strech (and in abscense of a style) it's overlapping the parent grid way to far:

Actually you don't need to change the style or the Button alignments. All you need is to set the HorizontalAlignment to Stretch in both controls. Note that the default value of it is Left.
<Grid x:Name="LayoutRoot">
<Grid Width="800">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<DatePicker Grid.Column="0" MonthFormat="{}{month.abbreviated(3)}" HorizontalAlignment="Stretch" />
<TimePicker Grid.Column="1" HorizontalAlignment="Stretch" />
</Grid>
</Grid>
Update
One more thing. DatePicker has a default MinWidth of 296 and TimePicker of 242. So if you could set them to a smaller value, like this -
<DatePicker Grid.Column="0" MonthFormat="{}{month.abbreviated(3)}" HorizontalAlignment="Stretch" MinWidth="80" />
<TimePicker Grid.Column="1" HorizontalAlignment="Stretch" MinWidth="80" />

Related

WPF custom control datagrid - creating column

I am WPF newbie and i want to create datagrid custom control with multiple controls inside this control.
my custom datagrid xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Bank"
xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit">
<Style TargetType="{x:Type local:EDataGrid}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:EDataGrid}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="500*" />
<RowDefinition Height="100*" />
</Grid.RowDefinitions>
<local:FilteringDataGrid x:Name="datagrid" Grid.Row="0" ItemsSource="{TemplateBinding ItemsSource}"></local:FilteringDataGrid>
<Grid Grid.Row="1" Height="26" Width="208">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25*"/>
<ColumnDefinition Width="25*"/>
<ColumnDefinition Width="50*"/>
<ColumnDefinition Width="20*"/>
<ColumnDefinition Width="50*"/>
<ColumnDefinition Width="25*"/>
<ColumnDefinition Width="25*"/>
</Grid.ColumnDefinitions>
<Button x:Name="ButtonFirstPage" Grid.Column="0" Tag="First" Content="<<" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderThickness="1,1,0,1" />
<Button x:Name="ButtonPreviousPage" Grid.Column="1" Tag="Previous" Content="<" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Button x:Name="ButtonNextPage" Grid.Column="5" Tag="Next" Content=">" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Button x:Name="ButtonLastPage" Grid.Column="6" Tag="Last" Content=">>" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderThickness="0,1,1,1"/>
<TextBox x:Name="TbPage" HorizontalAlignment="Stretch" VerticalContentAlignment="Center" Grid.Column="2" TextAlignment="Right" TextWrapping="Wrap" Text="1" VerticalAlignment="Stretch" BorderThickness="0,1" />
<TextBox x:Name="TbOfPage" VerticalContentAlignment="Center" Grid.Column="4" HorizontalAlignment="Stretch" TextWrapping="Wrap" VerticalAlignment="Stretch" Text="1" BorderThickness="0,1" />
<TextBox x:Name="TbPage_Copy" VerticalContentAlignment="Center" Grid.Column="3" TextAlignment="Center" HorizontalAlignment="Stretch" TextWrapping="Wrap" Text="z" VerticalAlignment="Stretch" BorderThickness="0,1"/>
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
and i want use this datagrid as follows in main windows(ie. specify columns):
<local:EDataGrid x:Name="dataGrid" " AutoGenerateColumns="False" >
<wp:DataGrid.Columns>
<wp:DataGridTextColumn Header="Id" Binding="{Binding Id}"/>
<wp:DataGridTextColumn Header="Type" Binding="{Binding Type}"/>
</wp:DataGrid.Columns>
</local:EDataGrid>
when i use it as in this example, datagrid autogenerate columns and i want to have only this two specified columns in datagrid.

Content overriding entire user control, rather than ContentPresenter

I'm guessing this is probably an easy mistake I am making somewhere. I have a custom control, stripped down to the basics:
<local:CustomUserControl x:Class="Test.UI.CustomUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Test.UI"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
IsEnabled="True" Loaded="CustomUserControl_Loaded">
<!-- Main border -->
<Border BorderBrush="#9B000000" BorderThickness="1" Margin="0,0,0,0" Padding="0">
<Grid Margin="0" Name="outerGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Margin="0" Grid.Row="0" Grid.Column="0" Name="innerGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Backgound -->
<Rectangle Fill="#FF5B87B8" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Name="headerRectangle" PreviewMouseLeftButtonUp ="headerRectangle_MouseLeftButtonUp" />
<!-- Text -->
<Label Grid.Row="0" Grid.Column="0" HorizontalContentAlignment="Left" VerticalContentAlignment="Center" Name="HeaderLabel" Content="Hello" Margin="5,0,0,0" Foreground="White" FontSize="18" Background="#FF5B87B8" PreviewMouseLeftButtonUp ="HeaderLabel_MouseLeftButtonUp" />
</Grid>
<!-- Content -->
<ContentPresenter Name="MainContent" Grid.Row="1" Grid.Column="0" Content="{Binding Content}" />
</Grid>
</Border>
</local:CustomUserControl>
When displaying on the form, like the following, it draws a box, with a shaded top, with white text:
<ui:CustomUserControl Grid.Row="0" Grid.Column="2" Name="borderDiagram" Header="Hello" />
But, if I try and add content to the ContentPresenter:
<ui:CustomUserControl Grid.Row="0" Grid.Column="2" Name="borderDiagram" Header="Hello">
<Label Content="Um..." />
</ui:CustomUserControl >
It overrides the entire custom control, leaving only the 'Um...' label.
I presume I am managing to override the entire control when I set the content, so how does one ensure that it's the ContentPresenter that takes the content, rather than the parent control?
CustomUserControl has some default Content:
<!-- Main border -->
<Border> ...
</Border>
and that Content is replaced with <Label Content="Um..." />
to make it work as expected (Label displayed in ContentPresenter) you should define default template:
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Border BorderBrush="#9B000000" BorderThickness="1" Margin="0,0,0,0" Padding="0">
<Grid Margin="0" Name="outerGrid">
...
<!-- Content -->
<ContentPresenter Name="MainContent" Grid.Row="1" Grid.Column="0"
Content="{TemplateBinding Content}" />
</Grid>
</Border>
</ControlTemplate>
</UserControl.Template>
pay attention to one important change:
Content="{TemplateBinding Content}"
ContentPresenter uses template binding to get and display custom content

Applying border style on certain grid cells in WPF

I want to apply the following style to certain cells of my grid:
<Border BorderBrush="#808080" BorderThickness="1,1,0,0" Grid.Column="3" >
<Border BorderBrush="#404040" BorderThickness="1,1,0,0" Width="Auto">
<Border BorderBrush="#FFFFFF" BorderThickness="0,0,1,1" Width="Auto">
<Border BorderBrush="#DCE6F4" BorderThickness="0,0,1,1" Width="Auto">
</Border>
</Border>
</Border>
</Border>
Right now i specify the cell in the first line Grid.Colum="3". However to do this for all cells I have to copy paste this like 20 times. Is there any short way to apply my style to all controls or cells of my choice (for example cell 1, , 7, 9 or label1, label 9 and label10?
I am a newbie in wpf, please be gentle :)
Assuming you want to place labels inside the grid you could create a ControlTemplate and assign it to the labels you want with Template="{StaticResource BorderLabel}":
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.Resources>
<ControlTemplate TargetType="Label" x:Key="BorderLabel">
<Border BorderBrush="#808080" BorderThickness="1,1,0,0" >
<Border BorderBrush="#404040" BorderThickness="1,1,0,0" Width="Auto">
<Border BorderBrush="#FFFFFF" BorderThickness="0,0,1,1" Width="Auto">
<Border BorderBrush="#DCE6F4" BorderThickness="0,0,1,1" Width="Auto">
<ContentControl Content="{TemplateBinding Content}" />
</Border>
</Border>
</Border>
</Border>
</ControlTemplate>
</Grid.Resources>
<Label Grid.Column="0" Content="MyText" />
<Label Grid.Column="1" Content="MyText" Template="{StaticResource BorderLabel}" />
</Grid>
And this is how it looks:

Styled Expander Control Template and not able to view Expanded Content on Click

I am just styling the Expander Control in WPF. I have defined only the styles in Expander Control Template, but I am not able to view the content of expander when I click on it.
I guess I have to define the expander trigers also ? but I don't know which triger and how to define it.
Also why I have to define triggers when I am just styling the expander.
<Window x:Class="ExpanderControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="Expander">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Expander}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="0" Name="contentRow"></RowDefinition>
</Grid.RowDefinitions>
<!--Expander Header-->
<Border Background="AliceBlue"
Grid.Row="0"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="20"></ColumnDefinition>
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0" ContentSource="Header"
RecognizesAccessKey="True"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="5"
></ContentPresenter>
<ToggleButton Grid.Column="1">
<TextBlock>x</TextBlock>
</ToggleButton>
</Grid>
</Border>
<!--Expander Content-->
<Border Background="Aqua" Grid.Row="1">
<ContentPresenter Grid.Row="1"></ContentPresenter>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Expander Header="Expander" HorizontalAlignment="Left" Margin="205,95,0,0" VerticalAlignment="Top" Width="200">
<Grid Background="#FFE5E5E5">
<Menu>
<MenuItem Header="hi"></MenuItem>
</Menu>
</Grid>
</Expander>
</Grid>
</Window>
At the moment there is no action linked to ToggleButton. You need to utilize Expander.IsExpanded property by binding it
To ToggleButton.IsChecked
To Border.Visibility via BooleanToVisibilityConverter (custom or built in)
Set content row height to Auto
This way changing ToggleButton.IsChecked will change Expander.IsExpanded which in turn will affect visibility of content Border. It will also work when you change IsExpanded property from outside.
This is working XAML
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<Style TargetType="{x:Type Expander}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Expander}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="Auto" Name="contentRow"/>
</Grid.RowDefinitions>
<!--Expander Header-->
<Border Background="AliceBlue" Grid.Row="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0" ContentSource="Header" RecognizesAccessKey="True" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="5" />
<ToggleButton Grid.Column="1" Content="x" IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsExpanded}"/>
</Grid>
</Border>
<!--Expander Content-->
<Border Background="Aqua" Grid.Row="1" Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsExpanded, Converter={StaticResource BooleanToVisibilityConverter}}">
<ContentPresenter/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
EDIT
If you want whole header to be able to expand/collapse your Expander you need to bring ContentPresenter for Header into Content of ToggleButton. In your case basically bring header Grid into ToggleButton.Content
<!--Expander Header-->
<ToggleButton IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsExpanded}" HorizontalContentAlignment="Stretch" Grid.Row="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0" ContentSource="Header" RecognizesAccessKey="True" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="5" />
<TextBlock Grid.Column="1" Text="x" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ToggleButton>

WPF XAML Custom Listbox Does Not Position Elements Correctly

I am trying to implement a custom multi-page dialog that takes an arbitrary number of visuals (slides) and displays them. The desired behavior would be that the selected item would appear at the top-center of the display area in the foreground. The previous slide would be at the bottom-left with a lower z-index, and the next slide would be at the bottom-right with a lower z-index. "Previous" and "Next" buttons would set the selected index. In the set method for the index, I loop through the slides and set an integer value called "SelectionState" based on whether each slide is hidden, selected, just before the selected one, or just after the selected one. I am trying to position the slides based on this integer using IValueConverters.
For my Listbox.ItemsPanelTemplate, I tried using a Grid. In the ItemsTemplate, I was setting the Grid.Column and Grid.Row using IValueConverters. Stepping through code, I can see that the value converters are being called, and that they are returning appropriate values, but all items appear in row 0, column 0 anyway.
After getting frustrated, I tried changing the Grid to a Canvas and setting the Canvas.Left and Canvas.Top properties, and again, I can see that I am getting good values back from the converter, but all items position themselves in the top-left corner anyway. (This code is shown, but commented out)
Since I know the value converters are behaving as expected, does anybody else see what I am doing wrong? Thank you in advance for any suggestions!
<Grid x:Name="DialogLayer">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="420" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="1100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListBox x:Name="lbSlides" ItemsSource="{Binding CurrentFormSet.InterviewSlides}" Grid.Column="1" Grid.Row="1" ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250" />
<ColumnDefinition Width="250" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="250" />
<ColumnDefinition Width="250" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="60" />
<RowDefinition Height="300" />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
</Grid>
<!--<Canvas Grid.Row="1" Grid.Column="1" />-->
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<!--<Border BorderBrush="Black" BorderThickness="1" Width="600" Height="360" Canvas.Top="{Binding SelectionState, Converter={StaticResource SelectionStateToCanvasTopConverter}}" Canvas.Left="{Binding SelectionState, Converter={StaticResource SelectionStateToCanvasLeftConverter}}" Panel.ZIndex="{Binding SelectionState, Converter={StaticResource SelectionStateToZIndexConverter}}">
<TextBlock Text="Hello World" />
</Border>-->
<Border BorderBrush="Black" BorderThickness="1" Width="600" Height="360" Grid.Column="{Binding SelectionState, Converter={StaticResource SelectionStateToGridColumnConverter}}" Grid.Row="{Binding SelectionState, Converter={StaticResource SelectionStateToGridRowConverter}}" Panel.ZIndex="{Binding SelectionState, Converter={StaticResource SelectionStateToZIndexConverter}}">
<TextBlock Text="Hello World" />
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
You have to set those properties on the item container (i.e. the ListBoxItem) by setting the ItemContainerStyle property:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Grid.Column" Value="{Binding SelectionState, ...}"/>
<Setter Property="Grid.Row" Value="{Binding SelectionState, ...}"/>
<Setter Property="Panel.ZIndex" Value="{Binding SelectionState, ...}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="1" Width="600" Height="360">
<TextBlock Text="Hello World" />
</Border>
</DataTemplate>
</ListBox.ItemTemplate>

Categories

Resources