0
votes

I'm new to MVVM and I'm working on a WP8 app and I'd like to be able to set the visibility of buttons and a textblock based on when one of those buttons were tapped. Here's my View to try and explain my problem a bit better; (http://i.imgur.com/JvrxBkh.png - can't post an image on this reputation) .

When the user taps the "Going to sleep" button, I'd like the counter textblock and the "I'm awake" button to be visible with the "Going to sleep" button to be collapsed. It'll then work the other way once the "I'm awake" button is pressed, etc. If I wasn't using MVVM I'd just set the Visibility value inside the button event, but I'm stuck on how to do this when using the MVVM pattern.

I've looked around and come across a solution using a converter such as using a BooleanToVisibilityConverter class and a bool property and then setting the visibility by binding to the bool value from the ViewModel and setting the converter value for the visibility to the StaticResource BooleanToVisibilityConverter. But it just doesn't work for me the way I want. Then my counter textblock has a bind already from the ViewModel so would I need some kind of multi-binding for this textblock?

Hopefully I've explained myself OK. It seems like it should be a simple task that maybe I'm just over thinking or something.

EDIT With some code snippets

The View components that I was referring to;

<BooleanToVisibilityConverter x:Key="boolToVis" />

<TextBlock 
Grid.Row="2"
Text="{Binding Counter}"
FontSize="50"
TextWrapping="Wrap"
Foreground="White"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{Binding VisibilityControl, Converter={StaticResource boolToVis}}"/>

<Button 
Grid.Row="3"
Width="230"
Height="70"
Content="I'm awake"
BorderThickness="0"
Background="Gray"
Margin="0,20,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Command="{Binding AwakeButtonCommand}"
Visibility="{Binding VisibilityControl, Converter={StaticResource boolToVis}}""/>

<Button 
Grid.Row="3"
Width="230"
Height="70"
Content="Going to sleep"
BorderThickness="0"
Background="Gray"
Margin="0,20,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center" 
Command="{Binding SleepButtonCommand}"
Visibility="{Binding VisibilityControl, Converter={StaticResource boolToVis}}"/>

Then in the ViewModel VisibilityControl is just;

private bool _visibilityControl;
public bool VisibilityControl
{
    if (_visibilityControl != value)
        _visibilityControl = value;

    OnPropertyChanged("VisibilityControl");
}

And I have the two buttons such as (I'll just post one up);

public ICommand AwakeButtonCommand
{
    get
    {
        return _awakeButtonCommand
            ?? (_awakeButtonCommand = new Resources.ActionCommand(() =>
        {
              VisibilityControl = true;
        }));
    }
}

It doesn't work, obviously. I think what's throwing me is because I want several things changed when one button is pressed, etc. It's throwing me off.

1
Could you post some code of what you've tried already? The Boolean property combined with a BooleanToVisibilityConverter is definitely the MVVM way of doing this kind of thing. You essentially use the Boolean property state to show and hide elements of your UI.Steven Rands
I've posted an answer but it would still be useful to see your code.Steven Rands
Yeah, sorry, didn't think it'd be of use to anyone. I've edited it in now.FUBAR

1 Answers

1
votes

I've not done any Windows Phone development but here's one way of doing it in WPF that might be applicable to WP also.

First, your ViewModel would have a couple of Boolean properties indicating which state is active (one would be a mirror of the other):

public bool IsAwake
{
    get
    {
        return _isAwake;
    }
    set
    {
        if (_isAwake != value)
        {
            _isAwake = value;
            // raise PropertyChanged event for *both* IsAwake and IsAsleep
        }
    }
}
bool _isAwake;

public bool IsAsleep
{
    get
    {
        return !_isAwake;
    }
}

Then your View would contain both parts of the UI (asleep & awake) but would switch between the two parts by binding their Visibility property to these Boolean properties of your ViewModel:

<StackPanel>
    <StackPanel x:Name="AwakePart"
        Visibility="{Binding IsAwake, Converter={StaticResource btvc}}">
        ... "Going to sleep" button here ...
    </StackPanel>
    <StackPanel x:Name="AsleepPart"
        Visibility="{Binding IsAsleep, Converter={StaticResource btvc}}">
        ... Elapsed time text block and "I'm awake" button here ...
    </StackPanel>
</StackPanel>

You will also need a BooleanToVisibilityConverter instance somewhere in your XAML resources:

<... .Resources>
    <BooleanToVisibilityConverter x:Key="btvc" />
</... .Resources>

I've used two Boolean properties in this example as it makes the XAML a little easier, however you could also use a DataTrigger -- assuming they have those in Windows Phone -- in which case you would only need one Boolean property. You would then write a trigger to toggle the Visibility properties of the two parts:

<DataTrigger Binding="{Binding IsAwake}" Value="True">
    <Setter TargetName="AwakePart" Property="Visibility" Value="Visible" />
    <Setter TargetName="AsleepPart" Property="Visibility" Value="Hidden" />
</DataTrigger>

For this to work you would need to explicitly set the "AwakePart" visibility to Hidden in the XAML to start with and ensure that in your ViewModel the IsAwake property is false by default. You would also need to remove the bindings on the visibility properties (as these would now be set via the trigger).