Привязка видимости кнопки к значению типа bool в ViewModel

122

Как привязать видимость кнопки к значению типа bool в моей ViewModel?

<Button Height="50" Width="50" Style="{StaticResource MyButtonStyle}"
    Command="{Binding SmallDisp}" CommandParameter="{Binding}" Cursor="Hand"
    Visibility="{Binding Path=AdvancedFormat}" />
raym0nd
источник
Взгляните на CalcBinding
VivekDev

Ответы:

204

Предполагая, что AdvancedFormatэто a bool, вам нужно объявить и использовать 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}}"/>

Обратите внимание на добавленный Converter={StaticResource BoolToVis}.

Это очень распространенный паттерн при работе с MVVM. В теории можно сделать преобразование самостоятельно на имуществе ViewModel (т.е. просто сделать свойство самого типа Visibility) , хотя я бы предпочел не делать этого, так как теперь вы будете баловаться с разделением проблем. Видимость элемента действительно должна зависеть от View.

dlev
источник
2
@ raym0nd Конечно. ViewModel возвращает только логическое значение, указывающее на условие. Если ваше представление интерпретирует это логическое значение как то, показывать ли что-то или нет, это зависит от представления. Обратите внимание, что другое представление все еще может интерпретировать его по-разному.
dlev 09
2
Да, поскольку это просто вспомогательный класс, который массирует значение. Модель просмотра по-прежнему будет находиться между вашей моделью и вашим видом.
CodeWarrior,
2
Кроме того, имейте в виду, что MVVM - это шаблон проектирования, и поэтому вы должны применять свои собственные правила в отношении его реализации. Кроме того, будут моменты, когда единственный способ чего-то добиться будет вне модели, ViewModel или части XAML представления. Положить что-то в Codebehind - не грех. Это просто больше соответствует шаблону MVVM, чтобы поместить его в ViewModel, если это возможно.
CodeWarrior
3
Лично я не против добавить свойство типа Visibility в мои ViewModels. Я знаю, что это еретик с моей стороны, но для меня это дает больше гибкости, а не меньше. Если View не хочет его использовать, это не обязательно, а если он это делает, он избавляет от необходимости играть с преобразователями или триггерами стилей. Да, это немного связывает мою ViewModel с технологией представления (например, WPF или ASP.Net MVC), но мне редко нужно смешивать эти технологии, и рефакторинг, если я когда-либо это сделаю, меня не сильно пугает.
Джейкоб Проффитт,
1
BooleanToVisibilityConverter в настоящее время недоступен для пользовательских интерфейсов Windows Phone, однако этот ответ предоставил реализацию stackoverflow.com/a/20344739/595473
CosworthTC
97

Есть третий способ, который не требует конвертера или изменения вашей модели представления: используйте стиль:

<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>

Я предпочитаю этот метод, потому что использую его во многих случаях, когда то, к чему я привязываюсь, не является логическим - например, отображение элемента только в том случае, если DataContextон не равен нулю, или реализация дисплеев с несколькими состояниями, где отображаются разные макеты на основе установка перечисления в модели представления.

Роберт Россни
источник
5
В целом я считаю, что конвертеры - это хакер, и они мне не нравятся. Думаю, это вопрос моего капризного личного вкуса, а не трезвой оценки плюсов и минусов с инженерной точки зрения, но я их избегаю.
Роберт Россни 09
1
Я тоже не могу сказать, что использую их так часто. Они, как правило, привередливы (sic?). После вашего поста я вспомнил, что использовал довольно много стилей / триггеров в предыдущих проектах ...
CodeWarrior
У меня был файл, TextBlockкоторый TextWrapping="Wrap"был отдан. Теперь это свойство упаковки в нем не задано.
amit jha
10

Двухстороннее преобразование в c # из логического в видимость

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;
        }
    }
}
Берти
источник
7
Как уже упоминалось, он уже встроен в WPF. Вам не нужно делать свое собственное.
Shoe
4

Как правило, это можно сделать двумя способами: класс преобразователя или свойство в модели просмотра, которое по сути преобразует значение за вас.

Я предпочитаю использовать имущественный подход, если это разовая конверсия. Если вы хотите использовать его повторно, воспользуйтесь конвертером. Ниже вы найдете пример конвертера:

<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

Метод свойства ViewModel просто проверяет значение логического свойства и возвращает видимость на основе этого. Обязательно реализуйте INotifyPropertyChanged и вызовите его для свойств Boolean и Visibility для правильного обновления.

CodeWarrior
источник
12
WPF уже имеет встроенный BooleanToVisibilityConverter .
CodeNaked
Я этого не осознавал. Это было что-то еще, что я отредактировал, чтобы соответствовать этому сценарию. Тем лучше, если он будет готов.
CodeWarrior,
3

Этого можно добиться очень простым способом 1. Напишите это в представлении.

<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. Ниже приводится логическое свойство, которое содержит значение истина / ложь. Ниже приведен фрагмент кода. В моем примере это свойство находится в классе UserNote.

    public bool _isHide = false;
    
    public bool IsHide
    {
    
    get { return _isHide; }
    
    set
        {
            _isHide = value;
                OnPropertyChanged("IsHide");
        }
    } 
  2. Таким образом свойство IsHide получает значение.

    userNote.IsHide = userNote.IsNoteDeleted;
Джой Фернандес
источник
2

Ввиду:

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

В представлении Модель:

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

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

Вам потребуется событие изменения свойства

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

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

Вот как они используют модель-представление-модель просмотра

Но так как вы хотите привязать его к логическому, вам понадобится какой-нибудь конвертер. Другой способ - установить логическое значение снаружи, и при нажатии этой кнопки установите для свойства property_advancedFormat желаемую видимость.

Kevin
источник
private Visibility _advancedFormat = Visibility.visibleЭто отлично работает на UWPспасибо.
rubStackOverflow
1

Начиная с Windows 10 15063 и выше

Начиная с Windows 10 build 15063, появилась новая функция, называемая «Неявное преобразование видимости», которая изначально привязывает видимость к значению типа bool - больше нет необходимости использовать преобразователь.

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

Мой код (который предполагает, что используется MVVM, а также шаблон 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(); }
}
Варус Септимус
источник