Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 38 additions & 12 deletions src/Wpf.Ui/Controls/Separator/Separator.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,54 @@
All Rights Reserved.
-->

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Wpf.Ui.Controls">

<Style TargetType="{x:Type Separator}">
<Setter Property="BorderBrush" Value="{DynamicResource SeparatorBorderBrush}" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Margin" Value="0" />
<Setter Property="BorderThickness" Value="1,1,0,0" />
<Setter Property="Focusable" Value="False" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<!--
Provides two default resource keys:
- Horizontal: DefaultSeparatorHorizontalMargin
- Vertical: DefaultSeparatorVerticalMargin

Allows developers to customize default margins for each orientation.
-->
<Thickness x:Key="DefaultSeparatorHorizontalMargin">0,2,0,2</Thickness>
<Thickness x:Key="DefaultSeparatorVerticalMargin">2,0,2,0</Thickness>

<Style x:Key="DefaultSeparatorStyle" TargetType="{x:Type Separator}">
<!--
Note: Any existing code referencing the "SeparatorBorderBrush" resource key will
need to be updated to "SeparatorBackgroundBrush".
-->
<Setter Property="Background" Value="{DynamicResource SeparatorBackgroundBrush}" />
<Setter Property="Margin" Value="{DynamicResource SeparatorHorizontalMargin}" />
<Setter Property="Focusable" Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Separator}">
<Border
Width="{TemplateBinding Width}"
Margin="{TemplateBinding Margin}"
x:Name="SeparatorBorder"
Height="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" />
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="true" />
<ControlTemplate.Triggers>
<Trigger Property="controls:SeparatorAttached.Orientation" Value="Vertical">
<Setter TargetName="SeparatorBorder" Property="Width" Value="1" />
<Setter TargetName="SeparatorBorder" Property="Height" Value="Auto" />
<Setter TargetName="SeparatorBorder" Property="HorizontalAlignment" Value="Center" />
<Setter TargetName="SeparatorBorder" Property="VerticalAlignment" Value="Stretch" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style BasedOn="{StaticResource DefaultSeparatorStyle}" TargetType="{x:Type Separator}" />

</ResourceDictionary>
91 changes: 91 additions & 0 deletions src/Wpf.Ui/Controls/Separator/SeparatorAttached.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and WPF UI Contributors.
// All Rights Reserved.

using System.Windows.Controls;

// ReSharper disable once CheckNamespace
namespace Wpf.Ui.Controls;

/// <summary>
/// Provides <c>Orientation</c> property for Separator
/// </summary>
/// <example>
/// <code lang="xml">
/// &lt;Separator controls:SeparatorAttached.Orientation="Vertical" /&gt;
/// </code>
/// </example>
public static class SeparatorAttached
{
/// <summary>
/// Resource key for <see cref="Separator"/> horizontal margin.
/// </summary>
public const string HorizontalMarginKey = "DefaultSeparatorHorizontalMargin";

/// <summary>
/// Resource key for <see cref="Separator"/> vertical margin.
/// </summary>
public const string VerticalMarginKey = "DefaultSeparatorVerticalMargin";

public static readonly DependencyProperty OrientationProperty =
DependencyProperty.RegisterAttached(
"Orientation",
typeof(Orientation),
typeof(SeparatorAttached),
new FrameworkPropertyMetadata(Orientation.Horizontal, OnOrientationChanged)
);

/// <summary>Helper for getting <see cref="OrientationProperty"/> from <paramref name="obj"/>.</summary>
/// <param name="obj"><see cref="DependencyObject"/> to read <see cref="OrientationProperty"/> from.</param>
/// <returns>Orientation property value.</returns>
[AttachedPropertyBrowsableForType(typeof(Separator))]
public static Orientation GetOrientation(DependencyObject obj)
{
return (Orientation)obj.GetValue(OrientationProperty);
}

/// <summary>Helper for setting <see cref="OrientationProperty"/> on <paramref name="obj"/>.</summary>
/// <param name="obj"><see cref="DependencyObject"/> to set <see cref="OrientationProperty"/> on.</param>
/// <param name="value">Orientation property value.</param>
public static void SetOrientation(DependencyObject obj, Orientation value)
{
obj.SetValue(OrientationProperty, value);
}

private static void OnOrientationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is not FrameworkElement element)
{
return;
}

Thickness currentMargin = element.Margin;
Orientation newOrientation = (Orientation)e.NewValue;

