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


122

Як я пов'язую видимість кнопки із значенням bool у моєму ViewModel?

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

Погляньте на CalcBinding
VivekDev

Відповіді:


204

Припускаючи , що AdvancedFormatце 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) , хоча я б вважав за краще не робити цього, так як тепер ви будете балуватися з поділом проблем. Видимість елемента дійсно повинна відповідати Перегляду.


2
@ raym0nd Звичайно. ViewModel повертає лише булева, що вказує на умову. Якщо ваш Перегляд трактує булеве значення як те, чи щось показувати, чи ні, це залежить від Перегляду. Зауважте, що інший вид може все-таки по-різному тлумачити його.
дв

2
Так, оскільки це лише клас помічників, який масажує значення. Модель перегляду все ще буде знаходитись між вашою моделлю та вашим виглядом.
CodeWarrior

2
Також майте на увазі, що MVVM - це модель дизайну, і тому вам доведеться виконувати свої власні правила щодо його реалізації. Крім того, будуть випадки, коли єдиний спосіб досягти чогось буде поза Моделі, ViewModel або XAML частини Перегляду. Не гріх ставити щось у "Кодексі". Це просто більше відповідає шаблону 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
Взагалі, я відчуваю, що перетворювачі - це злом, і мені їх не подобається. Я думаю, що це питання мого дивного особистого смаку, а не тверезої оцінки плюсів і мінусів з інженерної точки зору, але я їх уникаю.
Роберт Россні

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. Вам не потрібно робити своє.
взуття

4

Як правило, це два способи - клас перетворювача або властивість у Viewmodel, який по суті перетворює значення для вас.

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

<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, щоб оновлено належним чином.


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. Далі наведено властивість Boolean, яка має значення true / false. Далі наведено фрагмент коду. У моєму прикладі ця властивість знаходиться в класі 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)); 
    } 

Ось так вони використовують модель-view-viewmodel

Але оскільки ви хочете, щоб він прив’язаний до булевого, вам знадобиться певний перетворювач. Інший спосіб - встановити булевий зовнішній вигляд, і після натискання цієї кнопки встановіть властивість_advancedFormat на потрібну видимість.


private Visibility _advancedFormat = Visibility.visibleЦе прекрасно працює UWPзавдяки.
rubStackOverflow

1

З Windows 10 15063 і вище

Оскільки Windows 10 збирає 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(); }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.