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

时间:2013-01-08 06:47:59

标签: c# .net wpf

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

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

2 个答案:

答案 0 :(得分:1)

以下是允许您传递参数的解决方案,您可以发送DataContext中的Controls以及DataContextpublic 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; } } } } } 的属性中的任何属性

的MarkupExtension

/// <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)
    {

    }
}

TestApp:

代码:

<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>

的Xaml:

{{1}}

答案 1 :(得分:0)

这是我对事件方法绑定的实现:

http://www.singulink.com/CodeIndex/post/building-the-ultimate-wpf-event-method-binding-extension

支持完整的属性路径支持,参数值的任意数量的参数,绑定和其他扩展方法,并根据提供的参数类型解析方法。

用法:

<!--  Basic usage  -->
<Button Click="{data:MethodBinding OpenFromFile}" Content="Open" />

<!--  Pass in a binding as a method argument  -->
<Button Click="{data:MethodBinding Save, {Binding CurrentItem}}" Content="Save" />

<!--  Another example of a binding, but this time to a property on another element  -->
<ComboBox x:Name="ExistingItems" ItemsSource="{Binding ExistingItems}" />
<Button Click="{data:MethodBinding Edit, {Binding SelectedItem, ElementName=ExistingItems}}" />

<!--  Pass in a hard-coded method argument, XAML string automatically converted to the proper type  -->
<ToggleButton Checked="{data:MethodBinding SetWebServiceState, True}"
                Content="Web Service"
                Unchecked="{data:MethodBinding SetWebServiceState, False}" />

<!--  Pass in sender, and match method signature automatically -->
<Canvas PreviewMouseDown="{data:MethodBinding SetCurrentElement, {data:EventSender}, ThrowOnMethodMissing=False}">
    <controls:DesignerElementTypeA />
    <controls:DesignerElementTypeB />
    <controls:DesignerElementTypeC />
</Canvas>

    <!--  Pass in EventArgs  -->
<Canvas MouseDown="{data:MethodBinding StartDrawing, {data:EventArgs}}"
        MouseMove="{data:MethodBinding AddDrawingPoint, {data:EventArgs}}"
        MouseUp="{data:MethodBinding EndDrawing, {data:EventArgs}}" />

<!-- Support binding to methods further in a property path -->
<Button Content="SaveDocument" Click="{data:MethodBinding CurrentDocument.DocumentService.Save, {Binding CurrentDocument}}" />

查看模型方法签名:

public void OpenFromFile();
public void Save(DocumentModel model);
public void Edit(DocumentModel model);

public void SetWebServiceState(bool state);

public void SetCurrentElement(DesignerElementTypeA element);
public void SetCurrentElement(DesignerElementTypeB element);
public void SetCurrentElement(DesignerElementTypeC element);

public void StartDrawing(MouseEventArgs e);
public void AddDrawingPoint(MouseEventArgs e);
public void EndDrawing(MouseEventArgs e);

public class Document
{
    // Fetches the document service for handling this document
    public DocumentService DocumentService { get; }
}

public class DocumentService
{
    public void Save(Document document);
}