// Smart margin logic:
// 1. When switching orientation, if Margin still equals the horizontal default,
// we assume the user hasn't customized it and apply the new orientation's default.
// 2. Subsequent orientation switches only adjust the margin if it still matches
// the previous orientation's default.
// 3. If the user coincidentally sets Margin to a value that matches one default,
// switching to the other orientation will still apply the correct default.
// 4. Any non‑default value set by the user is treated as intentional and preserved.
if (newOrientation == Orientation.Vertical)
{
var horizontalMargin = element.TryFindResource(HorizontalMarginKey) as Thickness?;
if (currentMargin == horizontalMargin)
{
element.SetResourceReference(FrameworkElement.MarginProperty, VerticalMarginKey);
}
}
else if (newOrientation == Orientation.Horizontal)
{
var verticalMargin = element.TryFindResource(VerticalMarginKey) as Thickness?;
if (currentMargin == verticalMargin)
{
element.SetResourceReference(FrameworkElement.MarginProperty, HorizontalMarginKey);
}
}
}
}
2 changes: 1 addition & 1 deletion src/Wpf.Ui/Resources/Theme/Dark.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@
<SolidColorBrush x:Key="RatingControlSelectedForeground" Color="{DynamicResource SystemAccentColorPrimary}" />

<!-- Separator -->
<SolidColorBrush x:Key="SeparatorBorderBrush" Color="{StaticResource DividerStrokeColorDefault}" />
<SolidColorBrush x:Key="SeparatorBackgroundBrush" Color="{StaticResource DividerStrokeColorDefault}" />

<!-- Slider -->
<SolidColorBrush x:Key="SliderTrackFill" Color="{StaticResource ControlStrongFillColorDefault}" />
Expand Down
2 changes: 1 addition & 1 deletion src/Wpf.Ui/Resources/Theme/HC1.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@
<SolidColorBrush x:Key="RatingControlSelectedForeground" Color="{StaticResource SystemColorHighlightColor}" />

<!-- Separator -->
<SolidColorBrush x:Key="SeparatorBorderBrush" Color="{StaticResource SystemColorWindowTextColor}" />
<SolidColorBrush x:Key="SeparatorBackgroundBrush" Color="{StaticResource SystemColorWindowTextColor}" />

<!-- Slider -->
<SolidColorBrush x:Key="SliderTrackFill" Color="{StaticResource SystemColorWindowTextColor}" />
Expand Down
2 changes: 1 addition & 1 deletion src/Wpf.Ui/Resources/Theme/HC2.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@
<SolidColorBrush x:Key="RatingControlSelectedForeground" Color="{StaticResource SystemColorHighlightColor}" />

<!-- Separator -->
<SolidColorBrush x:Key="SeparatorBorderBrush" Color="{StaticResource SystemColorWindowTextColor}" />
<SolidColorBrush x:Key="SeparatorBackgroundBrush" Color="{StaticResource SystemColorWindowTextColor}" />

<!-- Slider -->
<SolidColorBrush x:Key="SliderTrackFill" Color="{StaticResource SystemColorWindowTextColor}" />
Expand Down
2 changes: 1 addition & 1 deletion src/Wpf.Ui/Resources/Theme/HCBlack.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@
<SolidColorBrush x:Key="RatingControlSelectedForeground" Color="{StaticResource SystemColorHighlightColor}" />

<!-- Separator -->
<SolidColorBrush x:Key="SeparatorBorderBrush" Color="{StaticResource SystemColorWindowTextColor}" />
<SolidColorBrush x:Key="SeparatorBackgroundBrush" Color="{StaticResource SystemColorWindowTextColor}" />

<!-- Slider -->
<SolidColorBrush x:Key="SliderTrackFill" Color="{StaticResource SystemColorWindowTextColor}" />
Expand Down
2 changes: 1 addition & 1 deletion src/Wpf.Ui/Resources/Theme/HCWhite.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@
<SolidColorBrush x:Key="RatingControlSelectedForeground" Color="{StaticResource SystemColorHighlightColor}" />

<!-- Separator -->
<SolidColorBrush x:Key="SeparatorBorderBrush" Color="{StaticResource SystemColorWindowTextColor}" />
<SolidColorBrush x:Key="SeparatorBackgroundBrush" Color="{StaticResource SystemColorWindowTextColor}" />

<!-- Slider -->
<SolidColorBrush x:Key="SliderTrackFill" Color="{StaticResource SystemColorWindowTextColor}" />
Expand Down
2 changes: 1 addition & 1 deletion src/Wpf.Ui/Resources/Theme/Light.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@
<SolidColorBrush x:Key="RatingControlSelectedForeground" Color="{DynamicResource SystemAccentColorPrimary}" />

<!-- Separator -->
<SolidColorBrush x:Key="SeparatorBorderBrush" Color="{StaticResource DividerStrokeColorDefault}" />
<SolidColorBrush x:Key="SeparatorBackgroundBrush" Color="{StaticResource DividerStrokeColorDefault}" />

<!-- Slider -->
<SolidColorBrush x:Key="SliderTrackFill" Color="{StaticResource ControlStrongFillColorDefault}" />
Expand Down
Loading