pkr
pkr

Reputation: 1761

How do I databind a property to a method and pass in parameters?

I have a grid with a rectangle in each cell in the xaml. I know I can bind the fill of each rectangle to a property in my ViewModel, but I want to instead bind the fill of each rectangle to a method in the ViewModel and pass in the x- and y- coordinates of the rectangle, and get back the fill (which can change during runtime).

Is there an easy way to do this? I don't know if this is even possible, since when the method changes the fill it returns for a particular x- and y- coordinate, how would the view know that the method updated that value?

The problem I'm facing is that since the ViewModel doesn't know about any of the UI controls on the View, I can't just directly change the fill colors on the rectangles. Also, since the grid can be large, I can't have a separate property for each rectangle.

Upvotes: 0

Views: 869

Answers (3)

sellmeadog
sellmeadog

Reputation: 7517

This may not work in your scenario, but you can invoke a method from a binding using an ObjectDataProvider. Here's a quick example:

<Window.Resources>
  <local:StringToDoubleConverter x:Key="stringToDouble" />

  <local:MyObject x:Key="objInstance" />

  <ObjectDataProvider
    x:Key="odp"
    ObjectInstance="{StaticResource objInstance}"
    ObjectMethod="MyMethod"
    >
    <ObjectDataProvider.MethodParameters>
      <sys:Double>0</sys:Double>
    </ObjectDataProvider.MethodParameters>
  </ObjectDataProvider>
</Window.Resources>

Now, an element in your view, say a TextBox can bind to the method parameter:

<TextBox Text={Binding Source={StaticResource odp}, Path=MethodParameters[0], UpdateSourceTrigger=PropertyChanged, Converter={StaticResource stringToDouble}} />

The method return value can then be used in a binding elsewhere:

<Label Content="{Binding Source={StaticResource odp}}" ContentStringFormat="Method returned: {0}" />

Again, this may not work in your scenario, but it does illustrate a way to pass a parameter to a method and use the return value entirely in XAML. Here's a resource for more information: http://bea.stollnitz.com/blog/?p=22

Upvotes: 1

RoelF
RoelF

Reputation: 7573

You could try using an IValueConverter for this:

[ValueConversion(typeof (MyCoordObject), typeof (Brush))]
public class CoordToBrushConverter : ConverterExtension
{
   public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var coordObject= (MyCoordObject) value;

        if (coordObject.X == 132) return Brushes.Red; 
        //define your own brushes as StaticResource or something, this won't work
        return Brushes.Black;
    }


    public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        //nothing
        return value;
    }
}

Now you just have to figure out which object you wanna pass to the converter. Use this in your XAML like this:

<my:CoordToBrushConverter x:key="myConverter"/>
<TextBox BackgroundBrush={Binding myObj, Converter={StaticResource myConverter}} />

If you don't have an object which contains to coordinates, maybe you can use a MultiValueConverter and pass the coordinates one by one from the control? You should play around with this to get it to work probably.

If you don't wanna use converters, you could always check out some of the MVVM frameworks out there, if I'm not mistaken some of them support binding to methods.
Check Caliburn or MVVMLight

HTH

Upvotes: 0

ColinE
ColinE

Reputation: 70142

Binding cannot be used as a way to invoke methods and pass parameters. It is merely a mechanism for synchronising state between your view and your view model.

In your case, the view model needs to know the coordinates of your rectangle in order to determine the fill. Therefore, for each rectangle, your view model needs to expose X, Y, Fill properties.

The big problem here is how to supply the view model with the X & Y coordinates? I am guessing these rectangles are within some sort of container that dictates their location? If so, the only technique I can think of is to create an attached behaviour for a UIElement that calculates its position via TransformToVisual. See for example:

http://forums.silverlight.net/forums/p/12160/414862.aspx

This can then be bound to your X & Y values in your view model.

However, to be honest, if you struggle to get MVVM working here, perhaps it is the wrong pattern?

If you are just building a UI which is composed of coloured rectangles, I would just do it in a loop, adding Rectangles and colouring them in code-behind!

KISS (Keep It Simple Stupid!)

Upvotes: 0

Related Questions