2025-08-24 13:49:55 +08:00
|
|
|
|
using System.Windows.Markup;
|
|
|
|
|
|
using System.Windows.Media.Imaging;
|
|
|
|
|
|
using System.Xaml;
|
2026-01-02 17:30:41 +08:00
|
|
|
|
using Melskin.Appearance;
|
|
|
|
|
|
using Melskin.Assets;
|
|
|
|
|
|
using Melskin.Controls;
|
2025-08-24 13:49:55 +08:00
|
|
|
|
|
2026-01-02 17:30:41 +08:00
|
|
|
|
namespace Melskin.Markup
|
2025-08-24 13:49:55 +08:00
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 方便在 XAML 中内联创建 IconElement 的标记扩展。
|
|
|
|
|
|
/// 用法示例:
|
|
|
|
|
|
/// <code lang="xaml">
|
2026-01-02 17:30:41 +08:00
|
|
|
|
/// xmlns:neo="clr-namespace:Melskin.Markup;assembly=Melskin"
|
2025-08-24 13:49:55 +08:00
|
|
|
|
/// <!-- MaterialSymbol -->
|
|
|
|
|
|
/// <Button Content="{neo:Icon Search Size=16}"/>
|
|
|
|
|
|
/// <!-- 指定 Glyph -->
|
2026-01-02 17:30:41 +08:00
|
|
|
|
/// <Button Content="{neo:Icon Glyph= FontFamily=/Melskin;component/Assets/Fonts/#YourFont Size=16}"/>
|
2025-08-24 13:49:55 +08:00
|
|
|
|
/// <!-- 几何 -->
|
|
|
|
|
|
/// <Button Content="{neo:Icon Geo=M0,0 L10,0 10,10 0,10Z GeometryFill=DodgerBlue Size=16}"/>
|
|
|
|
|
|
/// <!-- 图像 -->
|
2026-01-02 17:30:41 +08:00
|
|
|
|
/// <Button Content="{neo:Icon Image=/Melskin;component/Assets/Images/add.png Size=20}"/>
|
2025-08-24 13:49:55 +08:00
|
|
|
|
/// <!-- 资源中的 DrawingBrush -->
|
|
|
|
|
|
/// <Button Content="{neo:Icon BrushKey=SomeDrawingBrush Size=20}"/>
|
|
|
|
|
|
/// </code>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[MarkupExtensionReturnType(typeof(IconElement))]
|
|
|
|
|
|
public class IconExtension : MarkupExtension
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图标符号的字符串表示形式。此属性用于指定要显示的图标的名称。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
2025-10-04 08:52:23 +08:00
|
|
|
|
/// 通过设置此属性,可以使用一个字符串来标识所需的图标。如果设置了此属性且<see cref="Symbol"/>未被设置,则会尝试将这个字符串解析为有效的图标符号。
|
2025-08-24 13:49:55 +08:00
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public string? Symbol { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图标的值。此属性用于直接指定图标的具体值。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以直接指定一个具体的图标值。如果<see cref="SymbolValue"/>被设置,则会优先使用这个值来显示图标,而不是通过字符串解析的方式。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public MaterialSymbol? SymbolValue { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图标的字符表示。此属性用于指定要显示的图标的具体字符。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以使用一个字符来标识所需的图标。这个字符通常是从特定字体中选择的一个图标符号,例如BoxIcons等图标字体中的某个字符。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public string? Glyph { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图标图像的源。此属性用于指定要显示的图像的位置。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以使用一个字符串来标识图像的来源路径。如果设置了此属性且其他与图像相关的属性未被设置,则会尝试将这个字符串解析为有效的图像源,并加载相应的图像。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public string? Image { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置几何图形的字符串表示形式。此属性用于指定要显示的几何图形的数据。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以使用一个字符串来定义所需的几何图形。如果设置了此属性且字符串有效,则会尝试将这个字符串解析为几何图形数据并应用到图标元素上。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public string? Geo { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置用于查找绘图资源的键。此属性允许通过指定的键从资源中检索绘图对象。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 当设置了此属性且提供的键有效时,将尝试从当前资源上下文中查找对应的绘图资源,并将其应用于图标元素。如果找到了与键匹配的绘图资源,则该资源会被用作图标的内容。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public string? DrawingKey { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置用于查找画刷资源的键。此属性允许通过资源字典中的键来指定一个画刷或绘图画刷。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以使用一个字符串作为键来引用应用程序资源中的画刷对象(<see cref="Brush"/>)或绘图画刷对象(<see cref="DrawingBrush"/>)。如果设置了此属性,并且在资源字典中找到了对应的资源,则会将该资源应用到图标元素上。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public string? BrushKey { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图标的大小。此属性用于指定图标在显示时的尺寸。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以控制图标元素的高度和宽度。如果设置了<see cref="Size"/>属性而未明确设置<see cref="Height"/>和<see cref="Width"/>,则<see cref="Height"/>和<see cref="Width"/>将默认采用<see cref="Size"/>的值。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public double Size { get; set; } = double.NaN;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图标的宽度。此属性用于指定图标元素的宽度。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以自定义图标元素的宽度。如果设置了此属性且没有设置<see cref="Size"/>属性,则会直接使用这个值作为图标的宽度。如果同时设置了<see cref="Size"/>和<see cref="Width"/>,则<see cref="Width"/>优先级更高。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public double Width { get; set; } = double.NaN;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图标的高度。此属性用于指定图标在显示时的高度。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以控制图标元素的高度。如果设置了<see cref="Size"/>属性而未明确设置<see cref="Height"/>,则<see cref="Height"/>将默认采用<see cref="Size"/>的值。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public double Height { get; set; } = double.NaN;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图标的前景色。此属性用于指定图标中文字或几何图形部分的颜色。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以自定义图标的颜色。如果未显式设置此属性,则可能使用默认值或其他相关属性来确定颜色。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public Brush? Foreground { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置几何图形填充的画刷。此属性用于指定图标中几何图形部分的填充颜色。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以自定义图标的几何图形部分的填充效果。如果未显式设置此属性,则可能使用默认值或其他相关属性(如<see cref="Foreground"/>)来确定填充颜色。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public Brush? GeometryFill { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置几何图形描边的颜色。此属性用于指定图标的几何形状边缘所使用的画刷。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以自定义图标中几何形状边缘的颜色。如果设置了此属性,则会使用指定的画刷来绘制几何形状的边缘。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public Brush? GeometryStroke { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置几何图形描边的厚度。此属性用于控制图标的几何形状描边宽度。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以自定义图标中几何图形描边的宽度。如果设置了此属性且值不是NaN,则会应用指定的描边厚度。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public double GeometryStrokeThickness { get; set; } = double.NaN;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图标内容的类型。此属性用于指定图标的显示方式。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以定义图标是作为材料图标、字形、图像、几何图形、绘图还是画刷来展示。默认值为Auto,表示自动选择最合适的内容类型。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public IconElement.IconContentType ContentType { get; set; } = IconElement.IconContentType.Auto;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图标的字体系列。此属性用于指定图标所使用的字体,以便正确显示图标符号。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以指定一个字体系列来确保图标能够以正确的样式显示。如果设置了此属性,则会应用到图标元素的字体系列上。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public FontFamily? FontFamily { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图标的字体大小。此属性用于控制图标显示时的字体大小。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以指定图标字体的具体大小。如果设置了此属性且未被其他尺寸属性覆盖,则会使用这个值来设置图标的字体大小。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public double FontSize { get; set; } = double.NaN;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图像的拉伸模式。此属性决定了图像如何填充其布局空间。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以控制图像在显示时的拉伸方式。默认值为 <see cref="Stretch.Uniform"/>,表示图像将按比例缩放以适应可用空间,同时保持其原始宽高比。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public Stretch ImageStretch { get; set; } = Stretch.Uniform;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图标元素的边距。此属性用于控制图标与其容器之间的空间。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以自定义图标在布局中的位置和间距。边距值是一个<see cref="Thickness"/>类型的对象,允许指定左、上、右、下四个方向的边距。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public Thickness Margin { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图标元素的水平对齐方式。此属性用于指定图标在其容器中的水平位置。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以控制图标在水平方向上的对齐方式。默认值为居中对齐(HorizontalAlignment.Center)。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public HorizontalAlignment HorizontalAlignment { get; set; } = HorizontalAlignment.Center;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图标在垂直方向上的对齐方式。此属性用于控制图标在其容器中的垂直位置。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// 通过设置此属性,可以指定图标在其容器中是顶部对齐、居中对齐还是底部对齐。默认情况下,图标是居中对齐的。
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public VerticalAlignment VerticalAlignment { get; set; } = VerticalAlignment.Center;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 用于在XAML中创建图标元素的标记扩展。通过设置不同的属性,可以自定义图标的样式和内容。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public IconExtension()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 用于在XAML中创建图标元素的标记扩展。通过设置不同的属性,可以自定义图标的样式、内容和外观。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public IconExtension(string symbol)
|
|
|
|
|
|
{
|
|
|
|
|
|
Symbol = symbol;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-04 08:52:23 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 用于在XAML中创建图标元素的标记扩展。通过设置不同的属性,可以自定义图标的样式、内容和外观。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public IconExtension(MaterialSymbol materialSymbol)
|
|
|
|
|
|
{
|
|
|
|
|
|
SymbolValue = materialSymbol;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-24 13:49:55 +08:00
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public override object ProvideValue(IServiceProvider serviceProvider)
|
|
|
|
|
|
{
|
|
|
|
|
|
var icon = new IconElement();
|
|
|
|
|
|
|
|
|
|
|
|
// 尺寸
|
|
|
|
|
|
if (!double.IsNaN(Size))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (double.IsNaN(Width)) icon.Width = Size;
|
|
|
|
|
|
if (double.IsNaN(Height)) icon.Height = Size;
|
|
|
|
|
|
if (double.IsNaN(FontSize)) FontSize = Size;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!double.IsNaN(Width)) icon.Width = Width;
|
|
|
|
|
|
if (!double.IsNaN(Height)) icon.Height = Height;
|
|
|
|
|
|
|
|
|
|
|
|
if (!double.IsNaN(FontSize)) icon.SetValue(Control.FontSizeProperty, FontSize);
|
|
|
|
|
|
if (FontFamily != null) icon.SetValue(Control.FontFamilyProperty, FontFamily);
|
|
|
|
|
|
if (Margin != default) icon.Margin = Margin;
|
|
|
|
|
|
|
|
|
|
|
|
icon.HorizontalAlignment = HorizontalAlignment;
|
|
|
|
|
|
icon.VerticalAlignment = VerticalAlignment;
|
|
|
|
|
|
|
|
|
|
|
|
if (Foreground != null)
|
|
|
|
|
|
icon.SetValue(Control.ForegroundProperty, Foreground);
|
|
|
|
|
|
|
|
|
|
|
|
// 上下文(已移除元组)
|
|
|
|
|
|
var ctx = GetContext(serviceProvider);
|
|
|
|
|
|
var resourceOwner = ctx.RootObject as FrameworkElement ?? ctx.TargetObject as FrameworkElement;
|
|
|
|
|
|
|
|
|
|
|
|
// Drawing
|
|
|
|
|
|
if (!string.IsNullOrEmpty(DrawingKey))
|
|
|
|
|
|
{
|
|
|
|
|
|
var drawingObj = TryFindResource(resourceOwner, DrawingKey);
|
|
|
|
|
|
if (drawingObj is Drawing d)
|
|
|
|
|
|
{
|
|
|
|
|
|
icon.Drawing = d;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DrawingBrush / Brush
|
|
|
|
|
|
if (!string.IsNullOrEmpty(BrushKey))
|
|
|
|
|
|
{
|
|
|
|
|
|
var brushObj = TryFindResource(resourceOwner, BrushKey);
|
|
|
|
|
|
switch (brushObj)
|
|
|
|
|
|
{
|
|
|
|
|
|
case DrawingBrush db:
|
|
|
|
|
|
icon.DrawingBrush = db;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case Brush b:
|
|
|
|
|
|
GeometryFill ??= b;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Geometry
|
|
|
|
|
|
if (!string.IsNullOrEmpty(Geo))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var g = Geometry.Parse(Geo);
|
|
|
|
|
|
if (g.CanFreeze) g.Freeze();
|
|
|
|
|
|
icon.Geometry = g;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
// ignored
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Image
|
|
|
|
|
|
if (!string.IsNullOrEmpty(Image))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var uri = TryCreateUri(Image);
|
|
|
|
|
|
if (uri != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var bmp = new BitmapImage();
|
|
|
|
|
|
bmp.BeginInit();
|
|
|
|
|
|
bmp.UriSource = uri;
|
|
|
|
|
|
bmp.CacheOption = BitmapCacheOption.OnLoad;
|
|
|
|
|
|
bmp.EndInit();
|
|
|
|
|
|
if (bmp.CanFreeze) bmp.Freeze();
|
|
|
|
|
|
icon.ImageSource = bmp;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch { }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Glyph
|
|
|
|
|
|
if (!string.IsNullOrEmpty(Glyph))
|
|
|
|
|
|
icon.Glyph = Glyph;
|
|
|
|
|
|
|
|
|
|
|
|
// Symbol
|
|
|
|
|
|
if (SymbolValue.HasValue)
|
|
|
|
|
|
icon.Symbol = SymbolValue.Value;
|
|
|
|
|
|
else if (!string.IsNullOrEmpty(Symbol))
|
|
|
|
|
|
icon.Symbol = IconElement.Parse(Symbol);
|
|
|
|
|
|
|
|
|
|
|
|
// ContentType
|
|
|
|
|
|
if (ContentType != IconElement.IconContentType.Auto)
|
|
|
|
|
|
icon.ContentType = ContentType;
|
|
|
|
|
|
|
|
|
|
|
|
// Geometry 样式
|
|
|
|
|
|
if (icon.Geometry != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (GeometryFill != null)
|
|
|
|
|
|
icon.GeometryFill = GeometryFill;
|
|
|
|
|
|
else if (Foreground != null && icon.GeometryFill == System.Windows.Media.Brushes.Black)
|
|
|
|
|
|
icon.GeometryFill = Foreground;
|
|
|
|
|
|
|
|
|
|
|
|
if (GeometryStroke != null)
|
|
|
|
|
|
icon.GeometryStroke = GeometryStroke;
|
|
|
|
|
|
|
|
|
|
|
|
if (!double.IsNaN(GeometryStrokeThickness))
|
|
|
|
|
|
icon.GeometryStrokeThickness = GeometryStrokeThickness;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
icon.ImageStretch = ImageStretch;
|
|
|
|
|
|
return icon;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private sealed class ProvideContext
|
|
|
|
|
|
{
|
|
|
|
|
|
public object? TargetObject { get; set; }
|
|
|
|
|
|
public object? TargetProperty { get; set; }
|
|
|
|
|
|
public object? RootObject { get; set; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static ProvideContext GetContext(IServiceProvider serviceProvider)
|
|
|
|
|
|
{
|
|
|
|
|
|
object? targetObject = null;
|
|
|
|
|
|
object? targetProperty = null;
|
|
|
|
|
|
object? rootObject = null;
|
|
|
|
|
|
|
|
|
|
|
|
var pvt = serviceProvider?.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
|
|
|
|
|
|
if (pvt != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
targetObject = pvt.TargetObject;
|
|
|
|
|
|
targetProperty = pvt.TargetProperty;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var rop = serviceProvider?.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider;
|
|
|
|
|
|
if (rop != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
rootObject = rop.RootObject;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return new ProvideContext
|
|
|
|
|
|
{
|
|
|
|
|
|
TargetObject = targetObject,
|
|
|
|
|
|
TargetProperty = targetProperty,
|
|
|
|
|
|
RootObject = rootObject
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static object? TryFindResource(FrameworkElement? fe, string? key)
|
|
|
|
|
|
{
|
2025-10-04 08:52:23 +08:00
|
|
|
|
if (fe == null||key == null) return null;
|
2025-08-24 13:49:55 +08:00
|
|
|
|
var found = fe?.TryFindResource(key);
|
|
|
|
|
|
if (found != null) return found;
|
|
|
|
|
|
if (Application.Current != null && Application.Current.Resources.Contains(key))
|
|
|
|
|
|
return Application.Current.Resources[key];
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return ThemeManager.Current?.TryFindResource(key);
|
|
|
|
|
|
}
|
|
|
|
|
|
//return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static Uri? TryCreateUri(string? path)
|
|
|
|
|
|
{
|
2025-10-04 08:52:23 +08:00
|
|
|
|
if (string.IsNullOrEmpty(path)) return null;
|
|
|
|
|
|
if (path!.IndexOf(";component/", StringComparison.OrdinalIgnoreCase) >= 0 ||
|
2025-08-24 13:49:55 +08:00
|
|
|
|
path.StartsWith("pack://", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!path.StartsWith("pack://", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
path = "pack://application:,,," + (path.StartsWith("/") ? path : "/" + path);
|
|
|
|
|
|
return new Uri(path, UriKind.Absolute);
|
|
|
|
|
|
}
|
|
|
|
|
|
return Uri.TryCreate(path, UriKind.RelativeOrAbsolute, out var u) ? u : null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|