3
votes

Imagine you have a list of user selections. Depending on what selections the user has made, other selections may not be available anymore.

I have a ValueConverter that could potentially handle this. If it knows what selections are made, it will return a value indicating if the item being converted is still selectable.

The problem is that the only place to know what the user selections are is in the ViewModel for this screen. No problem, I though. I'll make the converter a property on the ViewModel, and in the constructor for the converter, I'll pass a reference to the ViewModel, so that the converter can check the list of selected items any time it wants.

The problem I'm having now is that it doesn't seem to actually be performing any conversions.

To boil it down: The ViewModel has a property called MySelectionConverter of type IValueConverter. The ViewModel has a list of selected items. In the View (of type MyScreen which inherits from UserControl), there is a listbox with items.

The ItemTemplate looks something like this:

<ListBox.ItemTemplate>
    <DataTemplate>
        <Grid Height="Auto" Width="100" VerticalAlignment="Top"  Visibility="{Binding Path=DataContext.MySelectionConverter, RelativeSource={RelativeSource AncestorType={x:Type MyScreen}}}">
            <TextBlock Text="The user might want to select me." />
        </Grid>
    </DataTemplate>
</ListBox.ItemTemplate>

I suspect something is wrong with my binding. But maybe you just can't do this at all. Any help is appreciated.

Edit: Based on the information I've gained so far, my binding was incorrect. But it turns out that I can't do what I was trying to do. In essence, I was trying to set the converter via a Binding using:

Visibility="{Binding Converter={Binding Path=DataContext.StyleOptionConverter, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:StyleSelectionScreen}}}}

Visual studio tells me:

A 'Binding' cannot be set on the 'Converter' property of type 'Binding'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.

So, now I guess the problem becomes: In what way I can get around this? I need to have a converter that knows about the state of the ViewModel for the screen it will be used in.

2

2 Answers

3
votes

Your binding is wrong. the converter is a property of the binding, not within the Path Property

here's some example code from a project of mine:

<local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>

And below:

<DataGrid ItemsSource="{Binding Path=Tracks, IsAsync=True}" AutoGenerateColumns="False" Height="130" HorizontalAlignment="Left" Name="dataGrid2" 
                                  Visibility="{Binding Path=ShowSongs, Converter={StaticResource BooleanToVisibilityConverter}, Mode=TwoWay}" GridLinesVisibility="Vertical" 
                                  AlternatingRowBackground="{StaticResource Background}">
                            <DataGrid.Columns>
                                <DataGridTextColumn Header="Song" Width="*" Binding="{Binding Name}" />
                                <DataGridTextColumn Header="Artist"  Width="*" Binding="{Binding Artist}" />
                                <DataGridTextColumn Header="Album" Width="*" Binding="{Binding Album}" />
                            </DataGrid.Columns>
                        </DataGrid>

where the converter is a class in the same namespace as the viewmodel

public class BooleanToVisibilityConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return (true.Equals(value)) ? Visibility.Visible : Visibility.Hidden;
    }

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

Turns out what I really need was a MultiBinding and an IMultiValueConverter.

The XAML winds up looking like this:

<Grid.Visibility>
    <MultiBinding Converter="{StaticResource styleOptionConverter}">
        <Binding />
        <Binding ElementName="UserControl" Path="DataContext" />
    </MultiBinding>
</Grid.Visibility>

Although, admittedly, I'd rather use a RelativeSource than an ElementName, but right now this is enough to keep me moving.

If anyone happens to know how the binding:

{Binding Path=DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:StyleSelectionScreen}}}

Should look when written in a MultiBinding, I'm all ears! Otherwise, I guess this one's closed out.