月更
This commit is contained in:
246
AntDesignWPF/Controls/Alert.cs
Normal file
246
AntDesignWPF/Controls/Alert.cs
Normal file
@@ -0,0 +1,246 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media;
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Alert component for feedback.
|
||||
/// </summary>
|
||||
[ContentProperty("Message")]
|
||||
[TemplatePart(Name = PART_Close, Type = typeof(ButtonBase))]
|
||||
public class Alert : Control
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private const string PART_Close = "PART_Close";
|
||||
|
||||
private ButtonBase close;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public static readonly RoutedEvent ClosingEvent =
|
||||
EventManager.RegisterRoutedEvent("Closing", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Alert));
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when closing the tag.
|
||||
/// </summary>
|
||||
public event RoutedEventHandler Closing
|
||||
{
|
||||
add { AddHandler(ClosingEvent, value); }
|
||||
remove { RemoveHandler(ClosingEvent, value); }
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent ClosedEvent =
|
||||
EventManager.RegisterRoutedEvent("Closed", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Alert));
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a Tag is closed and is no longer visible.
|
||||
/// </summary>
|
||||
public event RoutedEventHandler Closed
|
||||
{
|
||||
add { AddHandler(ClosedEvent, value); }
|
||||
remove { RemoveHandler(ClosedEvent, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty BannerProperty =
|
||||
DependencyProperty.Register("Banner", typeof(bool), typeof(Alert), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets whether to show as banner.
|
||||
/// </summary>
|
||||
public bool Banner
|
||||
{
|
||||
get { return (bool)GetValue(BannerProperty); }
|
||||
set { SetValue(BannerProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ClosableProperty =
|
||||
DependencyProperty.Register("Closable", typeof(bool?), typeof(Alert), new PropertyMetadata(null, OnClosableChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets whether alert can be closed.
|
||||
/// </summary>
|
||||
public bool? Closable
|
||||
{
|
||||
get { return (bool?)GetValue(ClosableProperty); }
|
||||
set { SetValue(ClosableProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnClosableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
(d as Alert).SetCloseButtonVisibility();
|
||||
}
|
||||
|
||||
private void SetCloseButtonVisibility()
|
||||
{
|
||||
if (close != null)
|
||||
{
|
||||
var visible = Closable.HasValue ? Closable.Value : CloseText != null;
|
||||
close.Visibility = visible ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CloseTextProperty =
|
||||
DependencyProperty.Register("CloseText", typeof(object), typeof(Alert), new PropertyMetadata(null, OnCloseTextChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets close text to show.
|
||||
/// </summary>
|
||||
public object CloseText
|
||||
{
|
||||
get { return GetValue(CloseTextProperty); }
|
||||
set { SetValue(CloseTextProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnCloseTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
(d as Alert).SetCloseButton();
|
||||
}
|
||||
|
||||
private void SetCloseButton()
|
||||
{
|
||||
if (close != null)
|
||||
{
|
||||
close.Content = CloseText != null ? CloseText : new Icon() { Type = "close" };
|
||||
}
|
||||
|
||||
SetCloseButtonVisibility();
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DescriptionProperty =
|
||||
DependencyProperty.Register("Description", typeof(object), typeof(Alert), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets additional content of alert.
|
||||
/// </summary>
|
||||
public object Description
|
||||
{
|
||||
get { return GetValue(DescriptionProperty); }
|
||||
set { SetValue(DescriptionProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IconProperty =
|
||||
DependencyProperty.Register("Icon", typeof(string), typeof(Alert), new PropertyMetadata(string.Empty));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the icon type of the alert.
|
||||
/// </summary>
|
||||
public string Icon
|
||||
{
|
||||
get { return (string)GetValue(IconProperty); }
|
||||
set { SetValue(IconProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MessageProperty =
|
||||
DependencyProperty.Register("Message", typeof(object), typeof(Alert), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets content of alert.
|
||||
/// </summary>
|
||||
public object Message
|
||||
{
|
||||
get { return GetValue(MessageProperty); }
|
||||
set { SetValue(MessageProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowIconProperty =
|
||||
DependencyProperty.Register("ShowIcon", typeof(bool), typeof(Alert), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets whether to show icon.
|
||||
/// </summary>
|
||||
public bool ShowIcon
|
||||
{
|
||||
get { return (bool)GetValue(ShowIconProperty); }
|
||||
set { SetValue(ShowIconProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TypeProperty =
|
||||
DependencyProperty.Register("Type", typeof(AlertType), typeof(Alert), new PropertyMetadata(AlertType.Info));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the type of alert.
|
||||
/// </summary>
|
||||
public AlertType Type
|
||||
{
|
||||
get { return (AlertType)GetValue(TypeProperty); }
|
||||
set { SetValue(TypeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IconBrushProperty =
|
||||
DependencyProperty.Register("IconBrush", typeof(Brush), typeof(Alert), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the alert icon brush.
|
||||
/// </summary>
|
||||
public Brush IconBrush
|
||||
{
|
||||
get { return (Brush)GetValue(IconBrushProperty); }
|
||||
set { SetValue(IconBrushProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static Alert()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(Alert), new FrameworkPropertyMetadata(typeof(Alert)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
close = GetTemplateChild(PART_Close) as ButtonBase;
|
||||
|
||||
if (close != null)
|
||||
{
|
||||
Loaded -= OnLoaded;
|
||||
Loaded += OnLoaded;
|
||||
|
||||
close.Click -= OnRaiseClosingEvent;
|
||||
close.Click += OnRaiseClosingEvent;
|
||||
}
|
||||
|
||||
SetCloseButton();
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Closing -= OnClosing;
|
||||
Closing += OnClosing;
|
||||
}
|
||||
|
||||
private void OnRaiseClosingEvent(object sender, RoutedEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
RaiseEvent(new RoutedEventArgs(ClosingEvent, this));
|
||||
}
|
||||
|
||||
private void OnClosing(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SetCurrentValue(VisibilityProperty, Visibility.Collapsed);
|
||||
RaiseEvent(new RoutedEventArgs(ClosedEvent, this));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public enum AlertType : byte
|
||||
{
|
||||
Success, Info, Warning, Error
|
||||
}
|
||||
}
|
||||
67
AntDesignWPF/Controls/AntIcon.cs
Normal file
67
AntDesignWPF/Controls/AntIcon.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// 图标控件
|
||||
/// </summary>
|
||||
public class AntIcon : System.Windows.Controls.Control
|
||||
{
|
||||
private static readonly Lazy<IDictionary<AntIconKey, string>> _dataList
|
||||
= new Lazy<IDictionary<AntIconKey, string>>(AntIconDataFactory.Create);
|
||||
|
||||
static AntIcon()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(AntIcon), new FrameworkPropertyMetadata(typeof(AntIcon)));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty KeyProperty
|
||||
= DependencyProperty.Register(nameof(Key), typeof(AntIconKey), typeof(AntIcon), new PropertyMetadata(default(AntIconKey), KeyPropertyChangedCallback));
|
||||
|
||||
private static void KeyPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
|
||||
=> ((AntIcon)dependencyObject).UpdateData();
|
||||
|
||||
private static readonly DependencyPropertyKey DataPropertyKey
|
||||
= DependencyProperty.RegisterReadOnly(nameof(Data), typeof(string), typeof(AntIcon), new PropertyMetadata(""));
|
||||
|
||||
// ReSharper disable once StaticMemberInGenericType
|
||||
public static readonly DependencyProperty DataProperty = DataPropertyKey.DependencyProperty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the icon to display.
|
||||
/// </summary>
|
||||
public AntIconKey Key
|
||||
{
|
||||
get => (AntIconKey)GetValue(KeyProperty);
|
||||
set => SetValue(KeyProperty, value);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the icon path data for the current <see cref="Key"/>.
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(GeometryConverter))]
|
||||
public string? Data
|
||||
{
|
||||
get => (string?)GetValue(DataProperty);
|
||||
private set => SetValue(DataPropertyKey, value);
|
||||
}
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
UpdateData();
|
||||
}
|
||||
|
||||
private void UpdateData()
|
||||
{
|
||||
string? data = null;
|
||||
_dataList.Value?.TryGetValue(Key, out data);
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
436
AntDesignWPF/Controls/AntIconDataFactory.cs
Normal file
436
AntDesignWPF/Controls/AntIconDataFactory.cs
Normal file
File diff suppressed because one or more lines are too long
456
AntDesignWPF/Controls/AntIconKey.cs
Normal file
456
AntDesignWPF/Controls/AntIconKey.cs
Normal file
@@ -0,0 +1,456 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
public enum AntIconKey
|
||||
{
|
||||
//StepBackward,
|
||||
//StepForward,
|
||||
//FastForward,
|
||||
//FastBackward,
|
||||
//Shrink,
|
||||
//ArrowsAlt,
|
||||
//Left,
|
||||
//Up,
|
||||
//Down,
|
||||
//Right,
|
||||
//CaretRight,
|
||||
//CaretUp,
|
||||
//CaretDown,
|
||||
//CaretLeft,
|
||||
//DownCircle,
|
||||
//RightCircle,
|
||||
//LeftCircle,
|
||||
//UpCircle,
|
||||
//DoubleLeft,
|
||||
//DoubleRight,
|
||||
//VerticalRight,
|
||||
//VerticalLeft,
|
||||
//VerticalAlignTop,
|
||||
//VerticalAlignMiddle,
|
||||
//VerticalAlignBottom,
|
||||
AccountBookOutlined,
|
||||
AimOutlined,
|
||||
AlertOutlined,
|
||||
AlibabaOutlined,
|
||||
AlignCenterOutlined,
|
||||
AlignLeftOutlined,
|
||||
AlignRightOutlined,
|
||||
AlipayCircleOutlined,
|
||||
AlipayOutlined,
|
||||
AliwangwangOutlined,
|
||||
AliyunOutlined,
|
||||
AmazonOutlined,
|
||||
AndroidOutlined,
|
||||
AntCloudOutlined,
|
||||
AntDesignOutlined,
|
||||
ApartmentOutlined,
|
||||
ApiOutlined,
|
||||
AppleOutlined,
|
||||
AppstoreAddOutlined,
|
||||
AppstoreOutlined,
|
||||
AreaChartOutlined,
|
||||
ArrowDownOutlined,
|
||||
ArrowLeftOutlined,
|
||||
ArrowRightOutlined,
|
||||
ArrowsAltOutlined,
|
||||
ArrowUpOutlined,
|
||||
AudioMutedOutlined,
|
||||
AudioOutlined,
|
||||
AuditOutlined,
|
||||
BackwardOutlined,
|
||||
BankOutlined,
|
||||
BarChartOutlined,
|
||||
BarcodeOutlined,
|
||||
BarsOutlined,
|
||||
BehanceOutlined,
|
||||
BehanceSquareOutlined,
|
||||
BellOutlined,
|
||||
BgColorsOutlined,
|
||||
BlockOutlined,
|
||||
BoldOutlined,
|
||||
BookOutlined,
|
||||
BorderBottomOutlined,
|
||||
BorderHorizontalOutlined,
|
||||
BorderInnerOutlined,
|
||||
BorderLeftOutlined,
|
||||
BorderlessTableOutlined,
|
||||
BorderOuterOutlined,
|
||||
BorderOutlined,
|
||||
BorderRightOutlined,
|
||||
BorderTopOutlined,
|
||||
BorderVerticleOutlined,
|
||||
BoxPlotOutlined,
|
||||
BranchesOutlined,
|
||||
BugOutlined,
|
||||
BuildOutlined,
|
||||
BulbOutlined,
|
||||
CalculatorOutlined,
|
||||
CalendarOutlined,
|
||||
CameraOutlined,
|
||||
CaretDownOutlined,
|
||||
CaretLeftOutlined,
|
||||
CaretRightOutlined,
|
||||
CaretUpOutlined,
|
||||
CarOutlined,
|
||||
CarryOutOutlined,
|
||||
CheckCircleOutlined,
|
||||
CheckOutlined,
|
||||
CheckSquareOutlined,
|
||||
ChromeOutlined,
|
||||
CiCircleOutlined,
|
||||
CiOutlined,
|
||||
ClearOutlined,
|
||||
ClockCircleOutlined,
|
||||
CloseCircleOutlined,
|
||||
CloseOutlined,
|
||||
CloseSquareOutlined,
|
||||
CloudDownloadOutlined,
|
||||
CloudOutlined,
|
||||
CloudServerOutlined,
|
||||
CloudSyncOutlined,
|
||||
CloudUploadOutlined,
|
||||
ClusterOutlined,
|
||||
CodeOutlined,
|
||||
CodepenCircleOutlined,
|
||||
CodepenOutlined,
|
||||
CodeSandboxOutlined,
|
||||
CoffeeOutlined,
|
||||
ColumnHeightOutlined,
|
||||
ColumnWidthOutlined,
|
||||
CommentOutlined,
|
||||
CompassOutlined,
|
||||
CompressOutlined,
|
||||
ConsoleSqlOutlined,
|
||||
ContactsOutlined,
|
||||
ContainerOutlined,
|
||||
ControlOutlined,
|
||||
CopyOutlined,
|
||||
CopyrightCircleOutlined,
|
||||
CopyrightOutlined,
|
||||
CreditCardOutlined,
|
||||
CrownOutlined,
|
||||
CustomerServiceOutlined,
|
||||
DashboardOutlined,
|
||||
DashOutlined,
|
||||
DatabaseOutlined,
|
||||
DeleteColumnOutlined,
|
||||
DeleteOutlined,
|
||||
DeleteRowOutlined,
|
||||
DeliveredProcedureOutlined,
|
||||
DeploymentUnitOutlined,
|
||||
DesktopOutlined,
|
||||
DiffOutlined,
|
||||
DingdingOutlined,
|
||||
DingtalkOutlined,
|
||||
DisconnectOutlined,
|
||||
DislikeOutlined,
|
||||
DollarCircleOutlined,
|
||||
DollarOutlined,
|
||||
DotChartOutlined,
|
||||
DoubleLeftOutlined,
|
||||
DoubleRightOutlined,
|
||||
DownCircleOutlined,
|
||||
DownloadOutlined,
|
||||
DownOutlined,
|
||||
DownSquareOutlined,
|
||||
DragOutlined,
|
||||
DribbbleOutlined,
|
||||
DribbbleSquareOutlined,
|
||||
DropboxOutlined,
|
||||
EditOutlined,
|
||||
EllipsisOutlined,
|
||||
EnterOutlined,
|
||||
EnvironmentOutlined,
|
||||
EuroCircleOutlined,
|
||||
EuroOutlined,
|
||||
ExceptionOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
ExclamationOutlined,
|
||||
ExpandAltOutlined,
|
||||
ExpandOutlined,
|
||||
ExperimentOutlined,
|
||||
ExportOutlined,
|
||||
EyeInvisibleOutlined,
|
||||
EyeOutlined,
|
||||
FacebookOutlined,
|
||||
FallOutlined,
|
||||
FastBackwardOutlined,
|
||||
FastForwardOutlined,
|
||||
FieldBinaryOutlined,
|
||||
FieldNumberOutlined,
|
||||
FieldStringOutlined,
|
||||
FieldTimeOutlined,
|
||||
FileAddOutlined,
|
||||
FileDoneOutlined,
|
||||
FileExcelOutlined,
|
||||
FileExclamationOutlined,
|
||||
FileGifOutlined,
|
||||
FileImageOutlined,
|
||||
FileJpgOutlined,
|
||||
FileMarkdownOutlined,
|
||||
FileOutlined,
|
||||
FilePdfOutlined,
|
||||
FilePptOutlined,
|
||||
FileProtectOutlined,
|
||||
FileSearchOutlined,
|
||||
FileSyncOutlined,
|
||||
FileTextOutlined,
|
||||
FileUnknownOutlined,
|
||||
FileWordOutlined,
|
||||
FileZipOutlined,
|
||||
FilterOutlined,
|
||||
FireOutlined,
|
||||
FlagOutlined,
|
||||
FolderAddOutlined,
|
||||
FolderOpenOutlined,
|
||||
FolderOutlined,
|
||||
FolderViewOutlined,
|
||||
FontColorsOutlined,
|
||||
FontSizeOutlined,
|
||||
ForkOutlined,
|
||||
FormatPainterOutlined,
|
||||
FormOutlined,
|
||||
ForwardOutlined,
|
||||
FrownOutlined,
|
||||
FullscreenExitOutlined,
|
||||
FullscreenOutlined,
|
||||
FunctionOutlined,
|
||||
FundOutlined,
|
||||
FundProjectionScreenOutlined,
|
||||
FundViewOutlined,
|
||||
FunnelPlotOutlined,
|
||||
GatewayOutlined,
|
||||
GifOutlined,
|
||||
GiftOutlined,
|
||||
GithubOutlined,
|
||||
GitlabOutlined,
|
||||
GlobalOutlined,
|
||||
GoldOutlined,
|
||||
GoogleOutlined,
|
||||
GooglePlusOutlined,
|
||||
GroupOutlined,
|
||||
HddOutlined,
|
||||
HeartOutlined,
|
||||
HeatMapOutlined,
|
||||
HighlightOutlined,
|
||||
HistoryOutlined,
|
||||
HomeOutlined,
|
||||
HourglassOutlined,
|
||||
Html5Outlined,
|
||||
IdcardOutlined,
|
||||
IeOutlined,
|
||||
ImportOutlined,
|
||||
InboxOutlined,
|
||||
InfoCircleOutlined,
|
||||
InfoOutlined,
|
||||
InsertRowAboveOutlined,
|
||||
InsertRowBelowOutlined,
|
||||
InsertRowLeftOutlined,
|
||||
InsertRowRightOutlined,
|
||||
InstagramOutlined,
|
||||
InsuranceOutlined,
|
||||
InteractionOutlined,
|
||||
IssuesCloseOutlined,
|
||||
ItalicOutlined,
|
||||
KeyOutlined,
|
||||
LaptopOutlined,
|
||||
LayoutOutlined,
|
||||
LeftCircleOutlined,
|
||||
LeftOutlined,
|
||||
LeftSquareOutlined,
|
||||
LikeOutlined,
|
||||
LineChartOutlined,
|
||||
LineHeightOutlined,
|
||||
LineOutlined,
|
||||
LinkedinOutlined,
|
||||
LinkOutlined,
|
||||
Loading3QuartersOutlined,
|
||||
LoadingOutlined,
|
||||
LockOutlined,
|
||||
LoginOutlined,
|
||||
LogoutOutlined,
|
||||
MacCommandOutlined,
|
||||
MailOutlined,
|
||||
ManOutlined,
|
||||
MedicineBoxOutlined,
|
||||
MediumOutlined,
|
||||
MediumWorkmarkOutlined,
|
||||
MehOutlined,
|
||||
MenuFoldOutlined,
|
||||
MenuOutlined,
|
||||
MenuUnfoldOutlined,
|
||||
MergeCellsOutlined,
|
||||
MessageOutlined,
|
||||
MinusCircleOutlined,
|
||||
MinusOutlined,
|
||||
MinusSquareOutlined,
|
||||
MobileOutlined,
|
||||
MoneyCollectOutlined,
|
||||
MonitorOutlined,
|
||||
MoreOutlined,
|
||||
NodeCollapseOutlined,
|
||||
NodeExpandOutlined,
|
||||
NodeIndexOutlined,
|
||||
NotificationOutlined,
|
||||
NumberOutlined,
|
||||
OneToOneOutlined,
|
||||
OrderedListOutlined,
|
||||
PaperClipOutlined,
|
||||
PartitionOutlined,
|
||||
PauseCircleOutlined,
|
||||
PauseOutlined,
|
||||
PayCircleOutlined,
|
||||
PercentageOutlined,
|
||||
PhoneOutlined,
|
||||
PicCenterOutlined,
|
||||
PicLeftOutlined,
|
||||
PicRightOutlined,
|
||||
PictureOutlined,
|
||||
PieChartOutlined,
|
||||
PlayCircleOutlined,
|
||||
PlaySquareOutlined,
|
||||
PlusCircleOutlined,
|
||||
PlusOutlined,
|
||||
PlusSquareOutlined,
|
||||
PoundCircleOutlined,
|
||||
PoundOutlined,
|
||||
PoweroffOutlined,
|
||||
PrinterOutlined,
|
||||
ProfileOutlined,
|
||||
ProjectOutlined,
|
||||
PropertySafetyOutlined,
|
||||
PullRequestOutlined,
|
||||
PushpinOutlined,
|
||||
QqOutlined,
|
||||
QrcodeOutlined,
|
||||
QuestionCircleOutlined,
|
||||
QuestionOutlined,
|
||||
RadarChartOutlined,
|
||||
RadiusBottomleftOutlined,
|
||||
RadiusBottomrightOutlined,
|
||||
RadiusSettingOutlined,
|
||||
RadiusUpleftOutlined,
|
||||
RadiusUprightOutlined,
|
||||
ReadOutlined,
|
||||
ReconciliationOutlined,
|
||||
RedditOutlined,
|
||||
RedEnvelopeOutlined,
|
||||
RedoOutlined,
|
||||
ReloadOutlined,
|
||||
RestOutlined,
|
||||
RetweetOutlined,
|
||||
RightCircleOutlined,
|
||||
RightOutlined,
|
||||
RightSquareOutlined,
|
||||
RiseOutlined,
|
||||
RobotOutlined,
|
||||
RocketOutlined,
|
||||
RollbackOutlined,
|
||||
RotateLeftOutlined,
|
||||
RotateRightOutlined,
|
||||
SafetyCertificateOutlined,
|
||||
SafetyOutlined,
|
||||
SaveOutlined,
|
||||
ScanOutlined,
|
||||
ScheduleOutlined,
|
||||
ScissorOutlined,
|
||||
SearchOutlined,
|
||||
SecurityScanOutlined,
|
||||
SelectOutlined,
|
||||
SendOutlined,
|
||||
SettingOutlined,
|
||||
ShakeOutlined,
|
||||
ShareAltOutlined,
|
||||
ShopOutlined,
|
||||
ShoppingCartOutlined,
|
||||
ShoppingOutlined,
|
||||
ShrinkOutlined,
|
||||
SisternodeOutlined,
|
||||
SketchOutlined,
|
||||
SkinOutlined,
|
||||
SkypeOutlined,
|
||||
SlackOutlined,
|
||||
SlackSquareOutlined,
|
||||
SlidersOutlined,
|
||||
SmallDashOutlined,
|
||||
SmileOutlined,
|
||||
SnippetsOutlined,
|
||||
SolutionOutlined,
|
||||
SortAscendingOutlined,
|
||||
SortDescendingOutlined,
|
||||
SoundOutlined,
|
||||
SplitCellsOutlined,
|
||||
StarOutlined,
|
||||
StockOutlined,
|
||||
StopOutlined,
|
||||
StrikethroughOutlined,
|
||||
SubnodeOutlined,
|
||||
SwapLeftOutlined,
|
||||
SwapOutlined,
|
||||
SwapRightOutlined,
|
||||
SwitcherOutlined,
|
||||
SyncOutlined,
|
||||
TableOutlined,
|
||||
TabletOutlined,
|
||||
TagOutlined,
|
||||
TagsOutlined,
|
||||
TaobaoCircleOutlined,
|
||||
TaobaoOutlined,
|
||||
TeamOutlined,
|
||||
ThunderboltOutlined,
|
||||
ToolOutlined,
|
||||
ToTopOutlined,
|
||||
TrademarkCircleOutlined,
|
||||
TrademarkOutlined,
|
||||
TransactionOutlined,
|
||||
TranslationOutlined,
|
||||
TrophyOutlined,
|
||||
TwitterOutlined,
|
||||
UnderlineOutlined,
|
||||
UndoOutlined,
|
||||
UngroupOutlined,
|
||||
UnlockOutlined,
|
||||
UnorderedListOutlined,
|
||||
UpCircleOutlined,
|
||||
UploadOutlined,
|
||||
UpOutlined,
|
||||
UpSquareOutlined,
|
||||
UsbOutlined,
|
||||
UserAddOutlined,
|
||||
UserDeleteOutlined,
|
||||
UsergroupAddOutlined,
|
||||
UsergroupDeleteOutlined,
|
||||
UserOutlined,
|
||||
UserSwitchOutlined,
|
||||
Vector,
|
||||
VerifiedOutlined,
|
||||
VerticalAlignMiddleOutlined,
|
||||
VerticalAlignTopOutlined,
|
||||
VerticalLeftOutlined,
|
||||
VerticalRightOutlined,
|
||||
VideoCameraAddOutlined,
|
||||
VideoCameraOutlined,
|
||||
WalletOutlined,
|
||||
WarningOutlined,
|
||||
WechatOutlined,
|
||||
WeiboCircleOutlined,
|
||||
WeiboOutlined,
|
||||
WeiboSquareOutlined,
|
||||
WhatsAppOutlined,
|
||||
WifiOutlined,
|
||||
WindowsOutlined,
|
||||
WomanOutlined,
|
||||
YahooOutlined,
|
||||
YoutubeOutlined,
|
||||
YuqueOutlined,
|
||||
ZhihuOutlined,
|
||||
ZoomInOutlined,
|
||||
ZoomOutOutlined,
|
||||
|
||||
}
|
||||
}
|
||||
748
AntDesignWPF/Controls/AntdBorder.cs
Normal file
748
AntDesignWPF/Controls/AntdBorder.cs
Normal file
@@ -0,0 +1,748 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using AntDesign.WPF.Utils;
|
||||
|
||||
namespace AntDesign.WPF.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// Draws a border, background, or both around another element.
|
||||
/// </summary>
|
||||
public class AntdBorder : Decorator
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private StreamGeometry backgroundGeometryCache;
|
||||
|
||||
private StreamGeometry upperLeftCache;
|
||||
|
||||
private StreamGeometry upperRightCache;
|
||||
|
||||
private StreamGeometry lowerRightCache;
|
||||
|
||||
private StreamGeometry lowerLeftCache;
|
||||
|
||||
private bool useComplexRender;
|
||||
|
||||
private Pen leftPenCache;
|
||||
|
||||
private Pen topPenCache;
|
||||
|
||||
private Pen rightPenCache;
|
||||
|
||||
private Pen bottomPenCache;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register(
|
||||
"Background",
|
||||
typeof(Brush),
|
||||
typeof(AntdBorder),
|
||||
new FrameworkPropertyMetadata(
|
||||
null,
|
||||
FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender
|
||||
));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the brush that fills the area between the bounds of a Border.
|
||||
/// </summary>
|
||||
public Brush Background
|
||||
{
|
||||
get { return (Brush)GetValue(BackgroundProperty); }
|
||||
set { SetValue(BackgroundProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BorderBrushProperty = DependencyProperty.Register(
|
||||
"BorderBrush",
|
||||
typeof(Brush),
|
||||
typeof(AntdBorder),
|
||||
new FrameworkPropertyMetadata(
|
||||
null,
|
||||
FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
|
||||
OnClearPenCache
|
||||
));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the brush that draws the outer border color.
|
||||
/// </summary>
|
||||
public Brush BorderBrush
|
||||
{
|
||||
get { return (Brush)GetValue(BorderBrushProperty); }
|
||||
set { SetValue(BorderBrushProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BorderThicknessProperty = DependencyProperty.Register(
|
||||
"BorderThickness",
|
||||
typeof(Thickness),
|
||||
typeof(AntdBorder),
|
||||
new FrameworkPropertyMetadata(
|
||||
new Thickness(),
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender,
|
||||
OnClearPenCache
|
||||
),
|
||||
IsThicknessValid);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the relative thickness of a border.
|
||||
/// </summary>
|
||||
public Thickness BorderThickness
|
||||
{
|
||||
get { return (Thickness)GetValue(BorderThicknessProperty); }
|
||||
set { SetValue(BorderThicknessProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnClearPenCache(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var border = (AntdBorder)d;
|
||||
border.leftPenCache = border.topPenCache = border.rightPenCache = border.bottomPenCache = null;
|
||||
}
|
||||
|
||||
private static bool IsThicknessValid(object value)
|
||||
{
|
||||
return ThicknessUtil.IsValid((Thickness)value, false, false, false, false);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(
|
||||
"CornerRadius",
|
||||
typeof(CornerRadius),
|
||||
typeof(AntdBorder),
|
||||
new FrameworkPropertyMetadata(
|
||||
new CornerRadius(),
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender
|
||||
),
|
||||
IsCornerRadiusValid);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that represents the degree to which the corners of a Border are rounded.
|
||||
/// </summary>
|
||||
public CornerRadius CornerRadius
|
||||
{
|
||||
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
|
||||
set { SetValue(CornerRadiusProperty, value); }
|
||||
}
|
||||
|
||||
private static bool IsCornerRadiusValid(object value)
|
||||
{
|
||||
return CornerRadiusUtil.IsValid((CornerRadius)value, false, false, false, false);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty PaddingProperty = DependencyProperty.Register(
|
||||
"Padding",
|
||||
typeof(Thickness),
|
||||
typeof(AntdBorder),
|
||||
new FrameworkPropertyMetadata(
|
||||
new Thickness(),
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender
|
||||
),
|
||||
IsThicknessValid);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a thickness value that describes the amount of space between a border and its child element.
|
||||
/// </summary>
|
||||
public Thickness Padding
|
||||
{
|
||||
get { return (Thickness)GetValue(PaddingProperty); }
|
||||
set { SetValue(PaddingProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BorderStyleProperty = DependencyProperty.Register(
|
||||
"BorderStyle",
|
||||
typeof(BorderStyle),
|
||||
typeof(AntdBorder),
|
||||
new FrameworkPropertyMetadata(
|
||||
BorderStyle.Solid,
|
||||
FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
|
||||
OnClearPenCache
|
||||
));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the border style.
|
||||
/// </summary>
|
||||
public BorderStyle BorderStyle
|
||||
{
|
||||
get { return (BorderStyle)GetValue(BorderStyleProperty); }
|
||||
set { SetValue(BorderStyleProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
|
||||
/// <summary>
|
||||
/// Updates DesiredSize of the Border. Called by parent UIElement. This is the first pass of layout.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Border determines its desired size it needs from the specified border the child: its sizing
|
||||
/// properties, margin, and requested size.
|
||||
/// </remarks>
|
||||
/// <param name="constraint">Constraint size is an "upper limit" that the return value should not exceed.</param>
|
||||
/// <returns>The Decorator's desired size.</returns>
|
||||
protected override Size MeasureOverride(Size constraint)
|
||||
{
|
||||
var child = Child;
|
||||
var desiredSize = new Size();
|
||||
var borders = BorderThickness;
|
||||
|
||||
if (UseLayoutRounding)
|
||||
{
|
||||
var dpi = DpiUtil.GetDpi(this);
|
||||
borders = new Thickness(UIElementUtil.RoundLayoutValue(borders.Left, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Top, dpi.DpiScaleY),
|
||||
UIElementUtil.RoundLayoutValue(borders.Right, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Bottom, dpi.DpiScaleY));
|
||||
}
|
||||
|
||||
// Compute the total size required
|
||||
var borderSize = ThicknessUtil.CollapseThickness(borders);
|
||||
var paddingSize = ThicknessUtil.CollapseThickness(Padding);
|
||||
|
||||
// If we have a child
|
||||
if (child != null)
|
||||
{
|
||||
// Combine into total decorating size
|
||||
var combined = new Size(borderSize.Width + paddingSize.Width, borderSize.Height + paddingSize.Height);
|
||||
|
||||
// Remove size of border only from child's reference size.
|
||||
var childConstraint = new Size(Math.Max(0.0, constraint.Width - combined.Width),
|
||||
Math.Max(0.0, constraint.Height - combined.Height));
|
||||
|
||||
|
||||
child.Measure(childConstraint);
|
||||
var childSize = child.DesiredSize;
|
||||
|
||||
// Now use the returned size to drive our size, by adding back the margins, etc.
|
||||
desiredSize.Width = childSize.Width + combined.Width;
|
||||
desiredSize.Height = childSize.Height + combined.Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Combine into total decorating size
|
||||
desiredSize = new Size(borderSize.Width + paddingSize.Width, borderSize.Height + paddingSize.Height);
|
||||
}
|
||||
|
||||
return desiredSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Border computes the position of its single child and applies its child's alignments to the child.
|
||||
/// </summary>
|
||||
/// <param name="finalSize">The size reserved for this element by the parent</param>
|
||||
/// <returns>The actual ink area of the element, typically the same as finalSize</returns>
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
var borders = BorderThickness;
|
||||
|
||||
if (UseLayoutRounding)
|
||||
{
|
||||
var dpi = DpiUtil.GetDpi(this);
|
||||
borders = new Thickness(UIElementUtil.RoundLayoutValue(borders.Left, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Top, dpi.DpiScaleY),
|
||||
UIElementUtil.RoundLayoutValue(borders.Right, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Bottom, dpi.DpiScaleY));
|
||||
}
|
||||
|
||||
var boundRect = new Rect(finalSize);
|
||||
var innerRect = RectUtil.Deflate(boundRect, borders);
|
||||
|
||||
// arrange child
|
||||
var child = Child;
|
||||
if (child != null)
|
||||
{
|
||||
Rect childRect = RectUtil.Deflate(innerRect, Padding);
|
||||
child.Arrange(childRect);
|
||||
}
|
||||
|
||||
var radius = CornerRadius;
|
||||
|
||||
useComplexRender = !CornerRadiusUtil.IsUniform(radius) || !ThicknessUtil.IsUniform(borders);
|
||||
backgroundGeometryCache = upperLeftCache = upperRightCache = lowerRightCache = lowerLeftCache = null;
|
||||
|
||||
if (useComplexRender)
|
||||
{
|
||||
// calculate border / background rendering geometry
|
||||
if (!DoubleUtil.IsZero(boundRect.Width) && !DoubleUtil.IsZero(boundRect.Height))
|
||||
{
|
||||
var outerRadii = new Radii(boundRect, radius, borders, true);
|
||||
|
||||
// Upper-right corner
|
||||
var radiusX = boundRect.TopRight.X - outerRadii.TopRight.X;
|
||||
var radiusY = outerRadii.RightTop.Y - boundRect.TopRight.Y;
|
||||
if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
|
||||
{
|
||||
upperRightCache = GenerateRoundedGeometry(outerRadii.TopRight, outerRadii.RightTop, new Size(radiusX, radiusY));
|
||||
}
|
||||
|
||||
// Lower-right corner
|
||||
radiusX = boundRect.BottomRight.X - outerRadii.BottomRight.X;
|
||||
radiusY = boundRect.BottomRight.Y - outerRadii.RightBottom.Y;
|
||||
if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
|
||||
{
|
||||
lowerRightCache = GenerateRoundedGeometry(outerRadii.RightBottom, outerRadii.BottomRight, new Size(radiusX, radiusY));
|
||||
}
|
||||
|
||||
// Lower-left corner
|
||||
radiusX = outerRadii.BottomLeft.X - boundRect.BottomLeft.X;
|
||||
radiusY = boundRect.BottomLeft.Y - outerRadii.LeftBottom.Y;
|
||||
if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
|
||||
{
|
||||
lowerLeftCache = GenerateRoundedGeometry(outerRadii.BottomLeft, outerRadii.LeftBottom, new Size(radiusX, radiusY));
|
||||
}
|
||||
|
||||
// Upper-left corner
|
||||
radiusX = outerRadii.TopLeft.X - boundRect.TopLeft.X;
|
||||
radiusY = outerRadii.LeftTop.Y - boundRect.TopLeft.Y;
|
||||
if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
|
||||
{
|
||||
upperLeftCache = GenerateRoundedGeometry(outerRadii.LeftTop, outerRadii.TopLeft, new Size(radiusX, radiusY));
|
||||
}
|
||||
}
|
||||
|
||||
if (!DoubleUtil.IsZero(innerRect.Width) && !DoubleUtil.IsZero(innerRect.Height))
|
||||
{
|
||||
var innerRadii = new Radii(innerRect, radius, borders, false);
|
||||
var backgroundGeometry = new StreamGeometry();
|
||||
|
||||
using (StreamGeometryContext sc = backgroundGeometry.Open())
|
||||
{
|
||||
// create the border geometry
|
||||
sc.BeginFigure(innerRadii.TopLeft, true /* is filled */, true /* is closed */);
|
||||
|
||||
// Top line
|
||||
sc.LineTo(innerRadii.TopRight, true /* is stroked */, false /* is smooth join */);
|
||||
|
||||
// Upper-right corners
|
||||
var radiusX = innerRect.TopRight.X - innerRadii.TopRight.X;
|
||||
var radiusY = innerRadii.RightTop.Y - innerRect.TopRight.Y;
|
||||
if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
|
||||
{
|
||||
sc.ArcTo(innerRadii.RightTop, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
|
||||
}
|
||||
|
||||
// Right line
|
||||
sc.LineTo(innerRadii.RightBottom, true /* is stroked */, false /* is smooth join */);
|
||||
|
||||
// Lower-right corners
|
||||
radiusX = innerRect.BottomRight.X - innerRadii.BottomRight.X;
|
||||
radiusY = innerRect.BottomRight.Y - innerRadii.RightBottom.Y;
|
||||
if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
|
||||
{
|
||||
sc.ArcTo(innerRadii.BottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
|
||||
}
|
||||
|
||||
// Bottom line
|
||||
sc.LineTo(innerRadii.BottomLeft, true /* is stroked */, false /* is smooth join */);
|
||||
|
||||
// Lower-left corners
|
||||
radiusX = innerRadii.BottomLeft.X - innerRect.BottomLeft.X;
|
||||
radiusY = innerRect.BottomLeft.Y - innerRadii.LeftBottom.Y;
|
||||
if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
|
||||
{
|
||||
sc.ArcTo(innerRadii.LeftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
|
||||
}
|
||||
|
||||
// Left line
|
||||
sc.LineTo(innerRadii.LeftTop, true /* is stroked */, false /* is smooth join */);
|
||||
|
||||
// Upper-left corners
|
||||
radiusX = innerRadii.TopLeft.X - innerRect.TopLeft.X;
|
||||
radiusY = innerRadii.LeftTop.Y - innerRect.TopLeft.Y;
|
||||
if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
|
||||
{
|
||||
sc.ArcTo(innerRadii.TopLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
backgroundGeometry.Freeze();
|
||||
backgroundGeometryCache = backgroundGeometry;
|
||||
}
|
||||
}
|
||||
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext dc)
|
||||
{
|
||||
if (useComplexRender)
|
||||
{
|
||||
ComplexRender(dc);
|
||||
} else
|
||||
{
|
||||
SimpleRender(dc);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void SimpleRender(DrawingContext dc)
|
||||
{
|
||||
var useLayoutRounding = UseLayoutRounding;
|
||||
var dpi = DpiUtil.GetDpi(this);
|
||||
|
||||
Brush brush;
|
||||
var borderStyle = BorderStyle;
|
||||
|
||||
var borders = BorderThickness;
|
||||
var cornerRadius = CornerRadius;
|
||||
|
||||
var outerCornerRadius = cornerRadius.TopLeft; // Already validated that all corners have the same radius
|
||||
var roundedCorners = !DoubleUtil.IsZero(outerCornerRadius);
|
||||
|
||||
var width = RenderSize.Width;
|
||||
var height = RenderSize.Height;
|
||||
|
||||
// Draw border
|
||||
if (!ThicknessUtil.IsZero(borders) && (brush = BorderBrush) != null)
|
||||
{
|
||||
var pen = GetPen(brush, borderStyle, borders.Left, dpi.DpiScaleX, useLayoutRounding);
|
||||
var penThickness = pen.Thickness;
|
||||
|
||||
double x = penThickness * 0.5;
|
||||
var rect = new Rect(x, x, width - penThickness, height - penThickness);
|
||||
|
||||
if (roundedCorners)
|
||||
{
|
||||
dc.DrawRoundedRectangle(null, pen, rect, outerCornerRadius, outerCornerRadius);
|
||||
}
|
||||
else
|
||||
{
|
||||
dc.DrawRectangle(null, pen, rect);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw background in rectangle inside border.
|
||||
if ((brush = Background) != null)
|
||||
{
|
||||
// Intialize background
|
||||
Point ptTL, ptBR;
|
||||
|
||||
if (useLayoutRounding)
|
||||
{
|
||||
ptTL = new Point(UIElementUtil.RoundLayoutValue(borders.Left, dpi.DpiScaleX),
|
||||
UIElementUtil.RoundLayoutValue(borders.Top, dpi.DpiScaleY));
|
||||
ptBR = new Point(width - UIElementUtil.RoundLayoutValue(borders.Right, dpi.DpiScaleX),
|
||||
height - UIElementUtil.RoundLayoutValue(borders.Bottom, dpi.DpiScaleY));
|
||||
}
|
||||
else
|
||||
{
|
||||
ptTL = new Point(borders.Left, borders.Top);
|
||||
ptBR = new Point(width - borders.Right, height - borders.Bottom);
|
||||
}
|
||||
|
||||
// Do not draw background if the borders are so large that they overlap.
|
||||
if (ptBR.X > ptTL.X && ptBR.Y > ptTL.Y)
|
||||
{
|
||||
if (roundedCorners)
|
||||
{
|
||||
// Determine the inner edge radius
|
||||
var innerCornerRadius = Math.Max(0.0, outerCornerRadius - borders.Top * 0.5);
|
||||
dc.DrawRoundedRectangle(brush, null, new Rect(ptTL, ptBR), innerCornerRadius, innerCornerRadius);
|
||||
}
|
||||
else
|
||||
{
|
||||
dc.DrawRectangle(brush, null, new Rect(ptTL, ptBR));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ComplexRender(DrawingContext dc)
|
||||
{
|
||||
Brush brush;
|
||||
var width = RenderSize.Width;
|
||||
var height = RenderSize.Height;
|
||||
|
||||
//Draw border
|
||||
if (!DoubleUtil.IsZero(width) && !DoubleUtil.IsZero(height) && (brush = BorderBrush) != null)
|
||||
{
|
||||
var useLayoutRounding = UseLayoutRounding;
|
||||
var dpi = DpiUtil.GetDpi(this);
|
||||
|
||||
var borders = BorderThickness;
|
||||
var borderStyle = BorderStyle;
|
||||
var radius = CornerRadius;
|
||||
double x, y;
|
||||
|
||||
// Left Line
|
||||
if (!DoubleUtil.IsZero(borders.Left))
|
||||
{
|
||||
if (leftPenCache == null)
|
||||
{
|
||||
leftPenCache = GetPen(brush, borderStyle, borders.Left, dpi.DpiScaleX, useLayoutRounding);
|
||||
}
|
||||
|
||||
x = leftPenCache.Thickness * 0.5;
|
||||
dc.DrawLine(leftPenCache, new Point(x, radius.TopLeft), new Point(x, height - radius.BottomLeft));
|
||||
}
|
||||
|
||||
// Top Line
|
||||
if (!DoubleUtil.IsZero(borders.Top))
|
||||
{
|
||||
if (topPenCache == null)
|
||||
{
|
||||
topPenCache = GetPen(brush, borderStyle, borders.Top, dpi.DpiScaleY, useLayoutRounding);
|
||||
}
|
||||
|
||||
y = topPenCache.Thickness * 0.5;
|
||||
dc.DrawLine(topPenCache, new Point(radius.TopLeft, y), new Point(width - radius.TopRight, y));
|
||||
}
|
||||
|
||||
// Right Line
|
||||
if (!DoubleUtil.IsZero(borders.Right))
|
||||
{
|
||||
if (rightPenCache == null)
|
||||
{
|
||||
rightPenCache = GetPen(brush, borderStyle, borders.Right, dpi.DpiScaleX, useLayoutRounding);
|
||||
}
|
||||
|
||||
x = width - rightPenCache.Thickness * 0.5;
|
||||
dc.DrawLine(rightPenCache, new Point(x, radius.TopRight), new Point(x, height - radius.BottomRight));
|
||||
}
|
||||
|
||||
// Bottom Line
|
||||
if (!DoubleUtil.IsZero(borders.Bottom))
|
||||
{
|
||||
if (bottomPenCache == null)
|
||||
{
|
||||
bottomPenCache = GetPen(brush, borderStyle, borders.Bottom, dpi.DpiScaleY, useLayoutRounding);
|
||||
}
|
||||
|
||||
y = height - bottomPenCache.Thickness * 0.5;
|
||||
dc.DrawLine(bottomPenCache, new Point(radius.BottomLeft, y), new Point(width - radius.BottomRight, y));
|
||||
}
|
||||
|
||||
// Draw Rounded
|
||||
Pen pen;
|
||||
|
||||
if (upperLeftCache != null && (pen = GetMaxPen(leftPenCache, topPenCache)) != null)
|
||||
{
|
||||
dc.DrawGeometry(null, pen, upperLeftCache);
|
||||
}
|
||||
|
||||
if (upperRightCache != null && (pen = GetMaxPen(topPenCache, rightPenCache)) != null)
|
||||
{
|
||||
dc.DrawGeometry(null, pen, upperRightCache);
|
||||
}
|
||||
|
||||
if (lowerRightCache != null && (pen = GetMaxPen(rightPenCache, bottomPenCache)) != null)
|
||||
{
|
||||
dc.DrawGeometry(null, pen, lowerRightCache);
|
||||
}
|
||||
|
||||
if (lowerLeftCache != null && (pen = GetMaxPen(bottomPenCache, leftPenCache)) != null)
|
||||
{
|
||||
dc.DrawGeometry(null, pen, lowerLeftCache);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw background in rectangle inside border.
|
||||
if (backgroundGeometryCache != null && (brush = Background) != null)
|
||||
{
|
||||
dc.DrawGeometry(brush, null, backgroundGeometryCache);
|
||||
}
|
||||
}
|
||||
|
||||
private Pen GetMaxPen(Pen pen1, Pen pen2)
|
||||
{
|
||||
if (pen2 == null || (pen1 != null && pen2.Thickness < pen1.Thickness))
|
||||
{
|
||||
return pen1;
|
||||
}
|
||||
|
||||
return pen2;
|
||||
}
|
||||
|
||||
private static StreamGeometry GenerateRoundedGeometry(Point startPoint, Point endPoint, Size size)
|
||||
{
|
||||
var streamGeometry = new StreamGeometry();
|
||||
|
||||
using (StreamGeometryContext sc = streamGeometry.Open())
|
||||
{
|
||||
sc.BeginFigure(startPoint, true, false);
|
||||
sc.ArcTo(endPoint, size, 0, false, SweepDirection.Clockwise, true, false);
|
||||
}
|
||||
|
||||
streamGeometry.Freeze();
|
||||
return streamGeometry;
|
||||
}
|
||||
|
||||
private static Pen GetPen(Brush brush, BorderStyle borderStyle, double thickness, double dpi, bool useLayoutRounding)
|
||||
{
|
||||
var pen = new Pen
|
||||
{
|
||||
Brush = brush,
|
||||
DashCap = PenLineCap.Flat,
|
||||
Thickness = useLayoutRounding ? UIElementUtil.RoundLayoutValue(thickness, dpi) : thickness,
|
||||
};
|
||||
|
||||
switch (borderStyle)
|
||||
{
|
||||
case BorderStyle.Dotted:
|
||||
pen.DashStyle = new DashStyle(new double[] { 1 }, 0d);
|
||||
break;
|
||||
case BorderStyle.Dashed:
|
||||
pen.DashStyle = new DashStyle(new double[] { 4, 2 }, 0d);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (brush.IsFrozen)
|
||||
{
|
||||
pen.Freeze();
|
||||
}
|
||||
|
||||
return pen;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Structures Classes
|
||||
|
||||
private struct Radii
|
||||
{
|
||||
#region Fields
|
||||
|
||||
internal readonly Point LeftTop;
|
||||
|
||||
internal readonly Point LeftBottom;
|
||||
|
||||
internal readonly Point TopLeft;
|
||||
|
||||
internal readonly Point TopRight;
|
||||
|
||||
internal readonly Point RightTop;
|
||||
|
||||
internal readonly Point RightBottom;
|
||||
|
||||
internal readonly Point BottomRight;
|
||||
|
||||
internal readonly Point BottomLeft;
|
||||
|
||||
#endregion
|
||||
|
||||
internal Radii(Rect rect, CornerRadius radius, Thickness borders, bool outer)
|
||||
{
|
||||
var left = borders.Left * 0.5;
|
||||
var top = borders.Top * 0.5;
|
||||
var right = borders.Right * 0.5;
|
||||
var bottom = borders.Bottom * 0.5;
|
||||
|
||||
LeftTop = new Point(0d, 0d);
|
||||
LeftBottom = new Point(0d, rect.Height);
|
||||
|
||||
TopLeft = new Point(0d, 0d);
|
||||
TopRight = new Point(rect.Width, 0d);
|
||||
|
||||
RightTop = new Point(rect.Width, 0d);
|
||||
RightBottom = new Point(rect.Width, rect.Height);
|
||||
|
||||
BottomRight = new Point(rect.Width, rect.Height);
|
||||
BottomLeft = new Point(0d, rect.Height);
|
||||
|
||||
if (outer)
|
||||
{
|
||||
LeftTop.X = left;
|
||||
LeftBottom.X = left;
|
||||
|
||||
TopLeft.Y = top;
|
||||
TopRight.Y = top;
|
||||
|
||||
RightTop.X -= right;
|
||||
RightBottom.X -= right;
|
||||
|
||||
BottomLeft.Y -= bottom;
|
||||
BottomRight.Y -= bottom;
|
||||
|
||||
if (!DoubleUtil.IsZero(radius.TopLeft))
|
||||
{
|
||||
TopLeft.X = radius.TopLeft; // + left;
|
||||
LeftTop.Y = radius.TopLeft;// + top;
|
||||
}
|
||||
|
||||
if (!DoubleUtil.IsZero(radius.TopRight))
|
||||
{
|
||||
RightTop.Y = radius.TopRight;// + top;
|
||||
TopRight.X -= radius.TopRight;// + right;
|
||||
}
|
||||
|
||||
if (!DoubleUtil.IsZero(radius.BottomRight))
|
||||
{
|
||||
BottomRight.X -= radius.BottomRight;// + right;
|
||||
RightBottom.Y -= radius.BottomRight;// + bottom; ;
|
||||
}
|
||||
|
||||
if (!DoubleUtil.IsZero(radius.BottomLeft))
|
||||
{
|
||||
LeftBottom.Y -= radius.BottomLeft; // + bottom;
|
||||
BottomLeft.X = radius.BottomLeft;// + left;
|
||||
}
|
||||
} else
|
||||
{
|
||||
TopLeft.X = Math.Max(0.0, radius.TopLeft - left);
|
||||
LeftTop.Y = Math.Max(0.0, radius.TopLeft - top);
|
||||
|
||||
RightTop.Y = Math.Max(0.0, radius.TopRight - top);
|
||||
TopRight.X -= Math.Max(0.0, radius.TopRight - right);
|
||||
|
||||
BottomRight.X -= Math.Max(0.0, radius.BottomRight - right);
|
||||
RightBottom.Y -= Math.Max(0.0, radius.BottomRight - bottom);
|
||||
|
||||
LeftBottom.Y -= Math.Max(0.0, radius.BottomLeft - bottom);
|
||||
BottomLeft.X = Math.Max(0.0, radius.BottomLeft - left);
|
||||
}
|
||||
|
||||
// check keypoints for overlap and resolve by partitioning corners according to
|
||||
// the percentage of each one.
|
||||
|
||||
// top edge
|
||||
if (TopLeft.X > TopRight.X)
|
||||
{
|
||||
var v = TopLeft.X / (TopLeft.X + rect.Width - TopRight.X) * rect.Width;
|
||||
TopLeft.X = v;
|
||||
TopRight.X = v;
|
||||
}
|
||||
|
||||
// right edge
|
||||
if (RightTop.Y > RightBottom.Y)
|
||||
{
|
||||
var v = RightTop.Y / (RightTop.Y + rect.Height - RightBottom.Y) * rect.Height;
|
||||
RightTop.Y = v;
|
||||
RightBottom.Y = v;
|
||||
}
|
||||
|
||||
// bottom edge
|
||||
if (BottomRight.X < BottomLeft.X)
|
||||
{
|
||||
var v = BottomLeft.X / (BottomLeft.X + rect.Width - BottomRight.X) * rect.Width;
|
||||
BottomRight.X = v;
|
||||
BottomLeft.X = v;
|
||||
}
|
||||
|
||||
// left edge
|
||||
if (LeftBottom.Y < LeftTop.Y)
|
||||
{
|
||||
var v = LeftTop.Y / (LeftTop.Y + rect.Height - LeftBottom.Y) * rect.Height;
|
||||
LeftBottom.Y = v;
|
||||
LeftTop.Y = v;
|
||||
}
|
||||
|
||||
// Apply offset
|
||||
var offset = new Vector(rect.TopLeft.X, rect.TopLeft.Y);
|
||||
|
||||
LeftTop += offset;
|
||||
LeftBottom += offset;
|
||||
|
||||
TopRight += offset;
|
||||
TopLeft += offset;
|
||||
|
||||
RightTop += offset;
|
||||
RightBottom += offset;
|
||||
|
||||
BottomRight += offset;
|
||||
BottomLeft += offset;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Structures Classes
|
||||
}
|
||||
39
AntDesignWPF/Controls/AntdContentControl.cs
Normal file
39
AntDesignWPF/Controls/AntdContentControl.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
public class AntdContentControl : ContentControl
|
||||
{
|
||||
public static readonly DependencyProperty ContentCharacterCasingProperty =
|
||||
DependencyProperty.Register("ContentCharacterCasing", typeof(CharacterCasing), typeof(AntdContentControl),
|
||||
new FrameworkPropertyMetadata(CharacterCasing.Normal, FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsMeasure),
|
||||
value => CharacterCasing.Normal <= (CharacterCasing)value && (CharacterCasing)value <= CharacterCasing.Upper);
|
||||
|
||||
/// <summary>
|
||||
/// Character casing of the Content
|
||||
/// </summary>
|
||||
public CharacterCasing ContentCharacterCasing
|
||||
{
|
||||
get { return (CharacterCasing)GetValue(ContentCharacterCasingProperty); }
|
||||
set { SetValue(ContentCharacterCasingProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty RecognizesAccessKeyProperty =
|
||||
DependencyProperty.Register("RecognizesAccessKey", typeof(bool), typeof(AntdContentControl), new FrameworkPropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// Determine if the inner ContentPresenter should use AccessText in its style
|
||||
/// </summary>
|
||||
public bool RecognizesAccessKey
|
||||
{
|
||||
get { return (bool)GetValue(RecognizesAccessKeyProperty); }
|
||||
set { SetValue(RecognizesAccessKeyProperty, value); }
|
||||
}
|
||||
|
||||
static AntdContentControl()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(AntdContentControl), new FrameworkPropertyMetadata(typeof(AntdContentControl)));
|
||||
}
|
||||
}
|
||||
}
|
||||
718
AntDesignWPF/Controls/AntdWindow.cs
Normal file
718
AntDesignWPF/Controls/AntdWindow.cs
Normal file
@@ -0,0 +1,718 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using AntDesign.WPF.Contracts;
|
||||
using AntDesign.WPF.Microsoft.Windows.Shell;
|
||||
using AntDesign.WPF.Win32;
|
||||
using Standard;
|
||||
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
|
||||
|
||||
[TemplatePart(Name = PART_TitleBarThumb, Type = typeof(Thumb))]
|
||||
[TemplatePart(Name = PART_TitleBar, Type = typeof(UIElement))]
|
||||
[TemplatePart(Name = PART_Icon, Type = typeof(FrameworkElement))]
|
||||
[TemplatePart(Name = PART_LeftWindowCommands, Type = typeof(WindowCommands))]
|
||||
[TemplatePart(Name = PART_Title, Type = typeof(UIElement))]
|
||||
[TemplatePart(Name = PART_RightWindowCommands, Type = typeof(WindowCommands))]
|
||||
[TemplatePart(Name = PART_WindowButtons, Type = typeof(WindowButtons))]
|
||||
public class AntdWindow : Window
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private const string PART_TitleBarThumb = "PART_TitleBarThumb";
|
||||
|
||||
private const string PART_TitleBar = "PART_TitleBar";
|
||||
|
||||
private const string PART_Icon = "PART_Icon";
|
||||
|
||||
private const string PART_LeftWindowCommands = "PART_LeftWindowCommands";
|
||||
|
||||
private const string PART_Title = "PART_Title";
|
||||
|
||||
private const string PART_RightWindowCommands = "PART_RightWindowCommands";
|
||||
|
||||
private const string PART_WindowButtons = "PART_WindowButtons";
|
||||
|
||||
private Thumb titleBarThumb;
|
||||
|
||||
private UIElement titleBar;
|
||||
|
||||
private FrameworkElement icon;
|
||||
|
||||
internal ContentPresenter leftWindowCommands;
|
||||
|
||||
private UIElement title;
|
||||
|
||||
internal ContentPresenter rightWindowCommands;
|
||||
|
||||
internal ContentPresenter windowButtons;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty IgnoreTaskbarProperty =
|
||||
DependencyProperty.Register("IgnoreTaskbar", typeof(bool), typeof(AntdWindow), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets whether the window will ignore (and overlap) the taskbar when maximized.
|
||||
/// </summary>
|
||||
public bool IgnoreTaskbar
|
||||
{
|
||||
get { return (bool)GetValue(IgnoreTaskbarProperty); }
|
||||
set { SetValue(IgnoreTaskbarProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowSystemMenuProperty =
|
||||
DependencyProperty.Register("ShowSystemMenu", typeof(bool), typeof(AntdWindow), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets if the the system menu should popup on right click.
|
||||
/// </summary>
|
||||
public bool ShowSystemMenu
|
||||
{
|
||||
get { return (bool)GetValue(ShowSystemMenuProperty); }
|
||||
set { SetValue(ShowSystemMenuProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsDraggableProperty =
|
||||
DependencyProperty.Register("IsDraggable", typeof(bool), typeof(AntdWindow), new PropertyMetadata(true));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets if the the allow drag window
|
||||
/// </summary>
|
||||
public bool IsDraggable
|
||||
{
|
||||
get { return (bool)GetValue(IsDraggableProperty); }
|
||||
set { SetValue(IsDraggableProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty UseNoneWindowStyleProperty =
|
||||
DependencyProperty.Register("UseNoneWindowStyle", typeof(bool), typeof(AntdWindow), new PropertyMetadata(false, OnUseNoneWindowStyleChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets whether the WindowStyle is None or not.
|
||||
/// </summary>
|
||||
public bool UseNoneWindowStyle
|
||||
{
|
||||
get { return (bool)GetValue(UseNoneWindowStyleProperty); }
|
||||
set { SetValue(UseNoneWindowStyleProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnUseNoneWindowStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.NewValue != e.OldValue)
|
||||
{
|
||||
(d as AntdWindow).ToggleNoneWindowStyle((bool)e.NewValue);
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleNoneWindowStyle(bool useNoneWindowStyle)
|
||||
{
|
||||
SetVisibiltyForTitleBarElements(!useNoneWindowStyle && TitleBarHeight > 0);
|
||||
}
|
||||
|
||||
protected IntPtr CriticalHandle
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = typeof(Window).GetProperty("CriticalHandle", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this, new object[0]);
|
||||
return (IntPtr)value;
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TitleBarHeightProperty =
|
||||
DependencyProperty.Register("TitleBarHeight", typeof(double), typeof(AntdWindow), new PropertyMetadata(30d, OnTitleBarHeightChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TitleBar height.
|
||||
/// </summary>
|
||||
public double TitleBarHeight
|
||||
{
|
||||
get { return (double)GetValue(TitleBarHeightProperty); }
|
||||
set { SetValue(TitleBarHeightProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnTitleBarHeightChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var window = (AntdWindow)dependencyObject;
|
||||
if (e.NewValue != e.OldValue)
|
||||
{
|
||||
window.SetVisibiltyForTitleBarElements((int)e.NewValue > 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TitleBarForegroundProperty =
|
||||
DependencyProperty.Register("TitleBarForeground", typeof(Brush), typeof(AntdWindow));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the foreground brush of the title bar.
|
||||
/// </summary>
|
||||
public Brush TitleBarForeground
|
||||
{
|
||||
get { return (Brush)GetValue(TitleBarForegroundProperty); }
|
||||
set { SetValue(TitleBarForegroundProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TitleBarBackgroundProperty =
|
||||
DependencyProperty.Register("TitleBarBackground", typeof(Brush), typeof(AntdWindow), new PropertyMetadata(Brushes.Transparent));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the background brush of the title bar.
|
||||
/// </summary>
|
||||
public Brush TitleBarBackground
|
||||
{
|
||||
get { return (Brush)GetValue(TitleBarBackgroundProperty); }
|
||||
set { SetValue(TitleBarBackgroundProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowIconProperty =
|
||||
DependencyProperty.Register("ShowIcon", typeof(bool), typeof(AntdWindow), new PropertyMetadata(true, OnShowIconChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets whether the titlebar icon is visible or not.
|
||||
/// </summary>
|
||||
public bool ShowIcon
|
||||
{
|
||||
get { return (bool)GetValue(ShowIconProperty); }
|
||||
set { SetValue(ShowIconProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnShowIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.NewValue != e.OldValue)
|
||||
{
|
||||
(d as AntdWindow).SetVisibiltyForIcon();
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IconTemplateProperty =
|
||||
DependencyProperty.Register("IconTemplate", typeof(DataTemplate), typeof(AntdWindow), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the icon content template to show a custom icon.
|
||||
/// </summary>
|
||||
public DataTemplate IconTemplate
|
||||
{
|
||||
get { return (DataTemplate)GetValue(IconTemplateProperty); }
|
||||
set { SetValue(IconTemplateProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TitleCharacterCasingProperty =
|
||||
DependencyProperty.Register("TitleCharacterCasing", typeof(CharacterCasing), typeof(AntdWindow),
|
||||
new FrameworkPropertyMetadata(CharacterCasing.Normal, FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsMeasure),
|
||||
value => CharacterCasing.Normal <= (CharacterCasing)value && (CharacterCasing)value <= CharacterCasing.Upper);
|
||||
|
||||
/// <summary>
|
||||
/// Character casing of the title
|
||||
/// </summary>
|
||||
public CharacterCasing TitleCharacterCasing
|
||||
{
|
||||
get { return (CharacterCasing)GetValue(TitleCharacterCasingProperty); }
|
||||
set { SetValue(TitleCharacterCasingProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TitleAlignmentProperty =
|
||||
DependencyProperty.Register("TitleAlignment", typeof(HorizontalAlignment), typeof(AntdWindow), new PropertyMetadata(HorizontalAlignment.Stretch, OnTitleAlignmentChanged));
|
||||
|
||||
public HorizontalAlignment TitleAlignment
|
||||
{
|
||||
get { return (HorizontalAlignment)GetValue(TitleAlignmentProperty); }
|
||||
set { SetValue(TitleAlignmentProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnTitleAlignmentChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (dependencyObject is AntdWindow window)
|
||||
{
|
||||
window.SizeChanged -= window.OnSizeChanged;
|
||||
|
||||
if ((HorizontalAlignment)e.NewValue == HorizontalAlignment.Center)
|
||||
{
|
||||
window.SizeChanged += window.OnSizeChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TitleTemplateProperty =
|
||||
DependencyProperty.Register("TitleTemplate", typeof(DataTemplate), typeof(AntdWindow), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the title content template to show a custom title.
|
||||
/// </summary>
|
||||
public DataTemplate TitleTemplate
|
||||
{
|
||||
get { return (DataTemplate)GetValue(TitleTemplateProperty); }
|
||||
set { SetValue(TitleTemplateProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LeftWindowCommandsProperty =
|
||||
DependencyProperty.Register("LeftWindowCommands", typeof(WindowCommands), typeof(AntdWindow), new PropertyMetadata(null, UpdateLogicalChilds));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the left window commands that hosts the user commands.
|
||||
/// </summary>
|
||||
public WindowCommands LeftWindowCommands
|
||||
{
|
||||
get { return (WindowCommands)GetValue(LeftWindowCommandsProperty); }
|
||||
set { SetValue(LeftWindowCommandsProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty RightWindowCommandsProperty =
|
||||
DependencyProperty.Register("RightWindowCommands", typeof(WindowCommands), typeof(AntdWindow), new PropertyMetadata(null, UpdateLogicalChilds));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the right window commands that hosts the user commands.
|
||||
/// </summary>
|
||||
public WindowCommands RightWindowCommands
|
||||
{
|
||||
get { return (WindowCommands)GetValue(RightWindowCommandsProperty); }
|
||||
set { SetValue(RightWindowCommandsProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty WindowButtonsProperty =
|
||||
DependencyProperty.Register("WindowButtons", typeof(WindowButtons), typeof(AntdWindow), new PropertyMetadata(null, UpdateLogicalChilds));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the window button commands that hosts the min/max/close commands.
|
||||
/// </summary>
|
||||
public WindowButtons WindowButtons
|
||||
{
|
||||
get { return (WindowButtons)GetValue(WindowButtonsProperty); }
|
||||
set { SetValue(WindowButtonsProperty, value); }
|
||||
}
|
||||
|
||||
private static void UpdateLogicalChilds(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (!(dependencyObject is AntdWindow window))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.OldValue is FrameworkElement oldChild)
|
||||
{
|
||||
window.RemoveLogicalChild(oldChild);
|
||||
}
|
||||
|
||||
if (e.NewValue is FrameworkElement newChild)
|
||||
{
|
||||
window.AddLogicalChild(newChild);
|
||||
// Yes, that's crazy. But we must do this to enable all possible scenarios for setting DataContext
|
||||
// in a Window. Without set the DataContext at this point it can happen that e.g. a Flyout
|
||||
// doesn't get the same DataContext.
|
||||
// So now we can type
|
||||
//
|
||||
// InitializeComponent();
|
||||
// DataContext = new MainViewModel();
|
||||
//
|
||||
// or
|
||||
//
|
||||
// DataContext = new MainViewModel();
|
||||
// InitializeComponent();
|
||||
//
|
||||
newChild.DataContext = window.DataContext;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static AntdWindow()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(AntdWindow), new FrameworkPropertyMetadata(typeof(AntdWindow)));
|
||||
}
|
||||
|
||||
public AntdWindow()
|
||||
{
|
||||
//SetResourceReference(StyleProperty, typeof(AntdWindow));
|
||||
DataContextChanged += OnDataContextChanged;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LogicalTree
|
||||
|
||||
protected override IEnumerator LogicalChildren
|
||||
{
|
||||
get
|
||||
{
|
||||
// cheat, make a list with all logical content and return the enumerator
|
||||
ArrayList children = new ArrayList { Content };
|
||||
|
||||
if (LeftWindowCommands != null)
|
||||
{
|
||||
children.Add(LeftWindowCommands);
|
||||
}
|
||||
|
||||
if (RightWindowCommands != null)
|
||||
{
|
||||
children.Add(RightWindowCommands);
|
||||
}
|
||||
|
||||
if (WindowButtons != null)
|
||||
{
|
||||
children.Add(WindowButtons);
|
||||
}
|
||||
|
||||
return children.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
titleBarThumb = GetTemplateChild(PART_TitleBarThumb) as Thumb;
|
||||
titleBar = GetTemplateChild(PART_TitleBar) as UIElement;
|
||||
icon = GetTemplateChild(PART_Icon) as FrameworkElement;
|
||||
title = GetTemplateChild(PART_Title) as UIElement;
|
||||
|
||||
leftWindowCommands = GetTemplateChild(PART_LeftWindowCommands) as ContentPresenter;
|
||||
rightWindowCommands = GetTemplateChild(PART_RightWindowCommands) as ContentPresenter;
|
||||
windowButtons = GetTemplateChild(PART_WindowButtons) as ContentPresenter;
|
||||
|
||||
if (LeftWindowCommands == null)
|
||||
LeftWindowCommands = new WindowCommands();
|
||||
if (RightWindowCommands == null)
|
||||
RightWindowCommands = new WindowCommands();
|
||||
if (WindowButtons == null)
|
||||
WindowButtons = new WindowButtons();
|
||||
|
||||
LeftWindowCommands.ParentWindow = this;
|
||||
RightWindowCommands.ParentWindow = this;
|
||||
WindowButtons.ParentWindow = this;
|
||||
|
||||
var windowChrome = GetValue(WindowChrome.WindowChromeProperty) as WindowChrome;
|
||||
|
||||
if (windowChrome != null)
|
||||
{
|
||||
BindingOperations.SetBinding(
|
||||
windowChrome,
|
||||
WindowChrome.IgnoreTaskbarProperty,
|
||||
new Binding { Path = new PropertyPath(IgnoreTaskbarProperty), Source = this, Mode = BindingMode.OneWay }
|
||||
);
|
||||
}
|
||||
|
||||
ToggleNoneWindowStyle(UseNoneWindowStyle);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
// add these controls to the window with AddLogicalChild method.
|
||||
// This has the side effect that the DataContext doesn't update, so do this now here.
|
||||
if (LeftWindowCommands != null) LeftWindowCommands.DataContext = DataContext;
|
||||
if (RightWindowCommands != null) RightWindowCommands.DataContext = DataContext;
|
||||
if (WindowButtons != null) WindowButtons.DataContext = DataContext;
|
||||
}
|
||||
|
||||
private void OnSizeChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// this all works only for centered title
|
||||
if (TitleAlignment != HorizontalAlignment.Center) return;
|
||||
|
||||
// Half of this Window
|
||||
var halfDistance = ActualWidth / 2;
|
||||
// Distance between center and left/right
|
||||
var distanceToCenter = title.DesiredSize.Width / 2;
|
||||
// Distance between right edge from LeftWindowCommands to left window side
|
||||
var distanceFromLeft = icon.ActualWidth + LeftWindowCommands.ActualWidth;
|
||||
// Distance between left edge from RightWindowCommands to right window side
|
||||
var distanceFromRight = WindowButtons.ActualWidth + RightWindowCommands.ActualWidth;
|
||||
// Margin
|
||||
const double horizontalMargin = 5.0;
|
||||
|
||||
var dLeft = distanceFromLeft + distanceToCenter + horizontalMargin;
|
||||
var dRight = distanceFromRight + distanceToCenter + horizontalMargin;
|
||||
|
||||
// TODO They should also change when the layout changes.
|
||||
if ((dLeft < halfDistance) && (dRight < halfDistance))
|
||||
{
|
||||
Grid.SetColumn(title, 0);
|
||||
Grid.SetColumnSpan(title, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
Grid.SetColumn(title, 2);
|
||||
Grid.SetColumnSpan(title, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetVisibiltyForTitleBarElements(bool visible)
|
||||
{
|
||||
var value = visible ? Visibility.Visible : Visibility.Collapsed;
|
||||
titleBar?.SetCurrentValue(VisibilityProperty, value);
|
||||
|
||||
title?.SetCurrentValue(VisibilityProperty, value);
|
||||
SetVisibiltyForIcon();
|
||||
|
||||
leftWindowCommands?.SetValue(VisibilityProperty, value);
|
||||
rightWindowCommands?.SetValue(VisibilityProperty, value);
|
||||
|
||||
windowButtons?.SetCurrentValue(VisibilityProperty, value);
|
||||
SetWindowEvents();
|
||||
}
|
||||
|
||||
private void SetVisibiltyForIcon()
|
||||
{
|
||||
if (icon == null) return;
|
||||
icon.Visibility = ShowIcon && !UseNoneWindowStyle && TitleBarHeight > 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private void SetWindowEvents()
|
||||
{
|
||||
// clear all event handlers first
|
||||
ClearWindowEvents();
|
||||
|
||||
// set mouse down/up for icon
|
||||
if (icon != null && icon.Visibility == Visibility.Visible)
|
||||
{
|
||||
icon.MouseLeftButtonDown += OnIconMouseLeftButtonDown;
|
||||
icon.MouseRightButtonUp += OnThumbMouseRightButtonUp;
|
||||
}
|
||||
|
||||
if (titleBarThumb != null)
|
||||
{
|
||||
titleBarThumb.PreviewMouseLeftButtonUp += OnThumbPreviewMouseLeftButtonUp;
|
||||
titleBarThumb.DragDelta += OnThumbDragDelta;
|
||||
titleBarThumb.MouseDoubleClick += OnThumbMouseDoubleClick;
|
||||
titleBarThumb.MouseRightButtonUp += OnThumbMouseRightButtonUp;
|
||||
}
|
||||
|
||||
var thumbContentControl = title as IThumb;
|
||||
|
||||
if (thumbContentControl != null)
|
||||
{
|
||||
thumbContentControl.PreviewMouseLeftButtonUp += OnThumbPreviewMouseLeftButtonUp;
|
||||
thumbContentControl.DragDelta += OnThumbDragDelta;
|
||||
thumbContentControl.MouseDoubleClick += OnThumbMouseDoubleClick;
|
||||
thumbContentControl.MouseRightButtonUp += OnThumbMouseRightButtonUp;
|
||||
}
|
||||
|
||||
// handle size if we have a Grid for the title (e.g. clean window have a centered title)
|
||||
if (title != null && TitleAlignment == HorizontalAlignment.Center)
|
||||
{
|
||||
SizeChanged += OnSizeChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearWindowEvents()
|
||||
{
|
||||
// clear all event handlers first:
|
||||
if (titleBarThumb != null)
|
||||
{
|
||||
titleBarThumb.PreviewMouseLeftButtonUp -= OnThumbPreviewMouseLeftButtonUp;
|
||||
titleBarThumb.DragDelta -= OnThumbDragDelta;
|
||||
titleBarThumb.MouseDoubleClick -= OnThumbMouseDoubleClick;
|
||||
titleBarThumb.MouseRightButtonUp -= OnThumbMouseRightButtonUp;
|
||||
}
|
||||
|
||||
var thumbContentControl = title as IThumb;
|
||||
|
||||
if (thumbContentControl != null)
|
||||
{
|
||||
thumbContentControl.PreviewMouseLeftButtonUp -= OnThumbPreviewMouseLeftButtonUp;
|
||||
thumbContentControl.DragDelta -= OnThumbDragDelta;
|
||||
thumbContentControl.MouseDoubleClick -= OnThumbMouseDoubleClick;
|
||||
thumbContentControl.MouseRightButtonUp -= OnThumbMouseRightButtonUp;
|
||||
}
|
||||
|
||||
if (icon != null)
|
||||
{
|
||||
icon.MouseLeftButtonDown -= OnIconMouseLeftButtonDown;
|
||||
icon.MouseRightButtonUp -= OnThumbMouseRightButtonUp;
|
||||
}
|
||||
|
||||
SizeChanged -= OnSizeChanged;
|
||||
}
|
||||
|
||||
private void OnIconMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (!ShowSystemMenu) return;
|
||||
|
||||
if (e.ClickCount == 2)
|
||||
{
|
||||
Close();
|
||||
} else
|
||||
{
|
||||
System.Windows.SystemCommands.ShowSystemMenu(this, PointToScreen(new Point(0, TitleBarHeight)));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnThumbPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
DoThumbPreviewMouseLeftButtonUp(this, e);
|
||||
}
|
||||
|
||||
private void OnThumbDragDelta(object sender, DragDeltaEventArgs e)
|
||||
{
|
||||
DoThumbDragDelta(sender as IThumb, this, e);
|
||||
}
|
||||
|
||||
private void OnThumbMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
DoThumbMouseDoubleClick(this, e);
|
||||
}
|
||||
|
||||
private void OnThumbMouseRightButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
DoThumbMouseRightButtonUp(this, e);
|
||||
}
|
||||
|
||||
internal static void DoThumbPreviewMouseLeftButtonUp(AntdWindow window, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.Source == e.OriginalSource)
|
||||
{
|
||||
Mouse.Capture(null);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DoThumbDragDelta(IThumb thumb, AntdWindow window, DragDeltaEventArgs e)
|
||||
{
|
||||
if (thumb == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(thumb));
|
||||
}
|
||||
|
||||
if (window == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(window));
|
||||
}
|
||||
|
||||
// drag only if IsDraggable is set to true
|
||||
if (!window.IsDraggable ||
|
||||
(!(Math.Abs(e.HorizontalChange) > 2) && !(Math.Abs(e.VerticalChange) > 2)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// tage from DragMove internal code
|
||||
window.VerifyAccess();
|
||||
|
||||
//var cursorPos = WinApiHelper.GetPhysicalCursorPos();
|
||||
|
||||
// if the window is maximized dragging is only allowed on title bar (also if not visible)
|
||||
var maximized = window.WindowState == WindowState.Maximized;
|
||||
var isMouseOnTitlebar = Mouse.GetPosition(thumb).Y <= window.TitleBarHeight && window.TitleBarHeight > 0;
|
||||
|
||||
if (!isMouseOnTitlebar && maximized) return;
|
||||
|
||||
#pragma warning disable 618
|
||||
// for the touch usage
|
||||
UnsafeNativeMethods.ReleaseCapture();
|
||||
#pragma warning restore 618
|
||||
|
||||
if (maximized)
|
||||
{
|
||||
//var cursorXPos = cursorPos.x;
|
||||
EventHandler windowOnStateChanged = null;
|
||||
windowOnStateChanged = (sender, args) =>
|
||||
{
|
||||
//window.Top = 2;
|
||||
//window.Left = Math.Max(cursorXPos - window.RestoreBounds.Width / 2, 0);
|
||||
|
||||
window.StateChanged -= windowOnStateChanged;
|
||||
if (window.WindowState == WindowState.Normal)
|
||||
{
|
||||
Mouse.Capture(thumb, CaptureMode.Element);
|
||||
}
|
||||
};
|
||||
|
||||
window.StateChanged += windowOnStateChanged;
|
||||
}
|
||||
|
||||
var criticalHandle = window.CriticalHandle;
|
||||
// DragMove works too
|
||||
// window.DragMove();
|
||||
// instead this 2 lines
|
||||
#pragma warning disable 618
|
||||
NativeMethods.SendMessage(criticalHandle, WM.SYSCOMMAND, (IntPtr)SC.MOUSEMOVE, IntPtr.Zero);
|
||||
NativeMethods.SendMessage(criticalHandle, WM.LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
|
||||
#pragma warning restore 618
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change window state on MouseDoubleClick
|
||||
/// </summary>
|
||||
/// <param name="window"></param>
|
||||
/// <param name="e"></param>
|
||||
internal static void DoThumbMouseDoubleClick(AntdWindow window, MouseButtonEventArgs e)
|
||||
{
|
||||
// restore/maximize only with left button
|
||||
if (e.ChangedButton == MouseButton.Left)
|
||||
{
|
||||
// we can maximize or restore the window if the title bar height is set (also if title bar is hidden)
|
||||
var canResize = window.ResizeMode == ResizeMode.CanResizeWithGrip || window.ResizeMode == ResizeMode.CanResize;
|
||||
var mousePos = Mouse.GetPosition(window);
|
||||
var isMouseOnTitlebar = mousePos.Y <= window.TitleBarHeight && window.TitleBarHeight > 0;
|
||||
if (canResize && isMouseOnTitlebar)
|
||||
{
|
||||
if (window.WindowState == WindowState.Normal)
|
||||
{
|
||||
System.Windows.SystemCommands.MaximizeWindow(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Windows.SystemCommands.RestoreWindow(window);
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show system menu on MouseRightButtonUp
|
||||
/// </summary>
|
||||
/// <param name="window"></param>
|
||||
/// <param name="e"></param>
|
||||
internal static void DoThumbMouseRightButtonUp(AntdWindow window, MouseButtonEventArgs e)
|
||||
{
|
||||
if (window.ShowSystemMenu)
|
||||
{
|
||||
// show menu only if mouse pos is on title bar or if we have a window with none style and no title bar
|
||||
var mousePos = e.GetPosition(window);
|
||||
if ((mousePos.Y <= window.TitleBarHeight && window.TitleBarHeight > 0) || (window.UseNoneWindowStyle && window.TitleBarHeight <= 0))
|
||||
{
|
||||
System.Windows.SystemCommands.ShowSystemMenu(window, window.PointToScreen(mousePos));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the template child with the given name.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The interface type inheirted from DependencyObject.</typeparam>
|
||||
/// <param name="name">The name of the template child.</param>
|
||||
internal T GetPart<T>(string name) where T : class
|
||||
{
|
||||
return GetTemplateChild(name) as T;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the template child with the given name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the template child.</param>
|
||||
internal DependencyObject GetPart(string name)
|
||||
{
|
||||
return GetTemplateChild(name);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
256
AntDesignWPF/Controls/Avatar.cs
Normal file
256
AntDesignWPF/Controls/Avatar.cs
Normal file
@@ -0,0 +1,256 @@
|
||||
namespace AntDesign.WPF.Controls;
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media;
|
||||
|
||||
/// <summary>
|
||||
/// Avatars can be used to represent people or objects. It supports images, Icons, or letters.
|
||||
/// </summary>
|
||||
[ContentProperty("Text")]
|
||||
[TemplatePart(Name = "PART_Content", Type = typeof(ContentPresenter))]
|
||||
public class Avatar : Control
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private const string PART_Content = "PART_Content";
|
||||
|
||||
private ContentPresenter contentPresenter;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty IconProperty =
|
||||
DependencyProperty.Register("Icon", typeof(string), typeof(Avatar), new PropertyMetadata(null, OnContentChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the icon type for an icon avatar.
|
||||
/// </summary>
|
||||
public string Icon
|
||||
{
|
||||
get { return (string)GetValue(IconProperty); }
|
||||
set { SetValue(IconProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
(d as Avatar).SetContent(true);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShapeProperty =
|
||||
DependencyProperty.Register("Shape", typeof(Shapes), typeof(Avatar), new PropertyMetadata(Shapes.Circle));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the shape of avatar.
|
||||
/// </summary>
|
||||
public Shapes Shape
|
||||
{
|
||||
get { return (Shapes)GetValue(ShapeProperty); }
|
||||
set { SetValue(ShapeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SizeProperty =
|
||||
DependencyProperty.Register("Size", typeof(Sizes?), typeof(Avatar), new PropertyMetadata(null, OnSizeChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the size of the avatar.
|
||||
/// </summary>
|
||||
public Sizes? Size
|
||||
{
|
||||
get { return (Sizes?)GetValue(SizeProperty); }
|
||||
set { SetValue(SizeProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var avatar = d as Avatar;
|
||||
var newValue = (Sizes?)e.NewValue;
|
||||
var oldValue = (Sizes?)e.OldValue;
|
||||
|
||||
if (newValue.HasValue && newValue.Value >= 0)
|
||||
{
|
||||
var size = (double)newValue.Value;
|
||||
avatar.SetValue(WidthProperty, size);
|
||||
avatar.SetValue(HeightProperty, size);
|
||||
avatar.SetValue(FontSizeProperty, size / 2);
|
||||
}
|
||||
else if (oldValue.HasValue && oldValue.Value >= 0)
|
||||
{
|
||||
avatar.ClearValue(WidthProperty);
|
||||
avatar.ClearValue(HeightProperty);
|
||||
avatar.ClearValue(FontSizeProperty);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SourceProperty =
|
||||
DependencyProperty.Register("Source", typeof(ImageSource), typeof(Avatar), new PropertyMetadata(null, OnContentChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the ImageSource for an image avatar.
|
||||
/// </summary>
|
||||
public ImageSource Source
|
||||
{
|
||||
get { return (ImageSource)GetValue(SourceProperty); }
|
||||
set { SetValue(SourceProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextProperty =
|
||||
DependencyProperty.Register("Text", typeof(string), typeof(Avatar), new PropertyMetadata(string.Empty, OnContentChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the text for an text avatar.
|
||||
/// </summary>
|
||||
public string Text
|
||||
{
|
||||
get { return (string)GetValue(TextProperty); }
|
||||
set { SetValue(TextProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AlternativeProperty =
|
||||
DependencyProperty.Register("Alternative", typeof(string), typeof(Avatar), new PropertyMetadata(string.Empty));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the alternative text describing the image.
|
||||
/// </summary>
|
||||
public string Alternative
|
||||
{
|
||||
get { return (string)GetValue(AlternativeProperty); }
|
||||
set { SetValue(AlternativeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsImageProperty =
|
||||
DependencyProperty.Register("IsImage", typeof(bool), typeof(Avatar), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current avatar type as an image.
|
||||
/// </summary>
|
||||
public bool IsImage
|
||||
{
|
||||
get { return (bool)GetValue(IsImageProperty); }
|
||||
private set { SetValue(IsImageProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static Avatar()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(Avatar), new FrameworkPropertyMetadata(typeof(Avatar)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
contentPresenter = GetTemplateChild(PART_Content) as ContentPresenter;
|
||||
SetContent(true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void SetContent(bool imageExist)
|
||||
{
|
||||
if (contentPresenter == null) return;
|
||||
|
||||
var content = contentPresenter.Content;
|
||||
|
||||
// Clear Event
|
||||
if (content is Image img)
|
||||
{
|
||||
ClearValue(IsImageProperty);
|
||||
img.ImageFailed -= OnImageFailed;
|
||||
}
|
||||
else if (content is TextBlock block)
|
||||
{
|
||||
SizeChanged -= OnTextSizeChanged;
|
||||
block.SizeChanged -= OnTextSizeChanged;
|
||||
}
|
||||
|
||||
if (Source != null && imageExist)
|
||||
{
|
||||
if (content is not Image)
|
||||
{
|
||||
content = new Image();
|
||||
}
|
||||
|
||||
SetCurrentValue(IsImageProperty, true);
|
||||
|
||||
var image = (Image)content;
|
||||
image.Source = Source;
|
||||
|
||||
image.ImageFailed += OnImageFailed;
|
||||
RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.HighQuality);
|
||||
|
||||
}
|
||||
else if (Icon != null)
|
||||
{
|
||||
if (content is not Controls.Icon icon)
|
||||
{
|
||||
content = new Icon();
|
||||
}
|
||||
|
||||
((Icon)content).Type = Icon;
|
||||
}
|
||||
else
|
||||
{
|
||||
var text = string.IsNullOrEmpty(Text) ? (imageExist ? string.Empty : Alternative) : Text;
|
||||
|
||||
if (content is not TextBlock)
|
||||
{
|
||||
content = new TextBlock();
|
||||
}
|
||||
|
||||
var textblock = (TextBlock)content;
|
||||
|
||||
SizeChanged += OnTextSizeChanged;
|
||||
textblock.SizeChanged += OnTextSizeChanged;
|
||||
|
||||
textblock.Text = text;
|
||||
textblock.RenderTransformOrigin = new Point(0.5, 0.5);
|
||||
}
|
||||
|
||||
// 引用传递对 Null 无效
|
||||
contentPresenter.Content = content;
|
||||
}
|
||||
|
||||
private void OnImageFailed(object sender, ExceptionRoutedEventArgs e)
|
||||
{
|
||||
SetContent(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Autoset Font Size
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void OnTextSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (contentPresenter != null && contentPresenter.Content is TextBlock textBlock)
|
||||
{
|
||||
var childrenWidth = textBlock.ActualWidth;
|
||||
var width = ActualWidth - 8;
|
||||
var scale = 1d;
|
||||
var left = 0d;
|
||||
|
||||
if (width < childrenWidth)
|
||||
{
|
||||
scale = width / childrenWidth;
|
||||
left = ActualWidth / 2 - childrenWidth / 2;
|
||||
}
|
||||
|
||||
textBlock.Margin = new Thickness(left, 0d, left, 0d);
|
||||
textBlock.RenderTransform = new ScaleTransform(scale, scale);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
223
AntDesignWPF/Controls/Badge.cs
Normal file
223
AntDesignWPF/Controls/Badge.cs
Normal file
@@ -0,0 +1,223 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using WindowSize = System.Windows.Size;
|
||||
using ContentControlBase = System.Windows.Controls.ContentControl;
|
||||
|
||||
namespace AntDesign.WPF.Controls;
|
||||
|
||||
[TemplatePart(Name = PART_BadgeContainer, Type = typeof(FrameworkElement))]
|
||||
[TemplatePart(Name = PART_Count, Type = typeof(ContentPresenter))]
|
||||
public class Badge : ContentControlBase
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private const string PART_BadgeContainer = "PART_BadgeContainer";
|
||||
|
||||
private const string PART_Count = "PART_Count";
|
||||
|
||||
private FrameworkElement badgeContainer;
|
||||
|
||||
private ContentPresenter count;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty CountProperty =
|
||||
DependencyProperty.Register("Count", typeof(object), typeof(Badge), new PropertyMetadata(null, OnCountChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets number to show in badge
|
||||
/// </summary>
|
||||
public object Count
|
||||
{
|
||||
get { return (object)GetValue(CountProperty); }
|
||||
set { SetValue(CountProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
(d as Badge).ApplyCount();
|
||||
}
|
||||
|
||||
private void ApplyCount()
|
||||
{
|
||||
if (count == null) return;
|
||||
|
||||
var content = Count;
|
||||
|
||||
if (Count is string)
|
||||
{
|
||||
try
|
||||
{
|
||||
var d = int.Parse(Count as string);
|
||||
|
||||
if (d > OverflowCount)
|
||||
{
|
||||
content = OverflowCount + "+";
|
||||
}
|
||||
}
|
||||
catch { } // Swallow the error, it may be normal
|
||||
}
|
||||
|
||||
count.Content = content;
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DotProperty =
|
||||
DependencyProperty.Register("Dot", typeof(bool), typeof(Badge), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets whether to display a red dot instead of count
|
||||
/// </summary>
|
||||
public bool Dot
|
||||
{
|
||||
get { return (bool)GetValue(DotProperty); }
|
||||
set { SetValue(DotProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty OffsetProperty =
|
||||
DependencyProperty.Register("Offset", typeof(Point?), typeof(Badge), new PropertyMetadata(null));
|
||||
|
||||
public Point? Offset
|
||||
{
|
||||
get { return (Point?)GetValue(OffsetProperty); }
|
||||
set { SetValue(OffsetProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty OverflowCountProperty =
|
||||
DependencyProperty.Register("OverflowCount", typeof(int), typeof(Badge), new PropertyMetadata(99, OnCountChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets max count to show
|
||||
/// </summary>
|
||||
public int OverflowCount
|
||||
{
|
||||
get { return (int)GetValue(OverflowCountProperty); }
|
||||
set { SetValue(OverflowCountProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowZeroProperty =
|
||||
DependencyProperty.Register("ShowZero", typeof(bool), typeof(Badge), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets whether to show badge when count is zero
|
||||
/// </summary>
|
||||
public bool ShowZero
|
||||
{
|
||||
get { return (bool)GetValue(ShowZeroProperty); }
|
||||
set { SetValue(ShowZeroProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StatusProperty =
|
||||
DependencyProperty.Register("Status", typeof(BadgeStatus?), typeof(Badge), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets badge as a status dot
|
||||
/// </summary>
|
||||
public BadgeStatus? Status
|
||||
{
|
||||
get { return (BadgeStatus?)GetValue(StatusProperty); }
|
||||
set { SetValue(StatusProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextProperty =
|
||||
DependencyProperty.Register("Text", typeof(string), typeof(Badge), new PropertyMetadata(string.Empty));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the text of the status dot. valid with StatusProperty set
|
||||
/// </summary>
|
||||
public string Text
|
||||
{
|
||||
get { return (string)GetValue(TextProperty); }
|
||||
set { SetValue(TextProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BadgeHeightProperty =
|
||||
DependencyProperty.Register("BadgeHeight", typeof(double), typeof(Badge), new PropertyMetadata(default(double)));
|
||||
|
||||
public double BadgeHeight
|
||||
{
|
||||
get { return (double)GetValue(BadgeHeightProperty); }
|
||||
set { SetValue(BadgeHeightProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BadgeForegroundProperty =
|
||||
DependencyProperty.Register("BadgeForeground", typeof(Brush), typeof(Badge), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public Brush BadgeForeground
|
||||
{
|
||||
get { return (Brush)GetValue(BadgeForegroundProperty); }
|
||||
set { SetValue(BadgeForegroundProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
public static readonly DependencyProperty BadgeBackgroundProperty =
|
||||
DependencyProperty.Register("BadgeBackground", typeof(Brush), typeof(Badge), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public Brush BadgeBackground
|
||||
{
|
||||
get { return (Brush)GetValue(BadgeBackgroundProperty); }
|
||||
set { SetValue(BadgeBackgroundProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static Badge()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(Badge), new FrameworkPropertyMetadata(typeof(Badge)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
badgeContainer = GetTemplateChild(PART_BadgeContainer) as FrameworkElement;
|
||||
count = GetTemplateChild(PART_Count) as ContentPresenter;
|
||||
|
||||
ApplyCount();
|
||||
}
|
||||
|
||||
protected override WindowSize ArrangeOverride(WindowSize arrangeBounds)
|
||||
{
|
||||
var result = base.ArrangeOverride(arrangeBounds);
|
||||
|
||||
if (badgeContainer == null) return result;
|
||||
|
||||
var desiredSize = badgeContainer.DesiredSize;
|
||||
|
||||
// System.Console.WriteLine(desiredSize);
|
||||
// if ((desiredSize.Width <= 0.0 || desiredSize.Height <= 0.0))
|
||||
|
||||
|
||||
//var containerDesiredSize = _badgeContainer.DesiredSize;
|
||||
//if ((containerDesiredSize.Width <= 0.0 || containerDesiredSize.Height <= 0.0)
|
||||
// && !double.IsNaN(_badgeContainer.ActualWidth) && !double.IsInfinity(_badgeContainer.ActualWidth)
|
||||
// && !double.IsNaN(_badgeContainer.ActualHeight) && !double.IsInfinity(_badgeContainer.ActualHeight))
|
||||
//{
|
||||
// containerDesiredSize = new Size(_badgeContainer.ActualWidth, _badgeContainer.ActualHeight);
|
||||
//}
|
||||
|
||||
var h = 0 - desiredSize.Width / 2;
|
||||
var v = 0 - desiredSize.Height / 2;
|
||||
|
||||
// badgeContainer.Margin = new Thickness(0);
|
||||
// badgeContainer.Margin = new Thickness(h, v, h, v);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public enum BadgeStatus : byte
|
||||
{
|
||||
Success, Processing, Default, Error, Warning
|
||||
}
|
||||
7
AntDesignWPF/Controls/BorderStyle.cs
Normal file
7
AntDesignWPF/Controls/BorderStyle.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
public enum BorderStyle : byte
|
||||
{
|
||||
Solid, Dotted, Dashed
|
||||
}
|
||||
}
|
||||
16
AntDesignWPF/Controls/CheckableTag.cs
Normal file
16
AntDesignWPF/Controls/CheckableTag.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
using System.Windows;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
/// <summary>
|
||||
/// CheckableTag works like Checkbox, click it to toggle checked.
|
||||
/// </summary>
|
||||
public class CheckableTag : ToggleButton
|
||||
{
|
||||
static CheckableTag()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(CheckableTag), new FrameworkPropertyMetadata(typeof(CheckableTag)));
|
||||
}
|
||||
}
|
||||
}
|
||||
9
AntDesignWPF/Controls/ClosingWindowEventHandlerArgs.cs
Normal file
9
AntDesignWPF/Controls/ClosingWindowEventHandlerArgs.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
using System;
|
||||
|
||||
public class ClosingWindowEventHandlerArgs : EventArgs
|
||||
{
|
||||
public bool Cancelled { get; set; }
|
||||
}
|
||||
}
|
||||
80
AntDesignWPF/Controls/CodeBox.cs
Normal file
80
AntDesignWPF/Controls/CodeBox.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
public class CodeBox : AntdContentControl
|
||||
{
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty TitleProperty =
|
||||
DependencyProperty.Register("Title", typeof(string), typeof(CodeBox), new PropertyMetadata(string.Empty));
|
||||
|
||||
public string Title
|
||||
{
|
||||
get { return (string)GetValue(TitleProperty); }
|
||||
set { SetValue(TitleProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
public static readonly DependencyProperty TitleTemplateProperty =
|
||||
DependencyProperty.Register("TitleTemplate", typeof(DataTemplate), typeof(CodeBox), new PropertyMetadata(null));
|
||||
|
||||
public DataTemplate TitleTemplate
|
||||
{
|
||||
get { return (DataTemplate)GetValue(TitleTemplateProperty); }
|
||||
set { SetValue(TitleTemplateProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DescriptionProperty =
|
||||
DependencyProperty.Register("Description", typeof(string), typeof(CodeBox), new PropertyMetadata(string.Empty));
|
||||
|
||||
public string Description
|
||||
{
|
||||
get { return (string)GetValue(DescriptionProperty); }
|
||||
set { SetValue(DescriptionProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DescriptionTemplateProperty =
|
||||
DependencyProperty.Register("DescriptionTemplate", typeof(DataTemplate), typeof(CodeBox), new PropertyMetadata(null));
|
||||
|
||||
public DataTemplate DescriptionTemplate
|
||||
{
|
||||
get { return (DataTemplate)GetValue(DescriptionTemplateProperty); }
|
||||
set { SetValue(DescriptionTemplateProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CodeProperty =
|
||||
DependencyProperty.Register("Code", typeof(string), typeof(CodeBox), new PropertyMetadata(string.Empty));
|
||||
|
||||
public string Code
|
||||
{
|
||||
get { return (string)GetValue(CodeProperty); }
|
||||
set { SetValue(CodeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CodeTemplateProperty =
|
||||
DependencyProperty.Register("CodeTemplate", typeof(DataTemplate), typeof(CodeBox), new PropertyMetadata(null));
|
||||
|
||||
public DataTemplate CodeTemplate
|
||||
{
|
||||
get { return (DataTemplate)GetValue(CodeTemplateProperty); }
|
||||
set { SetValue(CodeTemplateProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static CodeBox()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(CodeBox), new FrameworkPropertyMetadata(typeof(CodeBox)));
|
||||
}
|
||||
//public CodeBox()
|
||||
//{
|
||||
// SetResourceReference(StyleProperty, typeof(CodeBox));
|
||||
//}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
41
AntDesignWPF/Controls/Heading.cs
Normal file
41
AntDesignWPF/Controls/Heading.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// A heading of the a page.
|
||||
/// </summary>
|
||||
public class Heading : TextBlock
|
||||
{
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty SizeProperty =
|
||||
DependencyProperty.Register("Size", typeof(HeadingSizes), typeof(Heading), new PropertyMetadata(HeadingSizes.Normal));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the size of the heading.
|
||||
/// </summary>
|
||||
public HeadingSizes Size
|
||||
{
|
||||
get { return (HeadingSizes)GetValue(SizeProperty); }
|
||||
set { SetValue(SizeProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static Heading()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(Heading), new FrameworkPropertyMetadata(typeof(Heading)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public enum HeadingSizes : byte
|
||||
{
|
||||
ExtraLarge, Large, Medium, Normal, Small, Tiny
|
||||
}
|
||||
}
|
||||
36
AntDesignWPF/Controls/Hyperlink.cs
Normal file
36
AntDesignWPF/Controls/Hyperlink.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
using System.Windows;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
/// <summary>
|
||||
/// A hyperlink button.
|
||||
/// </summary>
|
||||
public class Hyperlink : ButtonBase
|
||||
{
|
||||
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty UriProperty =
|
||||
DependencyProperty.Register("Uri", typeof(string), typeof(Hyperlink), new PropertyMetadata(string.Empty));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the uri of hyperlinks.
|
||||
/// </summary>
|
||||
public string Uri
|
||||
{
|
||||
get { return (string)GetValue(UriProperty); }
|
||||
set { SetValue(UriProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static Hyperlink()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(Hyperlink), new FrameworkPropertyMetadata(typeof(Hyperlink)));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
498
AntDesignWPF/Controls/Icon.cs
Normal file
498
AntDesignWPF/Controls/Icon.cs
Normal file
@@ -0,0 +1,498 @@
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
using AntDesign.WPF.Contracts;
|
||||
using AntDesign.WPF.Utils;
|
||||
|
||||
namespace AntDesign.WPF.Controls;
|
||||
/// <summary>
|
||||
/// 头像、警告提示语义矢量图形
|
||||
/// </summary>
|
||||
public class Icon : FrameworkElement, ISpinable
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private Geometry definingGeometry;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Document Properties
|
||||
|
||||
/// <summary>
|
||||
/// DependencyProperty for <see cref="FontSize" /> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty FontSizeProperty =
|
||||
TextElement.FontSizeProperty.AddOwner(typeof(Icon));
|
||||
|
||||
/// <summary>
|
||||
/// The FontSize property specifies the size of the font.
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(FontSizeConverter))]
|
||||
[Localizability(LocalizationCategory.None)]
|
||||
public double FontSize
|
||||
{
|
||||
get { return (double)GetValue(FontSizeProperty); }
|
||||
set { SetValue(FontSizeProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DependencyProperty setter for <see cref="FontSize" /> property.
|
||||
/// </summary>
|
||||
/// <param name="element">The element to which to write the attached property.</param>
|
||||
/// <param name="value">The property value to set</param>
|
||||
public static void SetFontSize(DependencyObject element, double value)
|
||||
{
|
||||
if (element == null)
|
||||
{
|
||||
throw new ArgumentNullException("element");
|
||||
}
|
||||
|
||||
element.SetValue(FontSizeProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DependencyProperty getter for <see cref="FontSize" /> property.
|
||||
/// </summary>
|
||||
/// <param name="element">The element from which to read the attached property.</param>
|
||||
[TypeConverter(typeof(FontSizeConverter))]
|
||||
public static double GetFontSize(DependencyObject element)
|
||||
{
|
||||
if (element == null)
|
||||
{
|
||||
throw new ArgumentNullException("element");
|
||||
}
|
||||
|
||||
return (double)element.GetValue(FontSizeProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DependencyProperty for <see cref="Foreground" /> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ForegroundProperty =
|
||||
TextElement.ForegroundProperty.AddOwner(typeof(Icon));
|
||||
|
||||
/// <summary>
|
||||
/// The Foreground property specifies the foreground brush of an element's text content.
|
||||
/// </summary>
|
||||
public Brush Foreground
|
||||
{
|
||||
get { return (Brush)GetValue(ForegroundProperty); }
|
||||
set { SetValue(ForegroundProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DependencyProperty setter for <see cref="Foreground" /> property.
|
||||
/// </summary>
|
||||
/// <param name="element">The element to which to write the attached property.</param>
|
||||
/// <param name="value">The property value to set</param>
|
||||
public static void SetForeground(DependencyObject element, Brush value)
|
||||
{
|
||||
if (element == null)
|
||||
{
|
||||
throw new ArgumentNullException("element");
|
||||
}
|
||||
|
||||
element.SetValue(ForegroundProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DependencyProperty getter for <see cref="Foreground" /> property.
|
||||
/// </summary>
|
||||
/// <param name="element">The element from which to read the attached property.</param>
|
||||
public static Brush GetForeground(DependencyObject element)
|
||||
{
|
||||
if (element == null)
|
||||
{
|
||||
throw new ArgumentNullException("element");
|
||||
}
|
||||
|
||||
return (Brush)element.GetValue(ForegroundProperty);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BackgroundProperty =
|
||||
TextElement.BackgroundProperty.AddOwner(
|
||||
typeof(Icon),
|
||||
new FrameworkPropertyMetadata(
|
||||
Brushes.Transparent,
|
||||
FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
/// <summary>
|
||||
/// The Background property defines the brush used to fill the content area.
|
||||
/// </summary>
|
||||
public Brush Background
|
||||
{
|
||||
get { return (Brush)GetValue(BackgroundProperty); }
|
||||
set { SetValue(BackgroundProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Get the geometry that defines this icon.
|
||||
/// </summary>
|
||||
protected Geometry DefiningGeometry
|
||||
{
|
||||
get
|
||||
{
|
||||
if (definingGeometry == null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Type))
|
||||
{
|
||||
var key = "anticon." + Type.ToLower();
|
||||
|
||||
// With theme suffix.
|
||||
if (Theme == IconTheme.Filled)
|
||||
{
|
||||
key += ".fill";
|
||||
} else if (Theme == IconTheme.Colorful)
|
||||
{
|
||||
key += ".colorful";
|
||||
}
|
||||
|
||||
definingGeometry = TryFindResource(key) as Geometry ?? Geometry.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
definingGeometry = Geometry.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
return definingGeometry;
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TypeProperty =
|
||||
DependencyProperty.Register("Type", typeof(string), typeof(Icon),
|
||||
new FrameworkPropertyMetadata(null,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnSpinChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the type of the ant design icon.
|
||||
/// </summary>
|
||||
public string Type
|
||||
{
|
||||
get { return (string)GetValue(TypeProperty); }
|
||||
set { SetValue(TypeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ThemeProperty =
|
||||
DependencyProperty.Register("Theme", typeof(IconTheme), typeof(Icon),
|
||||
new FrameworkPropertyMetadata(IconTheme.Outlined, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the theme of the ant design icon.
|
||||
/// </summary>
|
||||
public IconTheme Theme
|
||||
{
|
||||
get { return (IconTheme)GetValue(ThemeProperty); }
|
||||
set { SetValue(ThemeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SpinProperty =
|
||||
DependencyProperty.Register("Spin", typeof(bool?), typeof(Icon), new PropertyMetadata(null, OnSpinChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets whether the icon has a spin animation.
|
||||
/// </summary>
|
||||
public bool? Spin
|
||||
{
|
||||
get { return (bool?)GetValue(SpinProperty); }
|
||||
set { SetValue(SpinProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnSpinChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
(d as Icon).SetSpinAnimation();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Attached Propperties
|
||||
|
||||
/// <summary>
|
||||
/// Why is it not a dependency property?
|
||||
/// icons are introduced by way of resources. if you define them as dependency properties, you will lose more flexibility.
|
||||
/// For example, each icon needs to use different stretch parameters.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ViewBoxProperty =
|
||||
DependencyProperty.RegisterAttached("ViewBox", typeof(Rect), typeof(Icon), new PropertyMetadata(new Rect(0, 0, 1024, 1024)), OnViewBoxValidate);
|
||||
|
||||
private static bool OnViewBoxValidate(object value)
|
||||
{
|
||||
var viewBox = (Rect)value;
|
||||
return viewBox.IsEmpty || (viewBox.Width >= 0 && viewBox.Height >= 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rectangular area of the geometric stretch.
|
||||
/// </summary>
|
||||
[AttachedPropertyBrowsableForType(typeof(Geometry))]
|
||||
public static Rect GetViewBox(DependencyObject obj)
|
||||
{
|
||||
return (Rect)obj.GetValue(ViewBoxProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the rectangular area of the geometric stretch.
|
||||
/// </summary>
|
||||
public static void SetViewBox(DependencyObject obj, Rect value)
|
||||
{
|
||||
obj.SetValue(ViewBoxProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When you need colorful icons, you need to be able to support custom brushes.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty FillProperty =
|
||||
DependencyProperty.RegisterAttached("Fill", typeof(Brush), typeof(Icon), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets the brush that fill the geometry.
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
[AttachedPropertyBrowsableForType(typeof(Geometry))]
|
||||
public static Brush GetFill(DependencyObject obj)
|
||||
{
|
||||
return (Brush)obj.GetValue(FillProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the brush to fill the geometry. Valid when Theme is colorful.
|
||||
/// </summary>
|
||||
public static void SetFill(DependencyObject obj, Brush value)
|
||||
{
|
||||
obj.SetValue(FillProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static Icon()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(Icon), new FrameworkPropertyMetadata(typeof(Icon)));
|
||||
}
|
||||
|
||||
public Icon()
|
||||
{
|
||||
Loaded += (s, e) => SetSpinAnimation();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
|
||||
/// <summary>
|
||||
/// Notification that a specified property has been invalidated.
|
||||
/// </summary>
|
||||
/// <param name="e">EventArgs that contains the property, metadata, old value, and new value for this change</param>
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.NewValue != e.OldValue && (e.Property == TypeProperty || e.Property == ThemeProperty))
|
||||
{
|
||||
// Reset definition geometry.
|
||||
definingGeometry = null;
|
||||
}
|
||||
|
||||
base.OnPropertyChanged(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates DesiredSize of the icon. Called by parent UIElement during is the first pass of layout.
|
||||
/// </summary>
|
||||
/// <param name="constraint">Constraint size is an "upper limit" that should not exceed.</param>
|
||||
/// <returns>icon desired size.</returns>
|
||||
protected override Size MeasureOverride(Size constraint)
|
||||
{
|
||||
return GetRenderSize(constraint, FontSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the rendered geometry.
|
||||
/// </summary>
|
||||
/// <param name="finalSize"></param>
|
||||
/// <returns></returns>
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
return GetRenderSize(finalSize, FontSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Render callback.
|
||||
/// </summary>
|
||||
protected override void OnRender(DrawingContext dc)
|
||||
{
|
||||
Geometry rendered;
|
||||
var geometry = DefiningGeometry;
|
||||
|
||||
Debug.Assert(geometry != null);
|
||||
|
||||
var foreground = Foreground;
|
||||
var matrix = GetStretchMatrix(geometry, FontSize);
|
||||
|
||||
// Need to use colorful render.
|
||||
if (geometry is GeometryGroup)
|
||||
{
|
||||
Brush brush;
|
||||
int index = 0;
|
||||
var isSolidColor = foreground is SolidColorBrush;
|
||||
var children = ((GeometryGroup)geometry).Children;
|
||||
|
||||
foreach (var child in children)
|
||||
{
|
||||
rendered = GetRenderedGeometry(child, matrix);
|
||||
|
||||
if (rendered != Geometry.Empty)
|
||||
{
|
||||
brush = rendered.GetValue(FillProperty) as Brush;
|
||||
|
||||
// It may need to be tinted
|
||||
if (brush == null)
|
||||
{
|
||||
if (!isSolidColor || index == 0 || index == 6 || index > 9)
|
||||
{
|
||||
brush = foreground;
|
||||
}else
|
||||
{
|
||||
brush = new SolidColorBrush(ColorPalette.Toning(((SolidColorBrush)foreground).Color, index));
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
dc.DrawGeometry(brush, null, rendered);
|
||||
}
|
||||
}
|
||||
|
||||
} else
|
||||
{
|
||||
rendered = GetRenderedGeometry(geometry, matrix);
|
||||
|
||||
if (rendered != Geometry.Empty)
|
||||
{
|
||||
dc.DrawGeometry(foreground, null, rendered);
|
||||
}
|
||||
}
|
||||
|
||||
// Without background, the mouse can penetrate geometry and cause event failure.
|
||||
var background = Background;
|
||||
|
||||
if (background != null)
|
||||
{
|
||||
dc.DrawRectangle(background, null, new Rect(0, 0, RenderSize.Width, RenderSize.Height));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void SetSpinAnimation()
|
||||
{
|
||||
var spin = Spin ?? Type == "loading";
|
||||
|
||||
if (spin)
|
||||
{
|
||||
this.BeginSpin(1d);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.StopSpin();
|
||||
}
|
||||
}
|
||||
|
||||
private Size GetRenderSize(Size availableSize, double fontSize)
|
||||
{
|
||||
if (IsGeometryEmpty(DefiningGeometry))
|
||||
{
|
||||
return new Size(0d, 0d);
|
||||
}
|
||||
|
||||
return new Size(Math.Min(availableSize.Width, fontSize), Math.Min(availableSize.Height, fontSize));
|
||||
}
|
||||
|
||||
private bool IsGeometryEmpty(Geometry geometry)
|
||||
{
|
||||
return geometry.IsEmpty() || geometry.Bounds.IsEmpty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the rendered geometry.
|
||||
/// </summary>
|
||||
private Geometry GetRenderedGeometry(Geometry geometry, Matrix matrix)
|
||||
{
|
||||
var rendered = geometry.CloneCurrentValue();
|
||||
|
||||
if (ReferenceEquals(geometry, rendered))
|
||||
{
|
||||
rendered = rendered.Clone();
|
||||
}
|
||||
|
||||
var transform = rendered.Transform;
|
||||
|
||||
if (transform == null)
|
||||
{
|
||||
rendered.Transform = new MatrixTransform(matrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
rendered.Transform = new MatrixTransform(transform.Value * matrix);
|
||||
}
|
||||
|
||||
return rendered;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the stretch matrix of the geometry.
|
||||
/// </summary>
|
||||
private Matrix GetStretchMatrix(Geometry geometry, double size)
|
||||
{
|
||||
var matrix = Matrix.Identity;
|
||||
|
||||
if (!IsGeometryEmpty(geometry))
|
||||
{
|
||||
double scaleX, scaleY;
|
||||
var viewBox = (Rect)geometry.GetValue(ViewBoxProperty);
|
||||
|
||||
if (viewBox.IsEmpty)
|
||||
{
|
||||
viewBox = geometry.Bounds;
|
||||
scaleX = size / viewBox.Right;
|
||||
scaleY = size / viewBox.Bottom;
|
||||
|
||||
if (scaleX > scaleY)
|
||||
{
|
||||
scaleX = scaleY;
|
||||
} else
|
||||
{
|
||||
scaleY = scaleX;
|
||||
}
|
||||
|
||||
} else
|
||||
{
|
||||
scaleX = size / viewBox.Width;
|
||||
scaleY = size / viewBox.Height;
|
||||
matrix.Translate(-(scaleX * viewBox.X), -(scaleY * viewBox.Y));
|
||||
}
|
||||
|
||||
matrix.Scale(scaleX, scaleY);
|
||||
}
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public enum IconTheme : byte
|
||||
{
|
||||
Filled, Outlined, Colorful
|
||||
}
|
||||
180
AntDesignWPF/Controls/MaterialWindow.cs
Normal file
180
AntDesignWPF/Controls/MaterialWindow.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom window class for a Material Design like styled window.
|
||||
/// </summary>
|
||||
public class MaterialWindow : Window
|
||||
{
|
||||
private const string MinimizeButtonName = "minimizeButton";
|
||||
private const string MaximizeRestoreButtonName = "maximizeRestoreButton";
|
||||
private const string CloseButtonName = "closeButton";
|
||||
|
||||
/// <summary>
|
||||
/// The color for the border and caption area background of the window.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty BorderBackgroundBrushProperty = DependencyProperty.Register(
|
||||
nameof(BorderBackgroundBrush), typeof(Brush), typeof(MaterialWindow), new FrameworkPropertyMetadata(null, null));
|
||||
|
||||
/// <summary>
|
||||
/// The color for the border and caption area background of the window.
|
||||
/// </summary>
|
||||
public Brush BorderBackgroundBrush
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Brush)GetValue(BorderBackgroundBrushProperty);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
SetValue(BorderBackgroundBrushProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The forground color for the caption area of the window.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty BorderForegroundBrushProperty = DependencyProperty.Register(
|
||||
nameof(BorderForegroundBrush), typeof(Brush), typeof(MaterialWindow), new FrameworkPropertyMetadata(null, null));
|
||||
|
||||
/// <summary>
|
||||
/// The forground color for the caption area of the window.
|
||||
/// </summary>
|
||||
public Brush BorderForegroundBrush
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Brush)GetValue(BorderForegroundBrushProperty);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
SetValue(BorderForegroundBrushProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lets the content of the window fade out if the window is inactive.
|
||||
/// The default is true (enabled).
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty FadeContentIfInactiveProperty = DependencyProperty.Register(
|
||||
nameof(FadeContentIfInactive), typeof(bool), typeof(MaterialWindow), new FrameworkPropertyMetadata(true));
|
||||
|
||||
/// <summary>
|
||||
/// Lets the content of the window fade out if the window is inactive.
|
||||
/// The default is true (enabled).
|
||||
/// </summary>
|
||||
public bool FadeContentIfInactive
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)GetValue(FadeContentIfInactiveProperty);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
SetValue(FadeContentIfInactiveProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The template for the title bar. The default shows a <see cref="TextBlock" /> with the title.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TitleTemplateProperty = DependencyProperty.Register(
|
||||
nameof(TitleTemplate), typeof(DataTemplate), typeof(MaterialWindow));
|
||||
|
||||
/// <summary>
|
||||
/// The template for the title bar. The default shows a <see cref="TextBlock" /> with the title.
|
||||
/// </summary>
|
||||
public DataTemplate TitleTemplate
|
||||
{
|
||||
get
|
||||
{
|
||||
return (DataTemplate)GetValue(TitleTemplateProperty);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
SetValue(TitleTemplateProperty, value);
|
||||
}
|
||||
}
|
||||
private AntdButton m_minimizeButton;
|
||||
private AntdButton m_maximizeRestoreButton;
|
||||
private AntdButton m_closeButton;
|
||||
|
||||
static MaterialWindow()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(MaterialWindow), new FrameworkPropertyMetadata(typeof(MaterialWindow)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="MaterialWindow" />.
|
||||
/// </summary>
|
||||
public MaterialWindow() : base() { }
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (m_minimizeButton != null)
|
||||
{
|
||||
m_minimizeButton.Click -= MinimizeButtonClickHandler;
|
||||
}
|
||||
|
||||
m_minimizeButton = GetTemplateChild(MinimizeButtonName) as AntdButton;
|
||||
|
||||
if (m_minimizeButton != null)
|
||||
{
|
||||
m_minimizeButton.Click += MinimizeButtonClickHandler;
|
||||
}
|
||||
|
||||
if (m_maximizeRestoreButton != null)
|
||||
{
|
||||
m_maximizeRestoreButton.Click -= MaximizeRestoreButtonClickHandler;
|
||||
}
|
||||
|
||||
m_maximizeRestoreButton = GetTemplateChild(MaximizeRestoreButtonName) as AntdButton;
|
||||
|
||||
if (m_maximizeRestoreButton != null)
|
||||
{
|
||||
m_maximizeRestoreButton.Click += MaximizeRestoreButtonClickHandler;
|
||||
}
|
||||
|
||||
if (m_closeButton != null)
|
||||
{
|
||||
m_closeButton.Click -= CloseButtonClickHandler;
|
||||
}
|
||||
|
||||
m_closeButton = GetTemplateChild(CloseButtonName) as AntdButton;
|
||||
|
||||
if (m_closeButton != null)
|
||||
{
|
||||
m_closeButton.Click += CloseButtonClickHandler;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
}
|
||||
|
||||
private void CloseButtonClickHandler(object sender, RoutedEventArgs args)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void MaximizeRestoreButtonClickHandler(object sender, RoutedEventArgs args)
|
||||
{
|
||||
WindowState = WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal;
|
||||
}
|
||||
|
||||
private void MinimizeButtonClickHandler(object sender, RoutedEventArgs args)
|
||||
{
|
||||
WindowState = WindowState.Minimized;
|
||||
}
|
||||
}
|
||||
}
|
||||
111
AntDesignWPF/Controls/PropertyChangeNotifier.cs
Normal file
111
AntDesignWPF/Controls/PropertyChangeNotifier.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
/// <summary>
|
||||
/// AddValueChanged of dependency property descriptor results in memory leak as you already know.
|
||||
/// So, as described here, you can create custom class PropertyChangeNotifier to listen
|
||||
/// to any dependency property changes.
|
||||
///
|
||||
/// This class takes advantage of the fact that bindings use weak references to manage associations
|
||||
/// so the class will not root the object who property changes it is watching. It also uses a WeakReference
|
||||
/// to maintain a reference to the object whose property it is watching without rooting that object.
|
||||
/// In this way, you can maintain a collection of these objects so that you can unhook the property
|
||||
/// change later without worrying about that collection rooting the object whose values you are watching.
|
||||
///
|
||||
/// Complete implementation can be found here: http://agsmith.wordpress.com/2008/04/07/propertydescriptor-addvaluechanged-alternative/
|
||||
/// </summary>
|
||||
internal sealed class PropertyChangeNotifier : DependencyObject, IDisposable
|
||||
{
|
||||
private WeakReference _propertySource;
|
||||
|
||||
public PropertyChangeNotifier(DependencyObject propertySource, string path)
|
||||
: this(propertySource, new PropertyPath(path))
|
||||
{
|
||||
}
|
||||
|
||||
public PropertyChangeNotifier(DependencyObject propertySource, DependencyProperty property)
|
||||
: this(propertySource, new PropertyPath(property))
|
||||
{
|
||||
}
|
||||
|
||||
public PropertyChangeNotifier(DependencyObject propertySource, PropertyPath property)
|
||||
{
|
||||
if (null == propertySource)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(propertySource));
|
||||
}
|
||||
if (null == property)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(property));
|
||||
}
|
||||
this._propertySource = new WeakReference(propertySource);
|
||||
var binding = new Binding();
|
||||
binding.Path = property;
|
||||
binding.Mode = BindingMode.OneWay;
|
||||
binding.Source = propertySource;
|
||||
BindingOperations.SetBinding(this, ValueProperty, binding);
|
||||
}
|
||||
|
||||
public DependencyObject PropertySource
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
// note, it is possible that accessing the target property
|
||||
// will result in an exception so i’ve wrapped this check
|
||||
// in a try catch
|
||||
return this._propertySource.IsAlive
|
||||
? this._propertySource.Target as DependencyObject
|
||||
: null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="Value"/> dependency property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ValueProperty
|
||||
= DependencyProperty.Register("Value", typeof(object), typeof(PropertyChangeNotifier),
|
||||
new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnPropertyChanged)));
|
||||
|
||||
/// <summary>
|
||||
/// Returns/sets the value of the property
|
||||
/// </summary>
|
||||
/// <seealso cref="ValueProperty"/>
|
||||
[Description("Returns/sets the value of the property")]
|
||||
[Category("Behavior")]
|
||||
[Bindable(true)]
|
||||
public object Value
|
||||
{
|
||||
get { return (object)this.GetValue(ValueProperty); }
|
||||
set { this.SetValue(ValueProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var notifier = (PropertyChangeNotifier)d;
|
||||
if (notifier.RaiseValueChanged)
|
||||
{
|
||||
notifier.ValueChanged?.Invoke(notifier.PropertySource, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler ValueChanged;
|
||||
|
||||
public bool RaiseValueChanged { get; set; } = true;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
BindingOperations.ClearBinding(this, ValueProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
61
AntDesignWPF/Controls/RadioButtonGroup.cs
Normal file
61
AntDesignWPF/Controls/RadioButtonGroup.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
public class RadioButtonGroup : ItemsControl
|
||||
{
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty SizeProperty =
|
||||
DependencyProperty.Register("Size", typeof(Sizes?), typeof(RadioButtonGroup), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets size for radio button style
|
||||
/// </summary>
|
||||
public Sizes? Size
|
||||
{
|
||||
get { return (Sizes?)GetValue(SizeProperty); }
|
||||
set { SetValue(SizeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty OrientationProperty =
|
||||
DependencyProperty.Register("Orientation", typeof(Orientation), typeof(RadioButtonGroup), new PropertyMetadata(Orientation.Horizontal));
|
||||
|
||||
|
||||
public Orientation Orientation
|
||||
{
|
||||
get { return (Orientation)GetValue(OrientationProperty); }
|
||||
set { SetValue(OrientationProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static RadioButtonGroup()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(RadioButtonGroup), new FrameworkPropertyMetadata(typeof(RadioButtonGroup)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
base.OnItemsChanged(e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class RadioButtonGroupTemplateSelector : DataTemplateSelector
|
||||
{
|
||||
public override DataTemplate SelectTemplate(object item, DependencyObject container)
|
||||
{
|
||||
return base.SelectTemplate(item, container);
|
||||
}
|
||||
}
|
||||
}
|
||||
7
AntDesignWPF/Controls/Shapes.cs
Normal file
7
AntDesignWPF/Controls/Shapes.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
public enum Shapes : byte
|
||||
{
|
||||
Circle, Square
|
||||
}
|
||||
}
|
||||
7
AntDesignWPF/Controls/Sizes.cs
Normal file
7
AntDesignWPF/Controls/Sizes.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
public enum Sizes
|
||||
{
|
||||
Large = -1, Small = -2
|
||||
}
|
||||
}
|
||||
94
AntDesignWPF/Controls/Spin.cs
Normal file
94
AntDesignWPF/Controls/Spin.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
using System.Windows;
|
||||
using ContentControlBase = System.Windows.Controls.ContentControl;
|
||||
|
||||
/// <summary>
|
||||
/// A spinner for displaying loading state of a page or a section.
|
||||
/// </summary>
|
||||
[TemplateVisualState(Name = "Spun", GroupName = "SpinStates")]
|
||||
[TemplateVisualState(Name = "Unspun", GroupName = "SpinStates")]
|
||||
public class Spin : ContentControlBase
|
||||
{
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty IndicatorProperty =
|
||||
DependencyProperty.Register("Indicator", typeof(UIElement), typeof(Spin), new PropertyMetadata(null, OnSpinningChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets element of the spinning indicator.
|
||||
/// </summary>
|
||||
public UIElement Indicator
|
||||
{
|
||||
get { return (UIElement)GetValue(IndicatorProperty); }
|
||||
set { SetValue(IndicatorProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SizeProperty =
|
||||
DependencyProperty.Register("Size", typeof(Sizes?), typeof(Spin), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets size of spin.
|
||||
/// </summary>
|
||||
public Sizes? Size
|
||||
{
|
||||
get { return (Sizes?)GetValue(SizeProperty); }
|
||||
set { SetValue(SizeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SpinningProperty =
|
||||
DependencyProperty.Register("Spinning", typeof(bool), typeof(Spin), new PropertyMetadata(true, OnSpinningChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets whether spin is spinning.
|
||||
/// </summary>
|
||||
public bool Spinning
|
||||
{
|
||||
get { return (bool)GetValue(SpinningProperty); }
|
||||
set { SetValue(SpinningProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnSpinningChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
(d as Spin).GoToSpinState();
|
||||
}
|
||||
|
||||
private void GoToSpinState()
|
||||
{
|
||||
VisualStateManager.GoToState(this, Spinning && null == Indicator ? "Spun" : "Unspun", true);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TipProperty =
|
||||
DependencyProperty.Register("Tip", typeof(string), typeof(Spin), new PropertyMetadata(string.Empty));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets customize description content when spin has children.
|
||||
/// </summary>
|
||||
public string Tip
|
||||
{
|
||||
get { return (string)GetValue(TipProperty); }
|
||||
set { SetValue(TipProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static Spin()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(Spin), new FrameworkPropertyMetadata(typeof(Spin)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
GoToSpinState();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
136
AntDesignWPF/Controls/Switch.cs
Normal file
136
AntDesignWPF/Controls/Switch.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
[TemplatePart(Name = PART_Dot, Type = typeof(FrameworkElement))]
|
||||
public class Switch : ToggleButton
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private const string PART_Dot = "PART_Dot";
|
||||
|
||||
private FrameworkElement dot;
|
||||
|
||||
private VisualState pressedState;
|
||||
|
||||
private Storyboard pressedStoryboard;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty LoadingProperty =
|
||||
DependencyProperty.Register("Loading", typeof(bool), typeof(Switch), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets loading state of switch.
|
||||
/// </summary>
|
||||
public bool Loading
|
||||
{
|
||||
get { return (bool)GetValue(LoadingProperty); }
|
||||
set { SetValue(LoadingProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SizeProperty =
|
||||
DependencyProperty.Register("Size", typeof(Sizes?), typeof(Switch), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the size of the switch.
|
||||
/// </summary>
|
||||
public Sizes? Size
|
||||
{
|
||||
get { return (Sizes?)GetValue(SizeProperty); }
|
||||
set { SetValue(SizeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty UnCheckedContentProperty =
|
||||
DependencyProperty.Register("UnCheckedContent", typeof(object), typeof(Switch), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets content to be shown when the state is unchecked.
|
||||
/// </summary>
|
||||
public object UnCheckedContent
|
||||
{
|
||||
get { return GetValue(UnCheckedContentProperty); }
|
||||
set { SetValue(UnCheckedContentProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static Switch()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(Switch), new FrameworkPropertyMetadata(typeof(Switch)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
dot = GetTemplateChild(PART_Dot) as FrameworkElement;
|
||||
pressedState = GetTemplateChild("Pressed") as VisualState;
|
||||
|
||||
if (pressedState != null && pressedState.Storyboard != null)
|
||||
{
|
||||
pressedStoryboard = pressedState.Storyboard.Clone();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
|
||||
{
|
||||
base.OnRenderSizeChanged(sizeInfo);
|
||||
SetDotAnimation();
|
||||
}
|
||||
private bool DotAnimated = false;
|
||||
protected override void OnIsPressedChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnIsPressedChanged(e);
|
||||
//if (!DotAnimated)
|
||||
//{
|
||||
if (dot != null /*&& IsChecked.HasValue && IsChecked.Value*/ && IsPressed)
|
||||
{
|
||||
var to = dot.Margin;
|
||||
// to.Left -= dot.ActualWidth * 1.3333 - dot.ActualWidth;
|
||||
to.Right -= dot.ActualWidth * 1.3333 - dot.ActualWidth;
|
||||
var ease = new CircleEase() { EasingMode = EasingMode.EaseInOut };
|
||||
var animation = new ThicknessAnimation(to, TimeSpan.FromSeconds(0.36)) { EasingFunction = ease };
|
||||
|
||||
dot.BeginAnimation(MarginProperty, animation);
|
||||
}
|
||||
|
||||
//else if (!IsPressed) DotAnimated = false;
|
||||
//}
|
||||
}
|
||||
|
||||
private void SetDotAnimation()
|
||||
{
|
||||
if (dot == null || pressedState == null || DotAnimated) return;
|
||||
|
||||
DotAnimated = true;
|
||||
var storyboard = pressedStoryboard != null ? pressedStoryboard.Clone() : new Storyboard();
|
||||
var ease = new CircleEase() { EasingMode = EasingMode.EaseInOut };
|
||||
var animation = new DoubleAnimation(dot.ActualWidth * 1.3333, TimeSpan.FromSeconds(0.36)) { EasingFunction = ease };
|
||||
|
||||
Storyboard.SetTargetName(animation, PART_Dot);
|
||||
Storyboard.SetTargetProperty(animation, new PropertyPath("Width"));
|
||||
|
||||
storyboard.Children.Add(animation);
|
||||
pressedState.Storyboard = storyboard;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
16
AntDesignWPF/Controls/TabControl.cs
Normal file
16
AntDesignWPF/Controls/TabControl.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
using System.Windows;
|
||||
|
||||
public class TabControl : System.Windows.Controls.TabControl
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
static TabControl()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(TabControl), new FrameworkPropertyMetadata(typeof(TabControl)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
144
AntDesignWPF/Controls/Tag.cs
Normal file
144
AntDesignWPF/Controls/Tag.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
using System.Windows;
|
||||
using ContentControlBase = System.Windows.Controls.ContentControl;
|
||||
|
||||
/// <summary>
|
||||
/// Tag for categorizing or markup.
|
||||
/// </summary>
|
||||
[TemplatePart(Name = PART_Close, Type = typeof(UIElement))]
|
||||
public class Tag : ContentControlBase
|
||||
{
|
||||
#region Fileds
|
||||
|
||||
private const string PART_Close = "PART_Close";
|
||||
|
||||
private UIElement close;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public static readonly RoutedEvent ClosingEvent =
|
||||
EventManager.RegisterRoutedEvent("Closing", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Tag));
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when closing the tag.
|
||||
/// </summary>
|
||||
public event RoutedEventHandler Closing
|
||||
{
|
||||
add { AddHandler(ClosingEvent, value); }
|
||||
remove { RemoveHandler(ClosingEvent, value); }
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent ClosedEvent =
|
||||
EventManager.RegisterRoutedEvent("Closed", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Tag));
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a Tag is closed and is no longer visible.
|
||||
/// </summary>
|
||||
public event RoutedEventHandler Closed
|
||||
{
|
||||
add { AddHandler(ClosedEvent, value); }
|
||||
remove { RemoveHandler(ClosedEvent, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty ClosableProperty =
|
||||
DependencyProperty.Register("Closable", typeof(bool), typeof(Tag), new PropertyMetadata(false, OnClosableChnaged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets whether the Tag can be closed.
|
||||
/// </summary>
|
||||
public bool Closable
|
||||
{
|
||||
get { return (bool)GetValue(ClosableProperty); }
|
||||
set { SetValue(ClosableProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnClosableChnaged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
(d as Tag).SetCloseVisibility();
|
||||
}
|
||||
|
||||
private void SetCloseVisibility()
|
||||
{
|
||||
if (close != null)
|
||||
{
|
||||
close.Visibility = Closable ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static readonly DependencyProperty ColorModeProperty =
|
||||
DependencyProperty.Register("ColorMode", typeof(ColorMode?), typeof(Tag), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the color mode of the tag.
|
||||
/// </summary>
|
||||
public ColorMode? ColorMode
|
||||
{
|
||||
get { return (ColorMode?)GetValue(ColorModeProperty); }
|
||||
set { SetValue(ColorModeProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static Tag()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(Tag), new FrameworkPropertyMetadata(typeof(Tag)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
close = GetTemplateChild(PART_Close) as UIElement;
|
||||
|
||||
if (close != null)
|
||||
{
|
||||
Loaded -= OnLoaded;
|
||||
Loaded += OnLoaded;
|
||||
|
||||
close.MouseLeftButtonUp -= OnRaiseClosingEvent;
|
||||
close.MouseLeftButtonUp += OnRaiseClosingEvent;
|
||||
|
||||
SetCloseVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Closing -= OnClosing;
|
||||
Closing += OnClosing;
|
||||
}
|
||||
|
||||
private void OnRaiseClosingEvent(object sender, RoutedEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
RaiseEvent(new RoutedEventArgs(ClosingEvent, this));
|
||||
}
|
||||
|
||||
private void OnClosing(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SetCurrentValue(VisibilityProperty, Visibility.Collapsed);
|
||||
RaiseEvent(new RoutedEventArgs(ClosedEvent, this));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public enum ColorMode : byte
|
||||
{
|
||||
Colorful, Inverse
|
||||
}
|
||||
}
|
||||
58
AntDesignWPF/Controls/Thumb.cs
Normal file
58
AntDesignWPF/Controls/Thumb.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using AntDesign.WPF.Contracts;
|
||||
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
using System.Windows.Input;
|
||||
|
||||
using WPF.Contracts;
|
||||
|
||||
using ThumbBase = System.Windows.Controls.Primitives.Thumb;
|
||||
|
||||
public class Thumb : ThumbBase, IThumb
|
||||
{
|
||||
private TouchDevice currentDevice = null;
|
||||
|
||||
protected override void OnPreviewTouchDown(TouchEventArgs e)
|
||||
{
|
||||
// Release any previous capture
|
||||
this.ReleaseCurrentDevice();
|
||||
// Capture the new touch
|
||||
this.CaptureCurrentDevice(e);
|
||||
}
|
||||
|
||||
protected override void OnPreviewTouchUp(TouchEventArgs e)
|
||||
{
|
||||
this.ReleaseCurrentDevice();
|
||||
}
|
||||
|
||||
protected override void OnLostTouchCapture(TouchEventArgs e)
|
||||
{
|
||||
// Only re-capture if the reference is not null
|
||||
// This way we avoid re-capturing after calling ReleaseCurrentDevice()
|
||||
if (this.currentDevice != null)
|
||||
{
|
||||
this.CaptureCurrentDevice(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseCurrentDevice()
|
||||
{
|
||||
if (this.currentDevice != null)
|
||||
{
|
||||
// Set the reference to null so that we don't re-capture in the OnLostTouchCapture() method
|
||||
var temp = this.currentDevice;
|
||||
this.currentDevice = null;
|
||||
this.ReleaseTouchCapture(temp);
|
||||
}
|
||||
}
|
||||
|
||||
private void CaptureCurrentDevice(TouchEventArgs e)
|
||||
{
|
||||
bool gotTouch = this.CaptureTouch(e.TouchDevice);
|
||||
if (gotTouch)
|
||||
{
|
||||
this.currentDevice = e.TouchDevice;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
263
AntDesignWPF/Controls/ThumbContentControl.cs
Normal file
263
AntDesignWPF/Controls/ThumbContentControl.cs
Normal file
@@ -0,0 +1,263 @@
|
||||
using AntDesign.WPF.Contracts;
|
||||
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation.Peers;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
|
||||
using WPF.Contracts;
|
||||
|
||||
public class ThumbContentControl : AntdContentControl, IThumb
|
||||
{
|
||||
#region Events
|
||||
|
||||
public static readonly RoutedEvent DragStartedEvent
|
||||
= EventManager.RegisterRoutedEvent("DragStarted", RoutingStrategy.Bubble, typeof(DragStartedEventHandler), typeof(ThumbContentControl));
|
||||
|
||||
/// <summary>
|
||||
/// Adds or remove a DragStartedEvent handler
|
||||
/// </summary>
|
||||
public event DragStartedEventHandler DragStarted
|
||||
{
|
||||
add { AddHandler(DragStartedEvent, value); }
|
||||
remove { RemoveHandler(DragStartedEvent, value); }
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent DragDeltaEvent
|
||||
= EventManager.RegisterRoutedEvent("DragDelta", RoutingStrategy.Bubble, typeof(DragDeltaEventHandler), typeof(ThumbContentControl));
|
||||
|
||||
/// <summary>
|
||||
/// Adds or remove a DragDeltaEvent handler
|
||||
/// </summary>
|
||||
public event DragDeltaEventHandler DragDelta
|
||||
{
|
||||
add { AddHandler(DragDeltaEvent, value); }
|
||||
remove { RemoveHandler(DragDeltaEvent, value); }
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent DragCompletedEvent
|
||||
= EventManager.RegisterRoutedEvent("DragCompleted", RoutingStrategy.Bubble, typeof(DragCompletedEventHandler), typeof(ThumbContentControl));
|
||||
|
||||
/// <summary>
|
||||
/// Adds or remove a DragCompletedEvent handler
|
||||
/// </summary>
|
||||
public event DragCompletedEventHandler DragCompleted
|
||||
{
|
||||
add { AddHandler(DragCompletedEvent, value); }
|
||||
remove { RemoveHandler(DragCompletedEvent, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
|
||||
private TouchDevice currentDevice = null;
|
||||
|
||||
private Point startDragPoint;
|
||||
|
||||
private Point startDragScreenPoint;
|
||||
|
||||
private Point oldDragScreenPoint;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyPropertyKey IsDraggingPropertyKey
|
||||
= DependencyProperty.RegisterReadOnly("IsDragging", typeof(bool), typeof(ThumbContentControl), new FrameworkPropertyMetadata(default(bool)));
|
||||
|
||||
/// <summary>
|
||||
/// DependencyProperty for the IsDragging property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsDraggingProperty = IsDraggingPropertyKey.DependencyProperty;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the left mouse button is pressed and is over the MetroThumbContentControl.
|
||||
/// </summary>
|
||||
public bool IsDragging
|
||||
{
|
||||
get { return (bool)GetValue(IsDraggingProperty); }
|
||||
protected set { SetValue(IsDraggingPropertyKey, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static ThumbContentControl()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(ThumbContentControl), new FrameworkPropertyMetadata(typeof(ThumbContentControl)));
|
||||
FocusableProperty.OverrideMetadata(typeof(ThumbContentControl), new FrameworkPropertyMetadata(default(bool)));
|
||||
EventManager.RegisterClassHandler(typeof(ThumbContentControl), Mouse.LostMouseCaptureEvent, new MouseEventHandler(OnLostMouseCapture));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
|
||||
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
|
||||
{
|
||||
if (!IsDragging)
|
||||
{
|
||||
e.Handled = true;
|
||||
try
|
||||
{
|
||||
// focus me
|
||||
Focus();
|
||||
// now capture the mouse for the drag action
|
||||
CaptureMouse();
|
||||
// so now we are in dragging mode
|
||||
SetValue(IsDraggingPropertyKey, true);
|
||||
// get the mouse points
|
||||
startDragPoint = e.GetPosition(this);
|
||||
oldDragScreenPoint = startDragScreenPoint = PointToScreen(startDragPoint);
|
||||
|
||||
RaiseEvent(new ThumbContentControlDragStartedEventArgs(startDragPoint.X, startDragPoint.Y));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Trace.TraceError($"{this}: Something went wrong here: {exception} {Environment.NewLine} {exception.StackTrace}");
|
||||
CancelDragAction();
|
||||
}
|
||||
}
|
||||
|
||||
base.OnMouseLeftButtonDown(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
|
||||
{
|
||||
if (IsMouseCaptured && IsDragging)
|
||||
{
|
||||
e.Handled = true;
|
||||
// now we are in normal mode
|
||||
ClearValue(IsDraggingPropertyKey);
|
||||
// release the captured mouse
|
||||
ReleaseMouseCapture();
|
||||
// get the current mouse position and call the completed event with the horizontal/vertical change
|
||||
Point currentMouseScreenPoint = PointToScreen(e.MouseDevice.GetPosition(this));
|
||||
var horizontalChange = currentMouseScreenPoint.X - startDragScreenPoint.X;
|
||||
var verticalChange = currentMouseScreenPoint.Y - startDragScreenPoint.Y;
|
||||
RaiseEvent(new ThumbContentControlDragCompletedEventArgs(horizontalChange, verticalChange, false));
|
||||
}
|
||||
|
||||
base.OnMouseLeftButtonUp(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
|
||||
if (!IsDragging) return;
|
||||
|
||||
if (e.MouseDevice.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
Point currentDragPoint = e.GetPosition(this);
|
||||
// Get client point and convert it to screen point
|
||||
Point currentDragScreenPoint = PointToScreen(currentDragPoint);
|
||||
if (currentDragScreenPoint != oldDragScreenPoint)
|
||||
{
|
||||
oldDragScreenPoint = currentDragScreenPoint;
|
||||
e.Handled = true;
|
||||
var horizontalChange = currentDragPoint.X - startDragPoint.X;
|
||||
var verticalChange = currentDragPoint.Y - startDragPoint.Y;
|
||||
RaiseEvent(new DragDeltaEventArgs(horizontalChange, verticalChange) { RoutedEvent = ThumbContentControl.DragDeltaEvent });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// clear some saved stuff
|
||||
if (e.MouseDevice.Captured == this)
|
||||
{
|
||||
ReleaseMouseCapture();
|
||||
}
|
||||
|
||||
ClearValue(IsDraggingPropertyKey);
|
||||
startDragPoint.X = 0;
|
||||
startDragPoint.Y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPreviewTouchDown(TouchEventArgs e)
|
||||
{
|
||||
// Release any previous capture
|
||||
ReleaseCurrentDevice();
|
||||
// Capture the new touch
|
||||
CaptureCurrentDevice(e);
|
||||
}
|
||||
|
||||
protected override void OnPreviewTouchUp(TouchEventArgs e)
|
||||
{
|
||||
ReleaseCurrentDevice();
|
||||
}
|
||||
|
||||
protected override void OnLostTouchCapture(TouchEventArgs e)
|
||||
{
|
||||
// Only re-capture if the reference is not null
|
||||
// This way we avoid re-capturing after calling ReleaseCurrentDevice()
|
||||
if (currentDevice != null)
|
||||
{
|
||||
CaptureCurrentDevice(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected override AutomationPeer OnCreateAutomationPeer()
|
||||
{
|
||||
return new ThumbContentControlAutomationPeer(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
private static void OnLostMouseCapture(object sender, MouseEventArgs e)
|
||||
{
|
||||
// Cancel the drag action if we lost capture
|
||||
var thumb = (ThumbContentControl)sender;
|
||||
if (Mouse.Captured != thumb)
|
||||
{
|
||||
thumb.CancelDragAction();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseCurrentDevice()
|
||||
{
|
||||
if (currentDevice != null)
|
||||
{
|
||||
// Set the reference to null so that we don't re-capture in the OnLostTouchCapture() method
|
||||
var temp = currentDevice;
|
||||
currentDevice = null;
|
||||
ReleaseTouchCapture(temp);
|
||||
}
|
||||
}
|
||||
|
||||
private void CaptureCurrentDevice(TouchEventArgs e)
|
||||
{
|
||||
bool gotTouch = CaptureTouch(e.TouchDevice);
|
||||
if (gotTouch)
|
||||
{
|
||||
currentDevice = e.TouchDevice;
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelDragAction()
|
||||
{
|
||||
if (!IsDragging) return;
|
||||
|
||||
if (IsMouseCaptured)
|
||||
{
|
||||
ReleaseMouseCapture();
|
||||
}
|
||||
|
||||
ClearValue(IsDraggingPropertyKey);
|
||||
var horizontalChange = oldDragScreenPoint.X - startDragScreenPoint.X;
|
||||
var verticalChange = oldDragScreenPoint.Y - startDragScreenPoint.Y;
|
||||
RaiseEvent(new ThumbContentControlDragCompletedEventArgs(horizontalChange, verticalChange, true));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
23
AntDesignWPF/Controls/ThumbContentControlAutomationPeer.cs
Normal file
23
AntDesignWPF/Controls/ThumbContentControlAutomationPeer.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
using System.Windows;
|
||||
using System.Windows.Automation.Peers;
|
||||
|
||||
public class ThumbContentControlAutomationPeer : FrameworkElementAutomationPeer
|
||||
{
|
||||
public ThumbContentControlAutomationPeer(FrameworkElement owner)
|
||||
: base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
protected override AutomationControlType GetAutomationControlTypeCore()
|
||||
{
|
||||
return AutomationControlType.Custom;
|
||||
}
|
||||
|
||||
protected override string GetClassNameCore()
|
||||
{
|
||||
return "ThumbContentControl";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
public class ThumbContentControlDragCompletedEventArgs : DragCompletedEventArgs
|
||||
{
|
||||
public ThumbContentControlDragCompletedEventArgs(double horizontalOffset, double verticalOffset, bool canceled)
|
||||
: base(horizontalOffset, verticalOffset, canceled)
|
||||
{
|
||||
this.RoutedEvent = ThumbContentControl.DragCompletedEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
public class ThumbContentControlDragStartedEventArgs : DragStartedEventArgs
|
||||
{
|
||||
public ThumbContentControlDragStartedEventArgs(double horizontalOffset, double verticalOffset)
|
||||
: base(horizontalOffset, verticalOffset)
|
||||
{
|
||||
this.RoutedEvent = ThumbContentControl.DragStartedEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
296
AntDesignWPF/Controls/WindowButtons.cs
Normal file
296
AntDesignWPF/Controls/WindowButtons.cs
Normal file
@@ -0,0 +1,296 @@
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
using System.Windows.Threading;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using AntDesign.WPF.Win32;
|
||||
using SystemCommands = System.Windows.SystemCommands;
|
||||
|
||||
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
[TemplatePart(Name = PART_Min, Type = typeof(ButtonBase))]
|
||||
[TemplatePart(Name = PART_Max, Type = typeof(ButtonBase))]
|
||||
[TemplatePart(Name = PART_Close, Type = typeof(ButtonBase))]
|
||||
public class WindowButtons : ContentControl, INotifyPropertyChanged
|
||||
{
|
||||
#region Events
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected virtual void RaisePropertyChanged(string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public event ClosingWindowEventHandler ClosingWindow;
|
||||
|
||||
public delegate void ClosingWindowEventHandler(object sender, ClosingWindowEventHandlerArgs args);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
|
||||
private const string PART_Min = "PART_Min";
|
||||
|
||||
private const string PART_Max = "PART_Max";
|
||||
|
||||
private const string PART_Close = "PART_Close";
|
||||
|
||||
private ButtonBase min;
|
||||
|
||||
private ButtonBase max;
|
||||
|
||||
private ButtonBase close;
|
||||
|
||||
private SafeLibraryHandle user32;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty MinimizeProperty =
|
||||
DependencyProperty.Register("Minimize", typeof(string), typeof(WindowButtons), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the minimize button tooltip.
|
||||
/// </summary>
|
||||
public string Minimize
|
||||
{
|
||||
get { return (string)GetValue(MinimizeProperty); }
|
||||
set { SetValue(MinimizeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaximizeProperty =
|
||||
DependencyProperty.Register("Maximize", typeof(string), typeof(WindowButtons), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximize button tooltip.
|
||||
/// </summary>
|
||||
public string Maximize
|
||||
{
|
||||
get { return (string)GetValue(MaximizeProperty); }
|
||||
set { SetValue(MaximizeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty RestoreProperty =
|
||||
DependencyProperty.Register("Restore", typeof(string), typeof(WindowButtons), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the restore button tooltip.
|
||||
/// </summary>
|
||||
public string Restore
|
||||
{
|
||||
get { return (string)GetValue(RestoreProperty); }
|
||||
set { SetValue(RestoreProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CloseProperty =
|
||||
DependencyProperty.Register("Close", typeof(string), typeof(WindowButtons), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the close button tooltip.
|
||||
/// </summary>
|
||||
public string Close
|
||||
{
|
||||
get { return (string)GetValue(CloseProperty); }
|
||||
set { SetValue(CloseProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MinimizeStyleProperty =
|
||||
DependencyProperty.Register("MinimizeStyle", typeof(Style), typeof(WindowButtons), new PropertyMetadata(null, OnStyleChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the style for the minimize button.
|
||||
/// </summary>
|
||||
public Style MinimizeStyle
|
||||
{
|
||||
get { return (Style)GetValue(MinimizeStyleProperty); }
|
||||
set { SetValue(MinimizeStyleProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaximizeStyleProperty =
|
||||
DependencyProperty.Register("MaximizeStyle", typeof(Style), typeof(WindowButtons), new PropertyMetadata(null, OnStyleChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the style for the maximize button.
|
||||
/// </summary>
|
||||
public Style MaximizeStyle
|
||||
{
|
||||
get { return (Style)GetValue(MaximizeStyleProperty); }
|
||||
set { SetValue(MaximizeStyleProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CloseStyleProperty =
|
||||
DependencyProperty.Register("CloseStyle", typeof(Style), typeof(WindowButtons), new PropertyMetadata(null, OnStyleChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the style for the close button.
|
||||
/// </summary>
|
||||
public Style CloseStyle
|
||||
{
|
||||
get { return (Style)GetValue(CloseStyleProperty); }
|
||||
set { SetValue(CloseStyleProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.NewValue == e.OldValue) return;
|
||||
(d as WindowButtons).ApplyStyle();
|
||||
}
|
||||
|
||||
private AntdWindow parentWindow;
|
||||
|
||||
public AntdWindow ParentWindow
|
||||
{
|
||||
get { return parentWindow; }
|
||||
set
|
||||
{
|
||||
if (Equals(parentWindow, value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
parentWindow = value;
|
||||
RaisePropertyChanged("ParentWindow");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static WindowButtons()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(WindowButtons), new FrameworkPropertyMetadata(typeof(WindowButtons)));
|
||||
}
|
||||
|
||||
public WindowButtons()
|
||||
{
|
||||
Dispatcher.BeginInvoke(DispatcherPriority.Loaded,
|
||||
new Action(() =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Minimize))
|
||||
{
|
||||
SetCurrentValue(MinimizeProperty, GetCaption(900));
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(Maximize))
|
||||
{
|
||||
SetCurrentValue(MaximizeProperty, GetCaption(901));
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(Close))
|
||||
{
|
||||
SetCurrentValue(CloseProperty, GetCaption(905));
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(Restore))
|
||||
{
|
||||
SetCurrentValue(RestoreProperty, GetCaption(903));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private string GetCaption(int id)
|
||||
{
|
||||
if (user32 == null)
|
||||
{
|
||||
user32 = UnsafeNativeMethods.LoadLibrary(Environment.SystemDirectory + "\\User32.dll");
|
||||
}
|
||||
|
||||
var sb = new StringBuilder(256);
|
||||
UnsafeNativeMethods.LoadString(user32, (uint)id, sb, sb.Capacity);
|
||||
return sb.ToString().Replace("&", "");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
close = Template.FindName(PART_Close, this) as ButtonBase;
|
||||
|
||||
if (close != null)
|
||||
{
|
||||
close.Click += OnClose;
|
||||
}
|
||||
|
||||
max = Template.FindName(PART_Max, this) as ButtonBase;
|
||||
|
||||
if (max != null)
|
||||
{
|
||||
max.Click += OnMaximize;
|
||||
}
|
||||
|
||||
min = Template.FindName(PART_Min, this) as ButtonBase;
|
||||
|
||||
if (min != null)
|
||||
{
|
||||
min.Click += OnMinimize;
|
||||
}
|
||||
|
||||
ApplyStyle();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
private void ApplyStyle()
|
||||
{
|
||||
if (min != null)
|
||||
{
|
||||
min.Style = MinimizeStyle;
|
||||
}
|
||||
|
||||
if (max != null)
|
||||
{
|
||||
max.Style = MaximizeStyle;
|
||||
}
|
||||
|
||||
if (close != null)
|
||||
{
|
||||
close.Style = CloseStyle;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable 618
|
||||
|
||||
private void OnMinimize(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (ParentWindow != null)
|
||||
{
|
||||
SystemCommands.MinimizeWindow(ParentWindow);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMaximize(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (null == ParentWindow) return;
|
||||
if (ParentWindow.WindowState == WindowState.Maximized)
|
||||
{
|
||||
SystemCommands.RestoreWindow(ParentWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
SystemCommands.MaximizeWindow(ParentWindow);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClose(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var closingWindowEventHandlerArgs = new ClosingWindowEventHandlerArgs();
|
||||
OnClosingWindow(closingWindowEventHandlerArgs);
|
||||
|
||||
if (closingWindowEventHandlerArgs.Cancelled) return;
|
||||
ParentWindow?.Close();
|
||||
}
|
||||
|
||||
protected void OnClosingWindow(ClosingWindowEventHandlerArgs args)
|
||||
{
|
||||
ClosingWindow?.Invoke(this, args);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
71
AntDesignWPF/Controls/WindowCommands.cs
Normal file
71
AntDesignWPF/Controls/WindowCommands.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace AntDesign.WPF.Controls
|
||||
{
|
||||
public class WindowCommands : ItemsControl, INotifyPropertyChanged
|
||||
{
|
||||
#region Events
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected virtual void RaisePropertyChanged(string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
private AntdWindow _parentWindow;
|
||||
|
||||
public AntdWindow ParentWindow
|
||||
{
|
||||
get { return _parentWindow; }
|
||||
set
|
||||
{
|
||||
if (Equals(_parentWindow, value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_parentWindow = value;
|
||||
RaisePropertyChanged("ParentWindow");
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SeparatorHeightProperty =
|
||||
DependencyProperty.Register("SeparatorHeight", typeof(double), typeof(WindowCommands), new PropertyMetadata(double.NaN));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the height of the separator.
|
||||
/// </summary>
|
||||
public double SeparatorHeight
|
||||
{
|
||||
get { return (double)GetValue(SeparatorHeightProperty); }
|
||||
set { SetValue(SeparatorHeightProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static WindowCommands()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(WindowCommands), new FrameworkPropertyMetadata(typeof(WindowCommands)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class WindowCommandsItem : AntdContentControl
|
||||
{
|
||||
static WindowCommandsItem()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(WindowCommandsItem), new FrameworkPropertyMetadata(typeof(WindowCommandsItem)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user