chore: add avalonia basic TextBox demo.

This commit is contained in:
NaBian committed 2025-08-02 22:45:20 +08:00
1 parent 752b1513d8
commit 2fb12122f3
20 files changed
+677 -48

No files matched your search

-3
View File
@@ -1,6 +1,3 @@
### 找工作
我有一个朋友,9 年工作经验,github 主页:https://github.com/DingpingZhang 目前在找上海的工作。他熟悉设计模式并具有大型客户端架构经验,技术栈涉及:python、wpf、pg、react,有意向可联系邮箱:dingpingzhang@outlook.com
## 友情链接
[SimpleFactoryGenerator](https://github.com/DingpingZhang/SimpleFactoryGenerator) - A simple factory source generator that enables the pattern to not violate the open-close principle.
-3
View File
@@ -1,6 +1,3 @@
### 找工作
我有一个朋友,9 年工作经验,github 主页:https://github.com/DingpingZhang 目前在找上海的工作。他熟悉设计模式并具有大型客户端架构经验,技术栈涉及:python、wpf、pg、react,有意向可联系邮箱:dingpingzhang@outlook.com
## Blogroll
[SimpleFactoryGenerator](https://github.com/DingpingZhang/SimpleFactoryGenerator) - A simple factory source generator that enables the pattern to not violate the open-close principle.
+1 -1
View File
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Nullable>enable</Nullable>
<AvaloniaVersion>11.1.1</AvaloniaVersion>
<AvaloniaVersion>11.3.2</AvaloniaVersion>
</PropertyGroup>
</Project>
@@ -13,7 +13,7 @@
[ "ScrollViewer", "NativeScrollViewerDemo", "Brush.ScrollBox", "", "" ],
[ "Slider", "SliderDemo", "Brush.Slider", "", "" ],
[ "TextBlock", "TextBlockDemo", "Brush.TextBlock", "", "" ],
[ "TextBox", "NativeTextBoxDemo", "Brush.TextBox", "", "" ],
[ "TextBox", "TextBoxDemo", "Brush.TextBox", "", "" ],
[ "ComboBox", "NativeComboBoxDemo", "Brush.ComboBox", "", "" ],
[ "PasswordBox", "NativePasswordBoxDemo", "Brush.PasswordBox", "", "" ],
[ "Expander", "ExpanderDemo", "Brush.Expander", "", "" ],
@@ -11,6 +11,12 @@
<AssemblyName>HandyControlDemo</AssemblyName>
<RootNamespace>HandyControlDemo</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<NoWarn>1701;1702;NETSDK1138</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<NoWarn>1701;1702;NETSDK1138</NoWarn>
</PropertyGroup>
<ItemGroup>
<None Remove="Data\DemoInfo.json" />
@@ -0,0 +1,90 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:hc="https://handyorg.github.io/handycontrol"
mc:Ignorable="d"
d:DesignWidth="800"
d:DesignHeight="450"
x:Class="HandyControlDemo.UserControl.TextBoxDemo">
<ScrollViewer>
<hc:UniformSpacingPanel Spacing="32"
Margin="32"
ChildWrapping="Wrap">
<StackPanel>
<TextBox Text="This is the content" />
<TextBox Text="This is the content"
Margin="0,16,0,0"
IsEnabled="False" />
<TextBox hc:TitleElement.Title="This is the title"
Theme="{StaticResource TextBoxExtend}"
Margin="0,32,0,0"
Text="This is the content" />
<TextBox hc:TitleElement.Title="This is the title"
Theme="{StaticResource TextBoxExtend}"
Margin="0,16,0,0"
Text="This is the content"
IsEnabled="False" />
<TextBox Watermark="please enter email"
hc:TitleElement.Title="This item must be filled in"
Theme="{StaticResource TextBoxExtend}"
hc:InfoElement.Necessary="True"
Margin="0,16,0,0" />
<TextBox Width="380"
hc:TitleElement.TitleWidth="120"
hc:TitleElement.TitlePlacement="Left"
hc:TitleElement.Title="The title is on the left"
Theme="{StaticResource TextBoxExtend}"
Margin="0,32,0,0"
Text="This is the content" />
<TextBox Width="380"
hc:TitleElement.TitleWidth="120"
Watermark="Please enter content"
hc:TitleElement.TitlePlacement="Left"
hc:TitleElement.Title="The title is on the left"
hc:InfoElement.Necessary="True"
Theme="{StaticResource TextBoxExtend}"
Margin="0,16,0,0" />
</StackPanel>
<StackPanel>
<TextBox Text="This is the content"
Theme="{StaticResource TextBox.Small}" />
<TextBox Text="This is the content"
Margin="0,16,0,0"
IsEnabled="False"
Theme="{StaticResource TextBox.Small}" />
<TextBox hc:TitleElement.Title="This is the title"
Theme="{StaticResource TextBoxExtend.Small}"
Margin="0,32,0,0"
Text="This is the content" />
<TextBox hc:TitleElement.Title="This is the title"
Theme="{StaticResource TextBoxExtend.Small}"
Margin="0,16,0,0"
Text="This is the content"
IsEnabled="False" />
<TextBox Watermark="please enter email"
hc:TitleElement.Title="This item must be filled in"
Theme="{StaticResource TextBoxExtend.Small}"
hc:InfoElement.Necessary="True"
Margin="0,16,0,0" />
<TextBox Width="380"
hc:TitleElement.TitleWidth="120"
hc:TitleElement.TitlePlacement="Left"
hc:TitleElement.Title="The title is on the left"
Theme="{StaticResource TextBoxExtend.Small}"
Margin="0,32,0,0"
Text="This is the content" />
<TextBox Width="380"
hc:TitleElement.TitleWidth="120"
Watermark="Please enter content"
hc:TitleElement.TitlePlacement="Left"
hc:TitleElement.Title="The title is on the left"
hc:InfoElement.Necessary="True"
Theme="{StaticResource TextBoxExtend.Small}"
Margin="0,16,0,0" />
</StackPanel>
</hc:UniformSpacingPanel>
</ScrollViewer>
</UserControl>
@@ -0,0 +1,10 @@
namespace HandyControlDemo.UserControl;
public partial class TextBoxDemo : Avalonia.Controls.UserControl
{
public TextBoxDemo()
{
InitializeComponent();
}
}
@@ -0,0 +1,63 @@
using Avalonia;
namespace HandyControl.Controls;
public class InfoElement
{
public static readonly AttachedProperty<bool> NecessaryProperty =
AvaloniaProperty.RegisterAttached<InfoElement, AvaloniaObject, bool>("Necessary", inherits: true);
public static void SetNecessary(AvaloniaObject element, bool value) => element.SetValue(NecessaryProperty, value);
public static bool GetNecessary(AvaloniaObject element) => element.GetValue(NecessaryProperty);
public static readonly AttachedProperty<object> SymbolProperty =
AvaloniaProperty.RegisterAttached<InfoElement, AvaloniaObject, object>("Symbol", inherits: true);
public static void SetSymbol(AvaloniaObject element, object value) => element.SetValue(SymbolProperty, value);
public static object GetSymbol(AvaloniaObject element) => element.GetValue(SymbolProperty);
public static readonly AttachedProperty<double> ContentHeightProperty =
AvaloniaProperty.RegisterAttached<InfoElement, AvaloniaObject, double>("ContentHeight", defaultValue: 28,
inherits: true);
public static void SetContentHeight(AvaloniaObject element, double value) =>
element.SetValue(ContentHeightProperty, value);
public static double GetContentHeight(AvaloniaObject element) => element.GetValue(ContentHeightProperty);
public static readonly AttachedProperty<double> MinContentHeightProperty =
AvaloniaProperty.RegisterAttached<InfoElement, AvaloniaObject, double>("MinContentHeight", defaultValue: 28,
inherits: true);
public static void SetMinContentHeight(AvaloniaObject element, double value) =>
element.SetValue(MinContentHeightProperty, value);
public static double GetMinContentHeight(AvaloniaObject element) => element.GetValue(MinContentHeightProperty);
public static readonly AttachedProperty<double> MaxContentHeightProperty =
AvaloniaProperty.RegisterAttached<InfoElement, AvaloniaObject, double>("MaxContentHeight",
defaultValue: double.PositiveInfinity);
public static void SetMaxContentHeight(AvaloniaObject element, double value) =>
element.SetValue(MaxContentHeightProperty, value);
public static double GetMaxContentHeight(AvaloniaObject element) => element.GetValue(MaxContentHeightProperty);
public static readonly AttachedProperty<string> RegexPatternProperty =
AvaloniaProperty.RegisterAttached<InfoElement, AvaloniaObject, string>("RegexPattern");
public static void SetRegexPattern(AvaloniaObject element, string value) =>
element.SetValue(RegexPatternProperty, value);
public static string GetRegexPattern(AvaloniaObject element) => element.GetValue(RegexPatternProperty);
public static readonly AttachedProperty<bool> ShowClearButtonProperty =
AvaloniaProperty.RegisterAttached<InfoElement, AvaloniaObject, bool>("ShowClearButton");
public static void SetShowClearButton(AvaloniaObject element, bool value) =>
element.SetValue(ShowClearButtonProperty, value);
public static bool GetShowClearButton(AvaloniaObject element) => element.GetValue(ShowClearButtonProperty);
}
@@ -0,0 +1,53 @@
using Avalonia;
using Avalonia.Controls;
namespace HandyControl.Controls;
public class TextBlockAttach
{
public static readonly AttachedProperty<bool> AutoTooltipProperty =
AvaloniaProperty.RegisterAttached<TextBlockAttach, AvaloniaObject, bool>("AutoTooltip", defaultValue: false);
public static void SetAutoTooltip(AvaloniaObject element, bool value) =>
element.SetValue(AutoTooltipProperty, value);
public static bool GetAutoTooltip(AvaloniaObject element) => element.GetValue(AutoTooltipProperty);
static TextBlockAttach()
{
AutoTooltipProperty.Changed.AddClassHandler<AvaloniaObject>(OnAutoTooltipChanged);
}
private static void OnAutoTooltipChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
{
if (d is not TextBlock ctl)
{
return;
}
if (e.GetNewValue<bool>())
{
UpdateTooltip(ctl);
ctl.SizeChanged += TextBlock_SizeChanged;
}
else
{
ctl.SizeChanged -= TextBlock_SizeChanged;
}
}
private static void TextBlock_SizeChanged(object? sender, SizeChangedEventArgs e)
{
if (sender is TextBlock textBlock)
{
UpdateTooltip(textBlock);
}
}
private static void UpdateTooltip(TextBlock textBlock)
{
textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
double width = textBlock.DesiredSize.Width - textBlock.Margin.Left - textBlock.Margin.Right;
ToolTip.SetTip(textBlock, textBlock.Bounds.Width > width ? textBlock.Text : null);
}
}
@@ -1,17 +1,19 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Layout;
using Avalonia.Media;
using HandyControl.Data;
namespace HandyControl.Controls;
public class TitleElement
{
public static readonly AttachedProperty<IBrush?> BorderBrushProperty =
AvaloniaProperty.RegisterAttached<TitleElement, AvaloniaObject, IBrush?>("BorderBrush", inherits: true);
public static readonly AttachedProperty<string> TitleProperty =
AvaloniaProperty.RegisterAttached<TitleElement, AvaloniaObject, string>("Title");
public static void SetBorderBrush(AvaloniaObject element, IBrush? value) =>
element.SetValue(BorderBrushProperty, value);
public static void SetTitle(AvaloniaObject element, string value) => element.SetValue(TitleProperty, value);
public static IBrush? GetBorderBrush(AvaloniaObject element) => element.GetValue(BorderBrushProperty);
public static string GetTitle(AvaloniaObject element) => element.GetValue(TitleProperty);
public static readonly AttachedProperty<IBrush?> BackgroundProperty =
AvaloniaProperty.RegisterAttached<TitleElement, AvaloniaObject, IBrush?>("Background", inherits: true);
@@ -28,4 +30,81 @@ public class TitleElement
element.SetValue(ForegroundProperty, value);
public static IBrush? GetForeground(AvaloniaObject element) => element.GetValue(ForegroundProperty);
public static readonly AttachedProperty<IBrush?> BorderBrushProperty =
AvaloniaProperty.RegisterAttached<TitleElement, AvaloniaObject, IBrush?>("BorderBrush", inherits: true);
public static void SetBorderBrush(AvaloniaObject element, IBrush? value) =>
element.SetValue(BorderBrushProperty, value);
public static IBrush? GetBorderBrush(AvaloniaObject element) => element.GetValue(BorderBrushProperty);
public static readonly AttachedProperty<TitlePlacementType> TitlePlacementProperty =
AvaloniaProperty.RegisterAttached<TitleElement, AvaloniaObject, TitlePlacementType>("TitlePlacement",
defaultValue: TitlePlacementType.Top, inherits: true);
public static void SetTitlePlacement(AvaloniaObject element, TitlePlacementType value) =>
element.SetValue(TitlePlacementProperty, value);
public static TitlePlacementType GetTitlePlacement(AvaloniaObject element) =>
element.GetValue(TitlePlacementProperty);
public static readonly AttachedProperty<GridLength> TitleWidthProperty =
AvaloniaProperty.RegisterAttached<TitleElement, AvaloniaObject, GridLength>("TitleWidth",
defaultValue: GridLength.Auto, inherits: true);
public static void SetTitleWidth(AvaloniaObject element, GridLength value) =>
element.SetValue(TitleWidthProperty, value);
public static GridLength GetTitleWidth(AvaloniaObject element) => element.GetValue(TitleWidthProperty);
public static readonly AttachedProperty<HorizontalAlignment> HorizontalAlignmentProperty =
AvaloniaProperty.RegisterAttached<TitleElement, AvaloniaObject, HorizontalAlignment>("HorizontalAlignment",
inherits: true);
public static void SetHorizontalAlignment(AvaloniaObject element, HorizontalAlignment value) =>
element.SetValue(HorizontalAlignmentProperty, value);
public static HorizontalAlignment GetHorizontalAlignment(AvaloniaObject element) =>
element.GetValue(HorizontalAlignmentProperty);
public static readonly AttachedProperty<VerticalAlignment> VerticalAlignmentProperty =
AvaloniaProperty.RegisterAttached<TitleElement, AvaloniaObject, VerticalAlignment>("VerticalAlignment",
inherits: true);
public static void SetVerticalAlignment(AvaloniaObject element, VerticalAlignment value) =>
element.SetValue(VerticalAlignmentProperty, value);
public static VerticalAlignment GetVerticalAlignment(AvaloniaObject element) =>
element.GetValue(VerticalAlignmentProperty);
public static readonly AttachedProperty<Thickness> MarginOnTheLeftProperty =
AvaloniaProperty.RegisterAttached<TitleElement, AvaloniaObject, Thickness>("MarginOnTheLeft", inherits: true);
public static void SetMarginOnTheLeft(AvaloniaObject element, Thickness value) =>
element.SetValue(MarginOnTheLeftProperty, value);
public static Thickness GetMarginOnTheLeft(AvaloniaObject element) => element.GetValue(MarginOnTheLeftProperty);
public static readonly AttachedProperty<Thickness> MarginOnTheTopProperty =
AvaloniaProperty.RegisterAttached<TitleElement, AvaloniaObject, Thickness>("MarginOnTheTop", inherits: true);
public static void SetMarginOnTheTop(AvaloniaObject element, Thickness value) =>
element.SetValue(MarginOnTheTopProperty, value);
public static Thickness GetMarginOnTheTop(AvaloniaObject element) => element.GetValue(MarginOnTheTopProperty);
public static readonly AttachedProperty<double> MinHeightProperty =
AvaloniaProperty.RegisterAttached<TitleElement, AvaloniaObject, double>("MinHeight");
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");
public static void SetMinWidth(AvaloniaObject element, double value) => element.SetValue(MinWidthProperty, value);
public static double GetMinWidth(AvaloniaObject element) => element.GetValue(MinWidthProperty);
}
@@ -0,0 +1,7 @@
namespace HandyControl.Data;
public enum TitlePlacementType
{
Left,
Top
}
@@ -107,6 +107,8 @@
<SolidColorBrush x:Key="DarkAccentBrush"
Color="{DynamicResource DarkAccentColor}" />
<SolidColorBrush x:Key="HighlightBrush"
Color="{DynamicResource HighlightColor}" />
<SolidColorBrush x:Key="DarkMaskBrush"
Color="{DynamicResource DarkMaskColor}" />
<SolidColorBrush x:Key="DarkOpacityBrush"
@@ -44,6 +44,7 @@
<Color x:Key="AccentColor">#f8491e</Color>
<Color x:Key="DarkAccentColor">#f8491e</Color>
<Color x:Key="HighlightColor">#783399FF</Color>
<Color x:Key="DarkMaskColor">#20000000</Color>
<Color x:Key="DarkOpacityColor">#40000000</Color>
<system:UInt32 x:Key="BlurGradientValue">2583691263</system:UInt32>
@@ -90,6 +91,7 @@
<Color x:Key="AccentColor">#ff5722</Color>
<Color x:Key="DarkAccentColor">#d43f3a</Color>
<Color x:Key="HighlightColor">#783399FF</Color>
<Color x:Key="DarkMaskColor">#40000000</Color>
<Color x:Key="DarkOpacityColor">#40000000</Color>
<system:UInt32 x:Key="BlurGradientValue">2583691263</system:UInt32>
@@ -9,6 +9,7 @@
<hc:GeometrySpacingConverter x:Key="GeometrySpacingConverter" />
<hc:CornerRadiusSplitConverter x:Key="CornerRadiusSplitConverter" />
<hc:DoubleExpandConverter x:Key="DoubleExpandConverter" />
<hc:Double2GridLengthConverter x:Key="Double2GridLengthConverter" />
<avalonia:StringFormatConverter x:Key="StringFormatConverter" />
<avalonia:MarginMultiplierConverter x:Key="LeftMarginConverter"
Indent="16"
@@ -0,0 +1,292 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:hc="clr-namespace:HandyControl.Controls"
xmlns:system="clr-namespace:System;assembly=System.Runtime">
<ControlTheme x:Key="TextBoxBaseStyle"
TargetType="TextBox">
<Setter Property="hc:TitleElement.MarginOnTheLeft"
Value="0,7,6,0" />
<Setter Property="hc:TitleElement.MarginOnTheTop"
Value="8,0,0,5" />
<Setter Property="hc:TitleElement.HorizontalAlignment"
Value="Left" />
<Setter Property="hc:BorderElement.CornerRadius"
Value="{StaticResource DefaultCornerRadius}" />
<Setter Property="MinHeight"
Value="{StaticResource DefaultControlHeight}" />
<Setter Property="Padding"
Value="{StaticResource DefaultInputPadding}" />
<Setter Property="VerticalContentAlignment"
Value="Center" />
<Setter Property="HorizontalContentAlignment"
Value="Left" />
<Setter Property="Background"
Value="{DynamicResource RegionBrush}" />
<Setter Property="BorderBrush"
Value="{DynamicResource BorderBrush}" />
<Setter Property="Foreground"
Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="BorderThickness"
Value="1" />
<Setter Property="SelectionBrush"
Value="{DynamicResource HighlightBrush}" />
<Setter Property="SelectionForegroundBrush"
Value="{DynamicResource HighlightForegroundBrush}" />
<Setter Property="CaretBrush"
Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="ScrollViewer.IsScrollChainingEnabled"
Value="True" />
<Setter Property="Template">
<ControlTemplate>
<Panel>
<Border x:Name="border"
CornerRadius="{Binding Path=(hc:BorderElement.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}" />
<ScrollViewer Name="PART_ScrollViewer"
AllowAutoHide="{TemplateBinding (ScrollViewer.AllowAutoHide)}"
BringIntoViewOnFocusChange="{TemplateBinding (ScrollViewer.BringIntoViewOnFocusChange)}"
HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
IsScrollChainingEnabled="{TemplateBinding (ScrollViewer.IsScrollChainingEnabled)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
<TextPresenter Name="PART_TextPresenter"
Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
CaretBlinkInterval="{TemplateBinding CaretBlinkInterval}"
CaretBrush="{TemplateBinding CaretBrush}"
CaretIndex="{TemplateBinding CaretIndex}"
LineHeight="{TemplateBinding LineHeight}"
LetterSpacing="{TemplateBinding LetterSpacing}"
PasswordChar="{TemplateBinding PasswordChar}"
RevealPassword="{TemplateBinding RevealPassword}"
SelectionBrush="{TemplateBinding SelectionBrush}"
SelectionEnd="{TemplateBinding SelectionEnd}"
SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"
SelectionStart="{TemplateBinding SelectionStart}"
Text="{TemplateBinding Text,Mode=TwoWay}"
TextAlignment="{TemplateBinding TextAlignment}"
TextWrapping="{TemplateBinding TextWrapping}" />
<ScrollViewer.Styles>
<Style Selector="ScrollContentPresenter#PART_ContentPresenter">
<Setter Property="Cursor"
Value="IBeam" />
</Style>
</ScrollViewer.Styles>
</ScrollViewer>
</Panel>
</ControlTemplate>
</Setter>
<Style Selector="^:disabled">
<Setter Property="Opacity"
Value="0.4" />
</Style>
<Style Selector="^:pointerover /template/ Border#border">
<Setter Property="BorderBrush"
Value="{DynamicResource SecondaryBorderBrush}" />
</Style>
<Style Selector="^:focus">
<Style Selector="^:pointerover /template/ Border#border">
<Setter Property="BorderBrush"
Value="{DynamicResource PrimaryBrush}" />
</Style>
<Setter Property="BorderBrush"
Value="{DynamicResource PrimaryBrush}" />
</Style>
</ControlTheme>
<ControlTemplate x:Key="TextBoxExtendTopTemplate"
TargetType="TextBox">
<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="{Binding Path=(hc:TitleElement.Title), RelativeSource={RelativeSource TemplatedParent},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}}" />
<TextBlock TextWrapping="NoWrap"
TextTrimming="CharacterEllipsis"
Text="{Binding Path=(hc:TitleElement.Title), RelativeSource={RelativeSource TemplatedParent}}" />
</DockPanel>
<Border x:Name="border"
Grid.Row="1"
CornerRadius="{Binding Path=(hc:BorderElement.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}" />
<TextBlock Grid.Row="1"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding Padding}"
IsVisible="{TemplateBinding Text, Converter={x:Static StringConverters.IsNullOrEmpty}}"
HorizontalAlignment="Stretch"
Theme="{StaticResource TextBlockDefaultThiLight}"
Text="{TemplateBinding Watermark}" />
<ScrollViewer Name="PART_ScrollViewer"
Grid.Row="1"
AllowAutoHide="{TemplateBinding (ScrollViewer.AllowAutoHide)}"
BringIntoViewOnFocusChange="{TemplateBinding (ScrollViewer.BringIntoViewOnFocusChange)}"
HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
IsScrollChainingEnabled="{TemplateBinding (ScrollViewer.IsScrollChainingEnabled)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
<TextPresenter Name="PART_TextPresenter"
Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
CaretBlinkInterval="{TemplateBinding CaretBlinkInterval}"
CaretBrush="{TemplateBinding CaretBrush}"
CaretIndex="{TemplateBinding CaretIndex}"
LineHeight="{TemplateBinding LineHeight}"
LetterSpacing="{TemplateBinding LetterSpacing}"
PasswordChar="{TemplateBinding PasswordChar}"
RevealPassword="{TemplateBinding RevealPassword}"
SelectionBrush="{TemplateBinding SelectionBrush}"
SelectionEnd="{TemplateBinding SelectionEnd}"
SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"
SelectionStart="{TemplateBinding SelectionStart}"
Text="{TemplateBinding Text,Mode=TwoWay}"
TextAlignment="{TemplateBinding TextAlignment}"
TextWrapping="{TemplateBinding TextWrapping}" />
<ScrollViewer.Styles>
<Style Selector="ScrollContentPresenter#PART_ContentPresenter">
<Setter Property="Cursor"
Value="IBeam" />
</Style>
</ScrollViewer.Styles>
</ScrollViewer>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="TextBoxExtendLeftTemplate"
TargetType="TextBox">
<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="{Binding Path=(hc:TitleElement.Title), RelativeSource={RelativeSource TemplatedParent},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}}" />
<TextBlock TextWrapping="NoWrap"
TextTrimming="CharacterEllipsis"
Text="{Binding Path=(hc:TitleElement.Title), RelativeSource={RelativeSource TemplatedParent}}" />
</DockPanel>
<Border x:Name="border"
Grid.Column="1"
CornerRadius="{Binding Path=(hc:BorderElement.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}" />
<TextBlock Grid.Column="1"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding Padding}"
IsVisible="{TemplateBinding Text, Converter={x:Static StringConverters.IsNullOrEmpty}}"
HorizontalAlignment="Stretch"
Theme="{StaticResource TextBlockDefaultThiLight}"
Text="{TemplateBinding Watermark}" />
<ScrollViewer Name="PART_ScrollViewer"
Grid.Column="1"
AllowAutoHide="{TemplateBinding (ScrollViewer.AllowAutoHide)}"
BringIntoViewOnFocusChange="{TemplateBinding (ScrollViewer.BringIntoViewOnFocusChange)}"
HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
IsScrollChainingEnabled="{TemplateBinding (ScrollViewer.IsScrollChainingEnabled)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
<TextPresenter Name="PART_TextPresenter"
Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
CaretBlinkInterval="{TemplateBinding CaretBlinkInterval}"
CaretBrush="{TemplateBinding CaretBrush}"
CaretIndex="{TemplateBinding CaretIndex}"
LineHeight="{TemplateBinding LineHeight}"
LetterSpacing="{TemplateBinding LetterSpacing}"
PasswordChar="{TemplateBinding PasswordChar}"
RevealPassword="{TemplateBinding RevealPassword}"
SelectionBrush="{TemplateBinding SelectionBrush}"
SelectionEnd="{TemplateBinding SelectionEnd}"
SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"
SelectionStart="{TemplateBinding SelectionStart}"
Text="{TemplateBinding Text,Mode=TwoWay}"
TextAlignment="{TemplateBinding TextAlignment}"
TextWrapping="{TemplateBinding TextWrapping}" />
<ScrollViewer.Styles>
<Style Selector="ScrollContentPresenter#PART_ContentPresenter">
<Setter Property="Cursor"
Value="IBeam" />
</Style>
</ScrollViewer.Styles>
</ScrollViewer>
</Grid>
</ControlTemplate>
<ControlTheme x:Key="TextBoxExtendBaseStyle"
BasedOn="{StaticResource TextBoxBaseStyle}"
TargetType="TextBox">
<Setter Property="hc:InfoElement.Symbol"
Value="●" />
<Setter Property="hc:InfoElement.ContentHeight"
Value="{x:Static system:Double.NaN}" />
<Setter Property="hc:InfoElement.MinContentHeight"
Value="{StaticResource DefaultControlHeight}" />
<Setter Property="Template"
Value="{StaticResource TextBoxExtendTopTemplate}" />
<Style Selector="^[(hc|TitleElement.TitlePlacement)=Left]">
<Setter Property="Template"
Value="{StaticResource TextBoxExtendLeftTemplate}" />
</Style>
</ControlTheme>
<ControlTheme x:Key="{x:Type TextBox}"
BasedOn="{StaticResource TextBoxBaseStyle}"
TargetType="TextBox" />
<ControlTheme x:Key="TextBox.Small"
BasedOn="{StaticResource TextBoxBaseStyle}"
TargetType="TextBox">
<Setter Property="MinHeight"
Value="20" />
<Setter Property="Padding"
Value="6,0" />
</ControlTheme>
<ControlTheme x:Key="TextBoxExtend"
BasedOn="{StaticResource TextBoxExtendBaseStyle}"
TargetType="TextBox" />
<ControlTheme x:Key="TextBoxExtend.Small"
BasedOn="{StaticResource TextBoxExtend}"
TargetType="TextBox">
<Setter Property="hc:InfoElement.MinContentHeight"
Value="20" />
<Setter Property="hc:InfoElement.ContentHeight"
Value="20" />
<Setter Property="hc:TitleElement.MarginOnTheLeft"
Value="0,3,6,0" />
<Setter Property="hc:TitleElement.MarginOnTheTop"
Value="6,0,0,1" />
<Setter Property="Padding"
Value="6,0" />
<Setter Property="MinHeight"
Value="20" />
</ControlTheme>
</ResourceDictionary>
@@ -35,6 +35,7 @@
<MergeResourceInclude Source="/Themes/Styles/Expander.axaml" />
<MergeResourceInclude Source="/Themes/Styles/ProgressBar.axaml" />
<MergeResourceInclude Source="/Themes/Styles/Calendar.axaml" />
<MergeResourceInclude Source="/Themes/Styles/TextBox.axaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Styles.Resources>
@@ -0,0 +1,29 @@
using System;
using System.Globalization;
using Avalonia.Controls;
using Avalonia.Data.Converters;
namespace HandyControl.Tools.Converter;
public class Double2GridLengthConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is not double doubleValue)
{
return new GridLength(0);
}
if (double.IsNaN(doubleValue) || double.IsInfinity(doubleValue))
{
return new GridLength(1.0, GridUnitType.Star);
}
return new GridLength(doubleValue);
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
@@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
@@ -669,8 +669,8 @@
<data name="HatchBrushGenerator" xml:space="preserve">
<value>HatchBrushGenerator</value>
</data>
<data name="Morphing Animation" xml:space="preserve">
<value>Morphing Animation</value>
<data name="MorphingAnimation" xml:space="preserve">
<value>MorphingAnimation</value>
</data>
<data name="Divider" xml:space="preserve">
<value>Divider</value>
@@ -810,4 +810,4 @@
<data name="ConfettiCannon" xml:space="preserve">
<value>ConfettiCannon</value>
</data>
</root>
</root>
@@ -9,7 +9,7 @@ public class InfoElement : TitleElement
/// 占位符
/// </summary>
public static readonly DependencyProperty PlaceholderProperty = DependencyProperty.RegisterAttached(
"Placeholder", typeof(string), typeof(InfoElement), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.Inherits));
"Placeholder", typeof(string), typeof(InfoElement), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
public static void SetPlaceholder(DependencyObject element, string value) => element.SetValue(PlaceholderProperty, value);
@@ -29,7 +29,7 @@ public class InfoElement : TitleElement
/// 标记
/// </summary>
public static readonly DependencyProperty SymbolProperty = DependencyProperty.RegisterAttached(
"Symbol", typeof(string), typeof(InfoElement), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.Inherits));
"Symbol", typeof(string), typeof(InfoElement), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
public static void SetSymbol(DependencyObject element, string value) => element.SetValue(SymbolProperty, value);
@@ -16,7 +16,7 @@ public class TitleElement
=> (string) element.GetValue(TitleProperty);
public static readonly DependencyProperty BackgroundProperty = DependencyProperty.RegisterAttached(
"Background", typeof(Brush), typeof(TitleElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
"Background", typeof(Brush), typeof(TitleElement), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
public static void SetBackground(DependencyObject element, Brush value)
=> element.SetValue(BackgroundProperty, value);
@@ -25,7 +25,7 @@ public class TitleElement
=> (Brush) element.GetValue(BackgroundProperty);
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.RegisterAttached(
"Foreground", typeof(Brush), typeof(TitleElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
"Foreground", typeof(Brush), typeof(TitleElement), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
public static void SetForeground(DependencyObject element, Brush value)
=> element.SetValue(ForegroundProperty, value);
@@ -34,7 +34,7 @@ public class TitleElement
=> (Brush) element.GetValue(ForegroundProperty);
public static readonly DependencyProperty BorderBrushProperty = DependencyProperty.RegisterAttached(
"BorderBrush", typeof(Brush), typeof(TitleElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
"BorderBrush", typeof(Brush), typeof(TitleElement), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
public static void SetBorderBrush(DependencyObject element, Brush value)
=> element.SetValue(BorderBrushProperty, value);