Vinculando la visibilidad de un botón a un valor bool en ViewModel

122

¿Cómo asocio la visibilidad de un botón a un valor bool en mi ViewModel?

<Button Height="50" Width="50" Style="{StaticResource MyButtonStyle}"
    Command="{Binding SmallDisp}" CommandParameter="{Binding}" Cursor="Hand"
    Visibility="{Binding Path=AdvancedFormat}" />
raym0nd
fuente
Eche un vistazo a CalcBinding
VivekDev

Respuestas:

204

Suponiendo que AdvancedFormates un bool, debe declarar y usar un BooleanToVisibilityConverter:

<!-- In your resources section of the XAML -->
<BooleanToVisibilityConverter x:Key="BoolToVis" />

<!-- In your Button declaration -->
<Button
 Height="50" Width="50"
 Style="{StaticResource MyButtonStyle}"
 Command="{Binding SmallDisp}" CommandParameter="{Binding}" 
Cursor="Hand" Visibility="{Binding Path=AdvancedFormat, Converter={StaticResource BoolToVis}}"/>

Tenga en cuenta lo agregado Converter={StaticResource BoolToVis}.

Este es un patrón muy común cuando se trabaja con MVVM. En teoría, podría hacer la conversión usted mismo en la propiedad ViewModel (es decir, simplemente hacer que la propiedad sea de tipo Visibility), aunque preferiría no hacerlo, ya que ahora está jugando con la separación de las preocupaciones. La visibilidad de un elemento realmente debería estar a la vista.

dlev
fuente
2
@ raym0nd Claro. ViewModel devuelve solo un valor booleano, lo que indica una condición. Si su Vista interpreta ese booleano como si muestra o no algo, eso depende de la Vista. Tenga en cuenta que otra vista aún puede interpretarlo de manera diferente.
dlev
2
Sí, ya que esta es solo una clase auxiliar que da masajes a un valor. El modelo de vista seguirá sentado entre su modelo y su vista.
CodeWarrior
2
Además, tenga en cuenta que MVVM es un patrón de diseño y, por lo tanto, debe aplicar sus propias reglas con respecto a su implementación. Además, habrá momentos en que la única forma de lograr algo será fuera del Modelo, el Modelo de Vista o la porción XAML de la Vista. No es pecado poner algo en el Código detrás. Simplemente está más en línea con el patrón MVVM para ponerlo en ViewModel si es posible.
CodeWarrior
3
Personalmente, no me importa poner una propiedad de tipo Visibilidad en mis ViewModels. Sé que es un hereje de mi parte, pero para mí, esto le da a View más flexibilidad, no menos. Si una Vista no quiere usarla, no tiene que hacerlo, y si lo hace, elimina el dolor de tener que jugar con convertidores o disparadores de estilo. Sí, esto vincula mi ViewModel a una tecnología de presentación (WPF vs. ASP.Net MVC, por ejemplo) un poco, pero rara vez necesito mezclar esas tecnologías y refactorizarlas si alguna vez lo hago no me asusta demasiado.
Jacob Proffitt
1
BooleanToVisibilityConverter no está disponible actualmente para las IU de Windows Phone, sin embargo, esta respuesta proporcionó una implementación stackoverflow.com/a/20344739/595473
CosworthTC
97

Hay una tercera forma que no requiere un convertidor o un cambio en su modelo de vista: use un estilo:

<Style TargetType="Button">
   <Setter Property="Visibility" Value="Collapsed"/>
   <Style.Triggers>
      <DataTrigger Binding="{Binding IsVisible}" Value="True">
         <Setter Property="Visibility" Value="Visible"/>
      </DataTrigger>
   </Style.Triggers>
</Style>

Tiendo a preferir esta técnica porque la uso en muchos casos en los que lo que estoy vinculando no es booleano, por ejemplo, mostrar un elemento solo si DataContextno es nulo o implementar pantallas de varios estados donde aparecen diferentes diseños basados ​​en el configuración de una enumeración en el modelo de vista.

Robert Rossney
fuente
55
En general, siento que los convertidores son un truco y no me gustan. Creo que esto es una cuestión de mi mal gusto personal en lugar de una evaluación sobria de los pros y los contras desde el punto de vista de la ingeniería, pero los evito.
Robert Rossney
1
No puedo decir que los uso con tanta frecuencia tampoco. Tienden a ser algo quisquillosos (sic?). Después de su puesto, recordé que he utilizado un buen número de estilos / disparadores en proyectos anteriores ...
CodeWarrior
Tuve una TextBlocka la que me TextWrapping="Wrap"dieron. Ahora esa propiedad de ajuste no está establecida en ella.
amit jha
10

Conversión bidireccional en c # de booleano a visibilidad

using System;
using System.Windows;
using System.Windows.Data;

namespace FaceTheWall.converters
{
    class BooleanToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is Boolean && (bool)value)
            {
                return Visibility.Visible;
            }
            return Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is Visibility && (Visibility)value == Visibility.Visible)
            {
                return true;
            }
            return false;
        }
    }
}
Berty
fuente
77
Como ya se mencionó, ya hay uno integrado en WPF. No necesitas hacer el tuyo.
Zapato
4

