feat: add avalonia HeaderedContentControl style.

This commit is contained in:
NaBian committed 2025-09-27 20:43:27 +08:00
1 parent 72abacf030
commit 97110e9dc9
5 files changed
+155 -13

No files matched your search

@@ -38,7 +38,7 @@ public class InfoElement
public static readonly AttachedProperty<double> MaxContentHeightProperty =
AvaloniaProperty.RegisterAttached<InfoElement, AvaloniaObject, double>("MaxContentHeight",
defaultValue: double.PositiveInfinity);
defaultValue: double.PositiveInfinity, inherits: true);
public static void SetMaxContentHeight(AvaloniaObject element, double value) =>
element.SetValue(MaxContentHeightProperty, value);
@@ -95,14 +95,14 @@ public class TitleElement
public static Thickness GetMarginOnTheTop(AvaloniaObject element) => element.GetValue(MarginOnTheTopProperty);
public static readonly AttachedProperty<double> MinHeightProperty =
AvaloniaProperty.RegisterAttached<TitleElement, AvaloniaObject, double>("MinHeight");
AvaloniaProperty.RegisterAttached<TitleElement, AvaloniaObject, double>("MinHeight", inherits: true);
public static void SetMinHeight(AvaloniaObject element, double value) => element.SetValue(MinHeightProperty, value);
public static double GetMinHeight(AvaloniaObject element) => element.GetValue(MinHeightProperty);
public static readonly AttachedProperty<double> MinWidthProperty =
AvaloniaProperty.RegisterAttached<TitleElement, AvaloniaObject, double>("MinWidth");
AvaloniaProperty.RegisterAttached<TitleElement, AvaloniaObject, double>("MinWidth", inherits: true);
public static void SetMinWidth(AvaloniaObject element, double value) => element.SetValue(MinWidthProperty, value);
@@ -0,0 +1,131 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:ClassModifier="internal"
xmlns:hc="clr-namespace:HandyControl.Controls"
xmlns:sys="using:System">
<ControlTemplate x:Key="HeaderedContentControlTopTemplate"
TargetType="HeaderedContentControl">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition MinHeight="{Binding Path=(hc:InfoElement.MinContentHeight), RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding Path=(hc:InfoElement.ContentHeight), RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource Double2GridLengthConverter}}" />
</Grid.RowDefinitions>
<DockPanel LastChildFill="True"
IsHitTestVisible="False"
IsVisible="{TemplateBinding Header, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
HorizontalAlignment="{Binding Path=(hc:TitleElement.HorizontalAlignment), RelativeSource={RelativeSource TemplatedParent}}"
Margin="{Binding Path=(hc:TitleElement.MarginOnTheTop), RelativeSource={RelativeSource TemplatedParent}}">
<ContentPresenter DockPanel.Dock="Right"
TextElement.Foreground="{DynamicResource DangerBrush}"
Margin="4,0,0,0"
Content="{Binding Path=(hc:InfoElement.Symbol), RelativeSource={RelativeSource TemplatedParent}}"
IsVisible="{Binding Path=(hc:InfoElement.Necessary), RelativeSource={RelativeSource TemplatedParent}}" />
<ContentPresenter Name="PART_HeaderPresenter"
Content="{TemplateBinding Header}">
<ContentPresenter.DataTemplates>
<DataTemplate DataType="sys:String">
<TextBlock Text="{Binding}"
TextWrapping="NoWrap"
TextTrimming="CharacterEllipsis"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
FontFamily="{TemplateBinding FontFamily}"
FontStyle="{TemplateBinding FontStyle}" />
</DataTemplate>
</ContentPresenter.DataTemplates>
</ContentPresenter>
</DockPanel>
<DataValidationErrors Grid.Row="1">
<ContentPresenter Name="PART_ContentPresenter"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
RecognizesAccessKey="True"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
FontFamily="{TemplateBinding FontFamily}"
FontStyle="{TemplateBinding FontStyle}" />
</DataValidationErrors>
</Grid>
</Border>
</ControlTemplate>
<ControlTemplate x:Key="HeaderedContentControlLeftTemplate"
TargetType="HeaderedContentControl">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}">
<Grid MinHeight="{Binding Path=(hc:InfoElement.MinContentHeight), RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding Path=(hc:InfoElement.ContentHeight), RelativeSource={RelativeSource TemplatedParent}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Path=(hc:TitleElement.TitleWidth), RelativeSource={RelativeSource TemplatedParent}}" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<DockPanel LastChildFill="True"
IsHitTestVisible="False"
IsVisible="{TemplateBinding Header, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
HorizontalAlignment="{Binding Path=(hc:TitleElement.HorizontalAlignment), RelativeSource={RelativeSource TemplatedParent}}"
VerticalAlignment="{Binding Path=(hc:TitleElement.VerticalAlignment), RelativeSource={RelativeSource TemplatedParent}}"
Margin="{Binding Path=(hc:TitleElement.MarginOnTheLeft), RelativeSource={RelativeSource TemplatedParent}}">
<ContentPresenter DockPanel.Dock="Right"
TextElement.Foreground="{DynamicResource DangerBrush}"
Margin="4,0,0,0"
Content="{Binding Path=(hc:InfoElement.Symbol), RelativeSource={RelativeSource TemplatedParent}}"
IsVisible="{Binding Path=(hc:InfoElement.Necessary), RelativeSource={RelativeSource TemplatedParent}}" />
<ContentPresenter Name="PART_HeaderPresenter"
Content="{TemplateBinding Header}">
<ContentPresenter.DataTemplates>
<DataTemplate DataType="sys:String">
<TextBlock Text="{Binding}"
TextWrapping="NoWrap"
TextTrimming="CharacterEllipsis"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
FontFamily="{TemplateBinding FontFamily}"
FontStyle="{TemplateBinding FontStyle}" />
</DataTemplate>
</ContentPresenter.DataTemplates>
</ContentPresenter>
</DockPanel>
<DataValidationErrors Grid.Column="1">
<ContentPresenter Name="PART_ContentPresenter"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
RecognizesAccessKey="True"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
FontFamily="{TemplateBinding FontFamily}"
FontStyle="{TemplateBinding FontStyle}" />
</DataValidationErrors>
</Grid>
</Border>
</ControlTemplate>
<ControlTheme x:Key="HeaderedContentControlBaseStyle"
TargetType="HeaderedContentControl">
<Setter Property="Template"
Value="{StaticResource HeaderedContentControlTopTemplate}" />
<Style Selector="^[(hc|TitleElement.TitlePlacement)=Left]">
<Setter Property="Template"
Value="{StaticResource HeaderedContentControlLeftTemplate}" />
</Style>
</ControlTheme>
<ControlTheme x:Key="{x:Type HeaderedContentControl}"
BasedOn="{StaticResource HeaderedContentControlBaseStyle}"
TargetType="HeaderedContentControl" />
</ResourceDictionary>
@@ -54,6 +54,7 @@
<MergeResourceInclude Source="avares://HandyControl/Themes/Styles/Menu.axaml" />
<MergeResourceInclude Source="avares://HandyControl/Themes/Styles/ContextMenu.axaml" />
<MergeResourceInclude Source="avares://HandyControl/Themes/Styles/SelectableTextBlock.axaml" />
<MergeResourceInclude Source="avares://HandyControl/Themes/Styles/HeaderedContentControl.axaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Styles.Resources>
@@ -9,9 +9,11 @@ public class InfoElement : TitleElement
/// 占位符
/// </summary>
public static readonly DependencyProperty PlaceholderProperty = DependencyProperty.RegisterAttached(
"Placeholder", typeof(string), typeof(InfoElement), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
"Placeholder", typeof(string), typeof(InfoElement),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
public static void SetPlaceholder(DependencyObject element, string value) => element.SetValue(PlaceholderProperty, value);
public static void SetPlaceholder(DependencyObject element, string value) =>
element.SetValue(PlaceholderProperty, value);
public static string GetPlaceholder(DependencyObject element) => (string) element.GetValue(PlaceholderProperty);
@@ -19,9 +21,11 @@ public class InfoElement : TitleElement
/// 是否必填
/// </summary>
public static readonly DependencyProperty NecessaryProperty = DependencyProperty.RegisterAttached(
"Necessary", typeof(bool), typeof(InfoElement), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits));
"Necessary", typeof(bool), typeof(InfoElement),
new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits));
public static void SetNecessary(DependencyObject element, bool value) => element.SetValue(NecessaryProperty, ValueBoxes.BooleanBox(value));
public static void SetNecessary(DependencyObject element, bool value) =>
element.SetValue(NecessaryProperty, ValueBoxes.BooleanBox(value));
public static bool GetNecessary(DependencyObject element) => (bool) element.GetValue(NecessaryProperty);
@@ -29,7 +33,8 @@ public class InfoElement : TitleElement
/// 标记
/// </summary>
public static readonly DependencyProperty SymbolProperty = DependencyProperty.RegisterAttached(
"Symbol", typeof(string), typeof(InfoElement), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
"Symbol", typeof(string), typeof(InfoElement),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
public static void SetSymbol(DependencyObject element, string value) => element.SetValue(SymbolProperty, value);
@@ -39,9 +44,11 @@ public class InfoElement : TitleElement
/// 内容高度
/// </summary>
public static readonly DependencyProperty ContentHeightProperty = DependencyProperty.RegisterAttached(
"ContentHeight", typeof(double), typeof(InfoElement), new FrameworkPropertyMetadata(28.0, FrameworkPropertyMetadataOptions.Inherits));
"ContentHeight", typeof(double), typeof(InfoElement),
new FrameworkPropertyMetadata(28.0, FrameworkPropertyMetadataOptions.Inherits));
public static void SetContentHeight(DependencyObject element, double value) => element.SetValue(ContentHeightProperty, value);
public static void SetContentHeight(DependencyObject element, double value) =>
element.SetValue(ContentHeightProperty, value);
public static double GetContentHeight(DependencyObject element) => (double) element.GetValue(ContentHeightProperty);
@@ -49,7 +56,8 @@ public class InfoElement : TitleElement
/// 最小内容高度
/// </summary>
public static readonly DependencyProperty MinContentHeightProperty = DependencyProperty.RegisterAttached(
"MinContentHeight", typeof(double), typeof(InfoElement), new PropertyMetadata(28.0));
"MinContentHeight", typeof(double), typeof(InfoElement),
new FrameworkPropertyMetadata(28.0, FrameworkPropertyMetadataOptions.Inherits));
public static void SetMinContentHeight(DependencyObject element, double value)
=> element.SetValue(MinContentHeightProperty, value);
@@ -61,7 +69,8 @@ public class InfoElement : TitleElement
/// 最大内容高度
/// </summary>
public static readonly DependencyProperty MaxContentHeightProperty = DependencyProperty.RegisterAttached(
"MaxContentHeight", typeof(double), typeof(InfoElement), new PropertyMetadata(double.PositiveInfinity));
"MaxContentHeight", typeof(double), typeof(InfoElement),
new FrameworkPropertyMetadata(double.PositiveInfinity, FrameworkPropertyMetadataOptions.Inherits));
public static void SetMaxContentHeight(DependencyObject element, double value)
=> element.SetValue(MaxContentHeightProperty, value);
@@ -93,7 +102,8 @@ public class InfoElement : TitleElement
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.RegisterAttached(
"IsReadOnly", typeof(bool), typeof(InfoElement), new PropertyMetadata(ValueBoxes.FalseBox));
public static void SetIsReadOnly(DependencyObject element, bool value) => element.SetValue(IsReadOnlyProperty, ValueBoxes.BooleanBox(value));
public static void SetIsReadOnly(DependencyObject element, bool value) =>
element.SetValue(IsReadOnlyProperty, ValueBoxes.BooleanBox(value));
public static bool GetIsReadOnly(DependencyObject element) => (bool) element.GetValue(IsReadOnlyProperty);
}