我正在为我已经讨论过的按钮单击事件创建标记扩展 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/