views:

167

answers:

2

(I'll explain the problem once I show my ViewModels and Views)

I have two ViewModels:

public class CommandViewModel
{
    public string DisplayName { get; set; }
    public ICommand Command { get; set; }
}

and

public class SomeViewModel : INotifyPropertyChanged
{
    private bool someFlag;
    private CommandViewModel someCommand;

    public bool SomeFlag
    {
        get
        {
            return someFlag;
        }
        set
        {
            if (value == someFlag)
            {
                return;
            }

            someFlag = value;

            OnPropertyChanged("SomeFlag");
        }
    }

    public CommandViewModel SomeCommandViewModel
    {
        get
        {
            if (someCommand == null)
            {
                someCommand = new CommandViewModel();
                // TODO: actually set the DisplayName and Command
            }
            return someCommand;
        }
    }
}

And I have two corresponding Views:

<UserControl x:Class="ButtonView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="28" d:DesignWidth="91">
    <Button Content="{Binding Path=DisplayName}" Command="{Binding Path=Command}" />
</UserControl>

and

<UserControl x:Class="SomeView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    mc:Ignorable="d" Height="125" Width="293" />

    <ViewButton
        Visibility="{Binding Path=SomeFlag, Converter={StaticResource BoolToVisibilityConverter}}"
        DataContext="{Binding Path=SomeCommandViewModel}" />

</UserControl>

I'm having a problem getting ButtonView's Visibility bound when its DataContext is also bound. If I leave the DataContext out, the Visibility works just fine (when SomeFlag switches value, the button's visibility changes with it) - but the display text and command don't work. If I bind the DataContext, the display text and command work, but the visibility doesn't. I'm sure it has to do with the fact that when I bind the DataContext to SomeCommandViewModel, it is expecting "SomeFlag" to exist within it. And of course, it doesn't.

+1  A: 

I don't condone your design, but this will work around your immediate problem:

<UserControl x:Name="root"
    x:Class="SomeView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    mc:Ignorable="d" Height="125" Width="293" />

    <ViewButton
        Visibility="{Binding Path=DataContext.SomeFlag, Converter={StaticResource BoolToVisibilityConverter}, ElementName=root}"
        DataContext="{Binding Path=SomeCommandViewModel}" />
</UserControl>

HTH,
Kent

Kent Boogaart
I'm a WPF/MVVM n00b. What's a better design?
fre0n
A: 

If you set the DataContext of any given Element EVERY Binding (including children ones) of this element will use the DataContext as Source unless you explicitly give another source.

What you seem to do is specify 2 DataContext at once (UserControl.DataContext is NOT read as ViewButton.DataContext is set and the first source it finds counts).

You can either explicitly take the datacontext of a given element as Kent states OR you can specify the source explicitly. e.g.

<ViewButton
    Visibility="{Binding Path=SomeFlag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Converter={StaticResource BoolToVisibilityConverter}}"
    DataContext="{Binding Path=SomeCommandViewModel}" />
Martin