wpf multibinding to viewmodel?
Asked Answered
G

4

6

How does one add a multibinding to several viewmodel objects in xaml?

I need to bind the IsEnabled property of a context menu to two integers in my viewmodel. The following binding doesn't work, since its designed for GUI components. How would I do it to work with my ints?

<MenuItem ItemsSource="{Binding MyMenuItem}">
    <MenuItem.IsEnabled>
        <MultiBinding>
            <Binding ElementName="FirstInt" Path="Value" />
            <Binding ElementName="SecondInt" Path="Value" />
        </MultiBinding>
    </MenuItem.IsEnabled>
</MenuItem>

MyMenuItem is CLR object with the two integers, FirstInt and SecondInt.

Gey answered 12/10, 2009 at 7:44 Comment(1)
give more detail or source code to reproduce your problemHarry
J
21

Filip's answer was acceptable, but for anyone looking for Filip's desired solution, the following should do it:

<MenuItem ItemsSource="{Binding MyMenuItem}">
    <MenuItem.IsEnabled>
        <MultiBinding  Converter="{StaticResource IntsToEnabledConverter}">
            <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=Window}" Path="DataContext.FirstInt" />
            <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=Window}" Path="DataContext.SecondInt" />
        </MultiBinding>
    </MenuItem.IsEnabled>
</MenuItem>

It should be noted that the AncestorType on the binding may need to be changed accordingly. I assumed the view model was set as the DataContext of the window, but the same idea applies to user controls, etc.

Joselynjoseph answered 13/6, 2014 at 4:47 Comment(1)
This should be accepted answer. If it doesn't work for you, try to explicitly add NotifyOnSourceUpdated="True" to both bindings.Warms
H
2

For your particular example you need an IMultiValueConverter that will convert the two integers to a boolean value representing whether the menu item is enabled or not. Something like this:

Public Class MVCIntsToEnabled
    Implements IMultiValueConverter

    Public Function Convert(ByVal values() As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IMultiValueConverter.Convert
        If values IsNot Nothing Then
            If values.Count = 2 Then
                Return (values(0) > 0) AndAlso (values(1) > 0)
            Else
                Return False
            End If
        Else
            Throw New ArgumentNullException("values")
        End If
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetTypes() As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object() Implements System.Windows.Data.IMultiValueConverter.ConvertBack
        Throw New NotImplementedException()
    End Function

End Class

Used like this:

<local:MVCIntsToEnabled x:Key="IntsToEnabledConverter"  />

...

<MenuItem ItemsSource="{Binding MyMenuItem}">
    <MenuItem.IsEnabled>
        <MultiBinding  Converter="{StaticResource IntsToEnabledConverter}">
            <Binding ElementName="FirstInt" Path="Value" />
            <Binding ElementName="SecondInt" Path="Value" />
        </MultiBinding>
    </MenuItem.IsEnabled>
</MenuItem>
Henriettehenriha answered 12/10, 2009 at 14:21 Comment(0)
H
2

Bluebit your wait is over...create a style for your target control instead.

Here is an example where I have a button which is a Login button which needs to be disabled if a combo box (named comboConfig) does not have a selection yet (selected index -1) or if a boolean value on my ViewModel is set to true (LoginInProcess). For the ViewModel boolean I simply set the its path to be the member name property, which is bound at the style time to the windows datacontext:

<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
    <Style.Triggers>
        <DataTrigger Value="True">
            <DataTrigger.Binding>
                <MultiBinding Converter="{StaticResource MultiComboBoolBoolFalse}">
                    <Binding ElementName="comboConfig" Path="SelectedIndex" />
                    <Binding Path="LoginInProcess"/>
                </MultiBinding>
            </DataTrigger.Binding>
            <Setter Property="IsEnabled" Value="False"/>
        </DataTrigger>
    </Style.Triggers>
</Style>
Hewett answered 15/1, 2013 at 17:49 Comment(0)
M
1

This is an old post I know but I have the same problem and couldn't find any solution on the net.

I think what he is asking is how to use a multibinding which doesn't bind to a GUI element instead binds to more than one property in the view model.

Something like this:

Xaml:

<MenuItem ItemsSource="{Binding MyMenuItem}">
    <MenuItem.IsEnabled>
        <MultiBinding  Converter="{StaticResource IntsToEnabledConverter}">
            <Binding Source="{Binding FirstInt}" />
            <Binding Source="{Binding SecondInt}" />
        </MultiBinding>
    </MenuItem.IsEnabled>
</MenuItem>

ViewModel:

public class ViewModel
{
 public int FirstInt{ get { return _firstInt;}}
 public int SecondInt{ get { return _secondInt;}}

}

I haven't been able to figure this out either. Instead I used a SingleValueConverter and a binding to a parent object which holds both the variables FirstInt and SecondInt and in the converter use this parent, smth like:

 public class IntsToEnabledConverter :IValueConverter 
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            Parent parent = value as Parent;

            if (parent.FirstInt == 1 && parent.SecondInt == 1)
                return true;
            else
                return false;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

It's not as clean as if a Multibinding as the parent could be a bigger object with many more members but it worked in my case. I would have better looking code if I could use the Multibinding solution.

Movement answered 5/10, 2010 at 4:9 Comment(1)
Binding the source of a Binding gives a runtime exception.Switzerland

© 2022 - 2024 — McMap. All rights reserved.