[Version 2.0] Null command parameters

Jul 5, 2012 at 10:55 PM
Edited Jul 5, 2012 at 10:55 PM
I have a style that sets CloseCommand to a property on the main application view model...

Setter Property="CloseCommand"
="{Binding Path=LayoutElement.Root.Manager.DataContext.Command_TryCloseItem,
={RelativeSource Self}}" />

I expected to see in the command parameter the corresponding LayoutItem for the tab being
closed, or at least the corresponding Model. But the parameter is null. It would be very
helpful to have the parameter set, as it allows a more centralized way of controlling
the life cycle of documents.
Jul 10, 2012 at 4:41 PM

I ended up creating a MultiValue converter that would take a binding and create a command that calls on the bound object the method indicated by the parameter. Additional bindings are treated as parameters to the method call...

<Setter Property="CloseCommand">
        <MultiBinding Converter="{x:Static converters:Common.MethodCallCommand}" ConverterParameter="TryCloseItem">
            <Binding Path="LayoutElement.Root.Manager.DataContext" />
            <Binding Path="Model" />

This allows a single method on the main window view model to control how or whether any given child screen closes.

Sep 26, 2012 at 9:12 PM

Hey, Nice solution, could you show me how the converter looks like.



Sep 27, 2012 at 5:27 AM

Here's the converter...

/// <summary>
/// A MultiValueConverter that finds a method (specified by parameter) on the first bound value and creates a DelegateCommand
/// that will call that method when executed. Additional bindings will be passed in the method as parameters.
/// </summary>
public class MethodCallCommandConverter : MultiValueConverterBase<ICommand>
	protected override ICommand Convert(object[] fromValues, object parameter, System.Globalization.CultureInfo culture)
		var methodName = parameter as string;
		if (string.IsNullOrEmpty(methodName))
			throw new ArgumentException("argument 'parameter' must be a method name");
		if (fromValues.Length == 0 || fromValues[0] == null)
			throw new ArgumentException("argument 'fromValues' must contain a non-null value in the first element");
		object target = fromValues[0];
		object[] arguments = fromValues.Skip(1).ToArray();
		Type[] argumentTypes = arguments
			.Select(x => x == null ? typeof(object) : x.GetType())
		var methodInfoEx = GlobalTypeInfoCache.GetTypeInfo(target.GetType())
			.GetMethodInfoEx(methodName, argumentTypes);
		if (methodInfoEx == null)
			throw new InvalidOperationException(string.Format("Unable to find a method named '{0}' on bound value {2}", methodName, fromValues[0]));
		return new DelegateCommand(() => methodInfoEx.FastCaller(target, arguments));

Please forgive any formatting issues, the code snippet inserter doesn't seem to accept this. GlobalTypeInfoCache I got from http://www.codeproject.com/Articles/109868/General-DynamicObject-Proxy-and-Fast-Reflection-Pr. It just creates fast delegates for reflection and caches them. MultiValueConverterBase just provides some boilerplate code for type verification and argument validation.