A simple way in WPF MVVM to reuse property method?

244 views Asked by At

I am new to WPF MVVM. Here's what my viewmodel is doing:

A button is pressed and a ping command is launched to see if servers are availables:

-If true, the button is set to Hidden.

-If false, a label with a message ("Servers not availables) is set to visible

How can I reuse the following IsVisible method to set the Label's visibility?

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Input;

namespace WpfTest
{
    public class PrnViewModel1 : ViewModelBase
    {
        private ICommand m_PrnServPingCommand;
        private Visibility _isVisible=Visibility.Visible;


        public PrnViewModel1()
        {
            PrnServPingCommand = new RelayCommand(new Action<object>(PrnServPing));
        }

        public ICommand PrnServPingCommand
        {
            get
            {
                return m_PrnServPingCommand;
            }
            set
            {
                m_PrnServPingCommand = value;
            }
        }

        public void PrnServPing(object obj)
        {
            string[] serverNames = { "svmsimp1", "svmsimp2" };
            bool serversArePingable = Cmethods.PingableAll(serverNames);
            if (serversArePingable)
            {
                IsVisible = Visibility.Hidden; //Button is Hidden
            }
            else
            {
                //*** Label with Message "Servers not pingable" set to visible
            }
        }

        public Visibility IsVisible
        {
            get
            {
                return _isVisible;
            }
            set
            {
                _isVisible = value;
                OnPropertyChanged("IsVisible");
            }
        }
    }
}
2

There are 2 answers

0
Mike Eason On

You can use an IValueConverter to reverse the Visibility on your label.

Here is an example implementation:

public static class Extensions
{
    public static System.Windows.Visibility Reversed(this System.Windows.Visibility visibility)
    {
        if (visibility == System.Windows.Visibility.Visible)
            visibility = System.Windows.Visibility.Collapsed;
        else if (visibility == System.Windows.Visibility.Collapsed || visibility == System.Windows.Visibility.Hidden)
            visibility = System.Windows.Visibility.Visible;

        return visibility;
    }
}

public class VisibilityReversedConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return ((System.Windows.Visibility)value).Reversed();
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return ((System.Windows.Visibility)value).Reversed();
    }
}

Usage:

<TextBlock Text="Servers not available" Visibility="{Binding Visibility, Converter={StaticResource VisibilityReversedConverter}}" ... />

Don't forget to instantiate the converter in the Resources. See here for a tutorial on converters.

0
Sinatr On

I myself often use Visibility type in ViewModel (to avoid writing converters to control layout, because Hidden != Collapsed).

What you need here is either 2 properties to control label and button visibility or single property (bool) to switch which one is displayed and converter (with parameter to invert or just 2 converters).

Here is solution which uses converter and parameter (bonus - MarkupExtension!):

public class SuperConverter : MarkupExtension, IValueConverter
{
    public SuperConverter() { }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool)
        {
            bool inverted = false;
            if (parameter != null && parameter.ToString().Contains("Inverted"))
                inverted = true;
            return (inverted && (bool)value || !inverted && !((bool)value)) ? Visibility.Hidden : Visibility.Visible;
        }
        throw new InvalidCastException();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

and use it (you have to have bool IsOperationInProgress in ViewModel, which value will toggle display of either text or button):

<TextBlock Visibility="{Binding IsOperationInProgress, Converter={l:SuperConverter}}" ... />
<Button Visibility="{Binding IsOperationInProgress, Converter={l:SuperConverter}, ConverterParameter=Inverted}" ... />