En general, hay dos formas de hacerlo, una clase de convertidor o una propiedad en el modelo de vista que esencialmente convierte el valor por usted.

Tiendo a usar el enfoque de propiedad si es una conversión única. Si desea reutilizarlo, use el convertidor. A continuación, encuentre un ejemplo del convertidor:

<ValueConversion(GetType(Boolean), GetType(Visibility))> _
Public Class BoolToVisibilityConverter
    Implements IValueConverter

    Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert

        If value IsNot Nothing Then
            If value = True Then 
                Return Visibility.Visible
            Else
                Return Visibility.Collapsed
            End If
        Else
            Return Visibility.Collapsed
        End If
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
        Throw New NotImplementedException
    End Function
End Class

Un método de propiedad ViewModel simplemente verificaría el valor de la propiedad booleana y devolvería una visibilidad basada en eso. Asegúrese de implementar INotifyPropertyChanged y solicítelo en las propiedades Boolean y Visibility para actualizarlo correctamente.

CodeWarrior
fuente
12
WPF ya tiene un BooleanToVisibilityConverter integrado.
CodeNaked
No me había dado cuenta de eso. Este fue realmente algo más que edité para adaptarse a este escenario. Tanto mejor si hay uno preconstruido.
CodeWarrior
3

Esto se puede lograr de una manera muy simple 1. Escriba esto en la vista.

<Button HorizontalAlignment="Center" VerticalAlignment="Center" Width="50" Height="30">
<Button.Style>
        <Style TargetType="Button">
                <Setter Property="Visibility" Value="Collapsed"/>
                        <Style.Triggers>
                                <DataTrigger Binding="{Binding IsHide}" Value="True">
                                        <Setter Property="Visibility" Value="Visible"/>
                                    </DataTrigger>
                            </Style.Triggers>
            </Style>
    </Button.Style>

  1. La siguiente es la propiedad booleana que contiene el valor verdadero / falso. El siguiente es el fragmento de código. En mi ejemplo, esta propiedad está en la clase UserNote.

    public bool _isHide = false;
    
    public bool IsHide
    {
    
    get { return _isHide; }
    
    set
        {
            _isHide = value;
                OnPropertyChanged("IsHide");
        }
    } 
  2. Esta es la forma en que la propiedad IsHide obtiene el valor.

    userNote.IsHide = userNote.IsNoteDeleted;
Alegría fernandes
fuente
2

En vista:

<Button
 Height="50" Width="50"
 Style="{StaticResource MyButtonStyle}"
 Command="{Binding SmallDisp}" CommandParameter="{Binding}" 
Cursor="Hand" Visibility="{Binding Path=AdvancedFormat}"/>

En vista Modelo:

public _advancedFormat = Visibility.visible (whatever you start with)

public Visibility AdvancedFormat
{
 get{return _advancedFormat;}
 set{
   _advancedFormat = value;
   //raise property changed here
}

Deberá tener un evento de cambio de propiedad

 protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) 
    { 
        PropertyChanged.Raise(this, e); 
    } 

    protected void OnPropertyChanged(string propertyName) 
    { 
        OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); 
    } 

Así es como usan Model-view-viewmodel

Pero dado que desea que esté enlazado a un booleano, necesitará algún convertidor. Otra forma es establecer un valor booleano afuera y cuando se hace clic en ese botón, establezca el property_advancedFormat a la visibilidad deseada.

Kevin
fuente
private Visibility _advancedFormat = Visibility.visibleEsto funciona bien UWPgracias.
rubStackOverflow
1

Desde Windows 10 15063 hacia arriba

Desde Windows 10 build 15063, hay una nueva característica llamada "Conversión de visibilidad implícita" que une la visibilidad al valor bool de forma nativa: ya no es necesario usar un convertidor.

(consulte https://social.technet.microsoft.com/wiki/contents/articles/34846.uwp-compiled-binding-windows-10-anniversary-update.aspx#Implicit_Visibility_conversion ).

Mi código (que supone que se usa MVVM, y también la Plantilla 10):

<!-- In XAML -->
<StackPanel x:Name="Msg_StackPanel" Visibility="{x:Bind ViewModel.ShowInlineHelp}" Orientation="Horizontal" Margin="0,24,0,0">
    <TextBlock Text="Frosty the snowman was a jolly happy soul" Margin="0,0,8,0"/>
    <SymbolIcon Symbol="OutlineStar "/>
    <TextBlock Text="With a corncob pipe and a button nose" Margin="8,0,0,0"/>
</StackPanel>

<!-- in companion View-Model -->
public bool ShowInlineHelp // using T10 SettingsService
{ 
    get { return (_settings.ShowInlineHelp); }
    set { _settings.ShowInlineHelp = !value; base.RaisePropertyChanged(); }
}
Varus Septimus
fuente