33

In my WPF application I am trying to change the visibility of a button depending on the options chosen by a user. On load I want one of the buttons to not be visible. I am using the in built value converter BooleanToVisibilityConverter. However it's not working as the button is appearing at load time. I have changed the property to both true and false, makes no difference. Below is my code, I can't see what I'm missing?

The property in my View Model

 bool ButtCancel
    {
        get { return _buttCancel; }
        set
        {
            _buttCancel = value;
            OnPropertyChanged("ButtCancel");
        }
    }

In my app.xaml

 <Application.Resources>       
    <BooleanToVisibilityConverter x:Key="BoolToVis"/>

In my MainWindow.xaml

 <Button Grid.Column="2" 
      Command="{Binding CommandButtProgressCancel}" 
      Content="Cancel" 
      Visibility="{Binding ButtCancel, Converter={StaticResource BoolToVis}}"
      IsEnabled="{Binding ButtCancelEnabled}" 
      Height="50" Width="120" 
      HorizontalAlignment="Center" 
      VerticalAlignment="Center" Margin="0,0,50,20"/>
kmote
  • 16,095
  • 11
  • 68
  • 91
mHelpMe
  • 6,336
  • 24
  • 75
  • 150
  • 3
    Is your `ButtCancel` property `public`? It has no access modifier in your code excerpt, which would make it `private` and thus invisible to the binding engine. Also, you should not be binding the `IsEnabled` property; let the button use your command's `CanExecute` callback to determine its own state. – Mike Strobel Dec 13 '13 at 15:39
  • @MikeStrobel, surely the default access modifier is `internal` and not `private`. – Sheridan Dec 13 '13 at 15:49
  • Yep can't belive I missed that! It wasn't public – mHelpMe Dec 13 '13 at 15:57
  • 2
    @Sheridan For top-level declarations, the default is `internal`; for class members, including nested type declarations, it is `private`. – Mike Strobel Dec 13 '13 at 15:57

2 Answers2

51

For starters mate, if you're using a Command, then you don't need to bind IsEnabled, the command implementation should decide this.

Secondly, the binding of a ViewModel to a View tends to happen at a bit of a later stage, so it's best to also set a default value for the binding, like so

Visibility="{Binding ButtCancel, Converter={StaticResource BoolToVis}, FallbackValue=Hidden}"

Third, as Mike pointed out, ensure that your property is public, since the ViewModel and the View are two separate classes.

Stefan Z Camilleri
  • 4,016
  • 1
  • 32
  • 42
7

Instead of using a converter, you can just use a DataTrigger.

<Button Grid.Column="2" Command="{Binding CommandButtProgressCancel}" Content="Cancel" 
        Visibility="{Binding ButtCancel, Converter={StaticResource BoolToVis}}" 
        IsEnabled="{Binding ButtCancelEnabled}" Height="50" Width="120"
        HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,50,20">
    <Button.Style>
        <Style TargetType={X:Type Button}>
            <!-- This would be the default visibility -->
            <Setter Property="Visibility" Value="Visible" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding ButtCancel, UpdateSourceTrigger=PropertyChanged}" Value="True">
                    <Setter Property="Visibility" Value="Hidden" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>

Update your ViewModel's properties to public

public bool ButtCancel
{
    get { return _buttCancel; }
    set
    {
        _buttCancel = value;
        OnPropertyChanged("ButtCancel");
    }
}

And make sure the DataContext of your MainWindow is set to the ViewModel.

FredM
  • 454
  • 9
  • 20
d.moncada
  • 16,900
  • 5
  • 53
  • 82