WPF 自定义几种 MarkupExtension
MarkupExtension
详见: MarkupExtension.
#region 程序集 WindowsBase.dll, v3.0.0.0
// C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\WindowsBase.dll
#endregion
using System;
namespace System.Windows.Markup
{
// 摘要:
// 为所有 XAML 标记扩展提供基类。
public abstract class MarkupExtension
{
// 摘要:
// 初始化从 System.Windows.Markup.MarkupExtension 派生的类的新实例。
protected MarkupExtension();
// 摘要:
// 在派生类中实现时,返回一个对象,此对象被设置为此标记扩展的目标属性的值。
//
// 参数:
// serviceProvider:
// 可以为标记扩展提供服务的对象。
//
// 返回结果:
// 将在扩展应用到的属性上设置的对象值。
public abstract object ProvideValue(IServiceProvider serviceProvider);
}
}
Bool2ColorConverter
实现Bool? 对应三种颜色状态变化。 可以扩展到枚举对象的颜色状态变化
#region << 版 本 注 释 >>
/*
* ----------------------------------------------------------------
* Copyright @ Daniel大妞 2021. All rights reserved.
* 作 者 :Daniel大妞 (Daniel)
* 创建时间 :2021/6/11 17:25:35
* CLR 版本 :4.0.30319.42000
* 命名空间 :DN.Controls.Markup
* 类 名 称 :ColorChangedExtension
* 类 描 述 :
* ------------------------------------------------------
* 历史更新记录
* 版本 : V1.0.0.0 修改时间:2021/6/11 17:25:35 修改人:Daniel大妞 (Daniel)
* 修改内容:
*
*/
#endregion
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Markup;
using System.Windows.Media;
namespace DN.Controls.Converters
{
public class Bool2ColorConverter : MarkupExtension, IValueConverter
{
private static readonly Brush MS_Red = new SolidColorBrush(Colors.Red);
private static readonly Brush MS_Green = new SolidColorBrush(Colors.Green);
private static readonly Brush MS_Blue = new SolidColorBrush(Colors.Blue);
public Brush BrushWhenTrue { get; set; } = MS_Red;
public Brush BrushWhenNull { get; set; } = MS_Green;
public Brush BrushWhenFalse { get; set; } = MS_Blue;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
return this.BrushWhenNull;
}
else if ((bool)value)
{
return this.BrushWhenTrue;
}
else
{
return this.BrushWhenFalse;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
}
用法:
<Window
x:Class="wpf.Bool2ColorExtensionTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:wpf.Bool2ColorExtensionTest"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Grid>
<CheckBox
x:Name="PART_SSS"
Width="100"
Height="100"
IsThreeState="True" />
<Button
Width="200"
Height="200"
Margin="30,0,0,0"
HorizontalAlignment="Left"
Background="{Binding ElementName=PART_SSS, Path=IsChecked, Converter={local:Bool2ColorConverter BrushWhenFalse=Red, BrushWhenNull=Green, BrushWhenTrue=Blue}}"
Content="Button" />
</Grid>
</Window>
效果
CallExtension
将数据模型的函数与事件绑定起来
#region << 版 本 注 释 >>
/*
* ----------------------------------------------------------------
* Copyright @ Daniel大妞 2021. All rights reserved.
* 作 者 :Daniel大妞 (Daniel)
* 创建时间 :2021/6/1 10:20:19
* CLR 版本 :4.0.30319.42000
* 命名空间 :DN.Controls.Markup
* 类 名 称 :CallExtension
* 类 描 述 :
* ------------------------------------------------------
* 历史更新记录
* 版本 : V1.0.0.0 修改时间:2021/6/1 10:20:19 修改人:Daniel大妞 (Daniel)
* 修改内容:
*
*/
#endregion
using DN.Core;
using System;
using System.Reflection;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Markup;
namespace DN.Controls.Markup
{
public class CallExtension : MarkupExtension
{
private readonly string m_MethodNameField;
public CallExtension(string methodName)
{
this.m_MethodNameField = methodName;
}
/// <summary>
/// 当在派生类中实现时,返回用作此标记扩展的目标属性值的对象。
/// </summary>
/// <param name="serviceProvider">可为标记扩展提供服务的服务提供程序帮助程序。</param>
/// <returns>要在应用了扩展的属性上设置的对象值。</returns>
public override object ProvideValue(IServiceProvider serviceProvider)
{
IProvideValueTarget t = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
return new CallCommand(t.TargetObject as FrameworkElement, this.m_MethodNameField);
}
internal class CallCommand : DependencyObject, ICommand
{
private static readonly Type MS_ThisType = typeof(CallCommand);
private readonly FrameworkElement m_Element;
private readonly string m_MethodName;
private MethodInfo m_Method;
public CallCommand(FrameworkElement element, string methodName)
{
if (element != null)
{
this.m_Element = element;
this.m_MethodName = methodName;
element.DataContextChanged += this.OnDataContextChanged;
BindingOperations.SetBinding(this, CanCallProperty, new Binding("DataContext.Can" + methodName)
{
Source = element
});
this.GetMethod();
}
}
#region ICommand
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return this.m_Method != null && this.CanCall;
}
public void Execute(object parameter)
{
this.m_Method.Invoke(this.DataContext, null);
}
#endregion
/// <summary>
/// 元素对象数据上下文
/// </summary>
public object DataContext => this.m_Element.DataContext;
public bool CanCall
{
get => (bool)this.GetValue(CanCallProperty);
set => this.SetValue(CanCallProperty, value);
}
public static readonly DependencyProperty CanCallProperty =
DependencyProperty.Register(nameof(CanCall), typeof(bool), MS_ThisType, new PropertyMetadata(SharedInstances.BoxedTrue));
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == CanCallProperty)
{
this.RaiseCanExecuteChanged();
}
}
private void GetMethod()
{
this.m_Method = this.DataContext?.GetType().GetMethod(this.m_MethodName, Type.EmptyTypes);
}
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
this.GetMethod();
this.RaiseCanExecuteChanged();
}
private void RaiseCanExecuteChanged()
{
this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}
}
}
示例:
<Window
x:Class="wpf.CallExtensionTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:wpf.CallExtensionTest"
xmlns:markup="http://schemas.Daniel.com/DN.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Grid>
<Button Margin="85,29,448.6,278" Command="{markup:Call Run}" />
</Grid>
</Window>
using System.Windows;
namespace wpf.CallExtensionTest
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
public void Run()
{
;
}
public bool CanRun => true;
}
}
AssemblyTypeProviderExtension
#region << 版 本 注 释 >>
/*
* ----------------------------------------------------------------
* Copyright @ Daniel大妞 2021. All rights reserved.
* 作 者 :Daniel大妞 (Daniel)
* 创建时间 :2021/6/15 22:22:12
* CLR 版本 :4.0.30319.42000
* 命名空间 :DN.Controls.Converters
* 类 名 称 :AssemblyTypeProviderExtension
* 类 描 述 :
* ------------------------------------------------------
* 历史更新记录
* 版本 : V1.0.0.0 修改时间:2021/6/15 22:22:12 修改人:Daniel大妞 (Daniel)
* 修改内容:
*
*/
#endregion
using System;
using System.Globalization;
using System.Reflection;
using System.Windows.Data;
using System.Windows.Markup;
namespace DN.Controls.Converters
{
public class AssemblyTypeProviderExtension: MarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string assemblyPath = value as string;
if (string.IsNullOrWhiteSpace(assemblyPath) || !assemblyPath.EndsWith(".dll"))
{
return null;
}
else
{
try
{
Assembly ass = Assembly.LoadFrom(assemblyPath);
return ass.GetExportedTypes();
}
catch
{
return null;
}
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
}
示例:MainWindow.Xaml
<Window
x:Class="wpf_AssemblyExtensionTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:wpf_AssemblyExtensionTest"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="PART_This"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ListView Grid.Row="1" ItemsSource="{Binding ElementName=PART_This, Path=DllPath, UpdateSourceTrigger=PropertyChanged, Converter={local:AssemblyTypeProvider}}">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="FullName">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding FullName}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Fullss">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="sdf" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
<Button
x:Name="button"
Width="75"
Margin="16,10,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Click="button_Click"
Content="Button" />
<TextBox
x:Name="listBox"
Width="670"
Height="35"
Margin="105,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Text="{Binding ElementName=PART_This, Path=DllPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</Grid>
</Window>
示例:MainWindow.Xaml.cs
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.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace wpf_AssemblyExtensionTest
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public string DllPath
{
get { return (string)GetValue(DllPathProperty); }
set { SetValue(DllPathProperty, value); }
}
public static readonly DependencyProperty DllPathProperty =
DependencyProperty.Register("DllPath", typeof(string), typeof(MainWindow));
private void button_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog
{
AddExtension = true,
Filter = "All dll Files|*.dll;",
Multiselect = false,
CheckFileExists = true
};
if ((bool)openFileDialog.ShowDialog(Window.GetWindow(this)))
{
this.DllPath = openFileDialog.FileName;
}
}
}
}