ここで説明したボタンクリックイベントのマークアップ拡張機能を作成しています。
次の問題は、XAMLからviewmodelのメソッドにパラメーターを渡す方法です。
これはあなたが引数を渡すことを可能にする解決策です、あなたはあなたからの任意のプロパティとあなたの中にあるからのプロパティを送ることがDataContext
できControls
ますDataContext
MarkupExtension
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;
}
}
}
}
}
TestApp:
コード:
/// <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>
イベントメソッドバインディングの実装は次のとおりです。
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);
}