c# - 如何将参数从 XAML 中定义的事件的 MarkupExtension 传递到 wpf 4.5 中模型中定义的方法

标签 c# .net wpf

我正在为我已经讨论过的按钮单击事件创建标记扩展 here .

我的下一个问题是如何将参数从 XAML 传递到 viewmodel 中的方法?

最佳答案

这是一个允许您传递参数的解决方案,您可以发送 DataContext 中的任何属性和 DataContext 中的 Controls 中的属性>

标记扩展

public class Call : MarkupExtension
{
    public Call() { }

    public string MethodName { get; set; }
    public string Path { get; set; }
    public string ElementName { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        IProvideValueTarget targetProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
        if (targetProvider != null)
        {
            var target = targetProvider.TargetObject as FrameworkElement;
            if (target != null)
            {
                if (targetProvider.TargetProperty is MethodInfo)
                {
                    var targetEventAddMethod = targetProvider.TargetProperty as MethodInfo;
                    if (targetEventAddMethod != null)
                    {
                        var delegateType = targetEventAddMethod.GetParameters()[1].ParameterType;
                        var methodInfo = this.GetType().GetMethod("MyProxyHandler", BindingFlags.NonPublic | BindingFlags.Instance);
                        return Delegate.CreateDelegate(delegateType, this, methodInfo); ;
                    }
                }
                else if (targetProvider.TargetProperty is EventInfo)
                {
                    var targetEventInfo = targetProvider.TargetProperty as EventInfo;
                    if (targetEventInfo != null)
                    {
                        var delegateType = targetEventInfo.EventHandlerType;
                        MethodInfo methodInfo = this.GetType().GetMethod("MyProxyHandler", BindingFlags.NonPublic | BindingFlags.Instance);
                        return Delegate.CreateDelegate(delegateType, this, methodInfo);
                    }
                }
            }
        }
        return null;
    }

    void MyProxyHandler(object sender, EventArgs e)
    {
        FrameworkElement target = sender as FrameworkElement;
        if (target == null) return;
        var dataContext = target.DataContext;
        if (dataContext == null) return;

        //get the method on the datacontext from its name
        MethodInfo methodInfo = dataContext.GetType().GetMethod(MethodName, BindingFlags.Public | BindingFlags.Instance);
        if (!string.IsNullOrEmpty(ElementName))
        {
            var element = FindVisualChildren(dataContext as DependencyObject).FirstOrDefault(c => c.Name.Equals(ElementName));
            if (element != null)
            {
                var path = element.GetType().GetProperty(Path);
                if (path != null)
                {
                    methodInfo.Invoke(dataContext, new object[] { path.GetValue(element, null) });
                }
                return;
            }
        }

        if (!string.IsNullOrEmpty(Path))
        {
            var path = dataContext.GetType().GetProperty(Path);
            if (path != null)
            {
                methodInfo.Invoke(dataContext, new object[] { path.GetValue(dataContext, null) });
            }
            return;
        }

        methodInfo.Invoke(dataContext,null);
    }

    private IEnumerable<FrameworkElement> FindVisualChildren(DependencyObject obj) 
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(obj, i);
            if (child != null && child is FrameworkElement)
            {
                yield return (FrameworkElement)child;
            }
            var childOfChild = FindVisualChildren(child);
            if (childOfChild != null)
            {
                foreach (var subchild in childOfChild)
                {
                    yield return subchild;
                }
            }
        }
    }
}

测试应用:

代码:

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window 
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private int myVar = 700;
    public int MyProperty
    {
        get { return myVar; }
        set { myVar = value; }
    }

    public void TestMethod1()
    {

    }

    public void TestMethod2(int value)
    {

    }

    public void TestMethod3(string value)
    {

    }
}

Xaml:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication11"
        xmlns:System="clr-namespace:System;assembly=mscorlib" x:Class="WpfApplication11.MainWindow"
        Title="MainWindow" Height="123" Width="275" x:Name="UI"
        >
    <Grid DataContext="{Binding ElementName=UI}">
        <StackPanel>
        <TextBlock Name="txtblock" Text="Hello" />
            <Button Click="{local:Call  MethodName=TestMethod1}" Height="24"/>
            <Button Click="{local:Call  MethodName=TestMethod2, Path=MyProperty}"  Height="24"/>
            <Button Click="{local:Call  MethodName=TestMethod3, ElementName=txtblock, Path=Text}" Height="24" />
        </StackPanel>
    </Grid>
</Window>

关于c# - 如何将参数从 XAML 中定义的事件的 MarkupExtension 传递到 wpf 4.5 中模型中定义的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14209616/

相关文章:

C# ToDictionary lambda 选择索引和元素?

c# - 安装向导 (visual studio 2010) 完成后如何启动应用程序

c# - 是否可以将非主键设置为另一个表中的外键?

c# - 在 C# 或 OOP 中,两个相关的类是否应该相互引用?

c# - WPF DataContext 在看似相同的情况下工作方式不同

wpf - IMul​​tiValueConverter 值没问题,但 CommandParameter 为空

c# - 如何检查一个 char 数组是否包含另一个 char 数组中的每个元素?

c# - EF Core 迁移不会获取所有属性

.net - 我可以让 .NET 框架类实现我定义的接口(interface)吗?

c# - 与 ViewModel 共享 EntityFramework 上下文