Say I wanted to toggle the visibility of a WPF object in an MVVM way, what would I need to do?
Here is what I currently have:
- ViewModels
- ShellViewModel
- LoadingViewModel
- Views
- ShellView
- LoadingView
When the application is loaded, the ShellViewModel is used to display the LoadingView in a ContentControl object. I have a button on there that I want to become visible after the LoadingView has been activated for 5 seconds.
What I need to do is created a custom class that has two methods: a way of converting a boolean to a visibility; and a way of converting a visibility to a visibility.
So I created a new folder in my tree called “Converters“. In here, I create a new class called “BooleanToVisiblityConverter“. Here is what my tree now looks like:
- ViewModels
- ShellViewModel
- LoadingViewModel
- Views
- ShellView
- LoadingView
- Converters
- BooleanToVisibilityConverter
In my BooleanToVisibilityConverter class, I inherited from IValueConverter and added the necessary two methods. You can see the entire class below:
using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Data; namespace Project.Converters { /// <summary> /// Contains the converter and convertback methods for the boolean to visibility conversions /// </summary> public sealed class BooleanToVisibilityConverter : IValueConverter { /// <summary> /// Used to convert a boolean to a visibility /// </summary> /// <param name="value">This is the boolean input</param> /// <param name="targetType"></param> /// <param name="parameter"></param> /// <param name="culture"></param> /// <returns>Returns a visibility</returns> public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (!(value is bool)) { //If there is an issue with the input, return collapsed return Visibility.Collapsed; } return (bool)value ? Visibility.Visible : Visibility.Collapsed; } /// <summary> /// Used to take a visibility and returns a visibility /// </summary> /// <param name="value">This is the boolean input</param> /// <param name="targetType"></param> /// <param name="parameter"></param> /// <param name="culture"></param> /// <returns>Returns a visibility</returns> public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (!(value is Visibility)) { //If there is an issue wtih the input, return collapsed return Visibility.Collapsed; } return (Visibility)value == Visibility.Visible; } } }
Next, in my LoadingView, I added “ xmlns:sp=”clr-namespace:Project.Converters” so that the view could use the converter namespace. This is what my view dependancies look like:
<UserControl x:Class="Project.Views.MainView" 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" xmlns:cal="http://www.caliburnproject.org" xmlns:sp="clr-namespace:Project.Converters" xmlns:local="clr-namespace:Project.Views" mc:Ignorable="d" FontSize="14" FontFamily="/Project;component/Assets/Fonts/#Roboto" d:DesignHeight="550" d:DesignWidth="400">
I then added the binding to the visibility property of my button. You can see this below:
<Button Name="LoadingButton" Content="Press Me" Visibility="{Binding ButtonIsVisible, Converter={StaticResource BooleanConverter}, FallBackValue=Collapsed}"
This means that it will get its visibility value from the LoadingViewModel and if this fails, it will fall back to being collapsed.
We’re almost done. In the LoadingViewModel create a full property which will hold and change the value for the visibility. This needs to be named the same as the binding given in the LoadingView (i.e ButtonVisibility). You can see this below:
private bool _buttonIsVisible; public bool ButtonIsVisible { get {return _buttonIsVisible; set { if (value != _buttonIsVisible) { _buttonIsVisible = value; NotifyOfPropertyChange(() => ButtonIsVisible); } } }
So now if you want the button to be visible, you can just update the ButtonIsVisible property in the LoadingViewModel. Here is an example below (Don’t actually do this):
public LoadingViewModel(){ ButtonIsVisible = false; Task.Delay(5000); ButtonIsVisible = true; }
I hope this helped you. Enjoy!