Mengikat visibilitas Tombol ke nilai bool di ViewModel

122

Bagaimana cara mengikat visibilitas tombol ke nilai bool di ViewModel saya?

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

Jawaban:

204

Dengan asumsi AdvancedFormatadalah a bool, Anda perlu mendeklarasikan dan menggunakan 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}}"/>

Perhatikan yang ditambahkan Converter={StaticResource BoolToVis}.

Ini adalah pola yang sangat umum saat bekerja dengan MVVM. Secara teori, Anda dapat melakukan konversi sendiri pada properti ViewModel (yaitu hanya membuat properti itu sendiri dari tipe Visibility) meskipun saya lebih suka tidak melakukannya, karena sekarang Anda mengotak - atik pemisahan kekhawatiran. Visibilitas item harus benar-benar sesuai dengan View.

dlev
sumber
2
@ raynd Tentu. ViewModel hanya mengembalikan boolean, yang menunjukkan suatu kondisi. Jika Tampilan Anda kebetulan menafsirkan boolean itu sebagai menampilkan sesuatu atau tidak, itu terserah Tampilan. Perhatikan bahwa Tampilan lain masih dapat menafsirkannya secara berbeda.
dlev
2
Ya, karena ini hanyalah kelas pembantu yang memberikan nilai. Model tampilan akan tetap berada di antara model dan tampilan Anda.
CodeWarrior
2
Juga, perlu diingat bahwa MVVM adalah pola desain, dan karenanya Anda harus menegakkan aturan Anda sendiri terkait implementasinya. Selain itu, ada kalanya satu-satunya cara untuk mencapai sesuatu adalah di luar Model, ViewModel atau bagian XAML dari View. Menaruh sesuatu di dalam Codebehind bukanlah dosa. Ini hanya lebih sejalan dengan pola MVVM untuk meletakkannya di ViewModel jika memungkinkan.
CodeWarrior
3
Secara pribadi, saya tidak keberatan menempatkan properti jenis Visibility di ViewModels saya. Saya tahu itu sesat bagi saya, tetapi bagi saya, ini memberi View lebih banyak fleksibilitas, bukan lebih sedikit. Jika Tampilan tidak ingin menggunakannya, itu tidak harus dan jika ada, ini mengurangi rasa sakit karena harus bermain dengan konverter atau pemicu gaya. Ya, ini sedikit mengikat ViewModel saya ke teknologi presentasi (WPF vs. ASP.Net MVC, misalnya), tetapi saya jarang perlu mencampur teknologi tersebut dan refactoring jika saya melakukannya tidak membuat saya takut.
Jacob Proffitt
1
BooleanToVisibilityConverter saat ini tidak tersedia untuk UI Windows Phone, namun jawaban ini menyediakan implementasi stackoverflow.com/a/20344739/595473
CosworthTC
97

Ada cara ketiga yang tidak memerlukan konverter atau perubahan pada model tampilan Anda: gunakan gaya:

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

Saya cenderung lebih suka teknik ini karena saya menggunakannya dalam banyak kasus di mana yang saya ikat bukanlah boolean - misalnya menampilkan elemen hanya jika DataContextbukan null, atau mengimplementasikan tampilan multi-status di mana tata letak yang berbeda muncul berdasarkan pengaturan enum dalam model tampilan.

Robert Rossney
sumber
5
Secara umum, saya merasa konverter adalah retasan dan saya tidak menyukainya. Saya pikir ini adalah masalah selera pribadi saya yang rewel daripada penilaian yang bijaksana tentang pro dan kontra dari sudut pandang teknik, tetapi saya menghindarinya.
Robert Rossney
1
Saya juga tidak bisa mengatakan bahwa saya sering menggunakannya. Mereka cenderung rewel (sic?). Setelah posting Anda, saya ingat bahwa saya menggunakan beberapa gaya / pemicu di proyek sebelumnya ...
CodeWarrior
Saya memiliki TextBlockyang TextWrapping="Wrap"diberikan. Sekarang properti pembungkus tidak disetel di dalamnya.
amit jha
10

2 cara konversi di c # dari boolean ke visibilitas

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
sumber
7
Seperti yang telah disebutkan, ada satu yang sudah terpasang di WPF. Anda tidak perlu membuatnya sendiri.
Sepatu
4

Umumnya ada dua cara untuk melakukannya, kelas konverter atau properti di Viewmodel yang pada dasarnya mengonversi nilai untuk Anda.

Saya cenderung menggunakan pendekatan properti jika itu adalah konversi satu kali. Jika Anda ingin menggunakannya kembali, gunakan konverter. Di bawah ini, temukan contoh konverternya:

<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

Metode properti ViewModel hanya akan memeriksa nilai properti boolean, dan mengembalikan visibilitas berdasarkan itu. Pastikan untuk mengimplementasikan INotifyPropertyChanged dan memanggilnya di properti Boolean dan Visibility agar diperbarui dengan benar.

CodeWarrior
sumber
12
WPF sudah memiliki BooleanToVisibilityConverter bawaan .
CodeNaked
Saya tidak menyadarinya. Yang ini sebenarnya adalah sesuatu yang lain yang saya edit agar sesuai dengan skenario ini. Jauh lebih baik jika ada satu prebuilt.
CodeWarrior
3

Ini dapat dicapai dengan cara yang sangat sederhana 1. Tuliskan ini dalam tampilan.

<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. Berikut ini adalah properti Boolean yang menyimpan nilai benar / salah. Berikut ini adalah potongan kodenya. Dalam contoh saya, properti ini berada di kelas UserNote.

    public bool _isHide = false;
    
    public bool IsHide
    {
    
    get { return _isHide; }
    
    set
        {
            _isHide = value;
                OnPropertyChanged("IsHide");
        }
    } 
  2. Ini adalah cara properti IsHide mendapatkan nilainya.

    userNote.IsHide = userNote.IsNoteDeleted;
Joy Fernandes
sumber
2

Dalam penglihatan:

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

Model dalam tampilan:

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

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

Anda harus memiliki acara yang diubah properti

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

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

Beginilah cara mereka menggunakan Model-view-viewmodel

Tetapi karena Anda ingin mengikatnya ke boolean, Anda memerlukan beberapa konverter. Cara lain adalah dengan menyetel boolean di luar dan saat tombol itu diklik, setel property_advancedFormat ke visibilitas yang Anda inginkan.

Kevin
sumber
private Visibility _advancedFormat = Visibility.visibleIni bekerja dengan baik karena UWPterima kasih.
rubStackOverflow
1

Sejak Windows 10 15063 ke atas

Sejak Windows 10 membangun 15063, ada fitur baru yang disebut "Konversi Visibilitas Implisit" yang mengikat Visibilitas ke nilai bool secara native - Tidak perlu lagi menggunakan konverter.

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

Kode saya (yang menganggap bahwa MVVM digunakan, dan Templat 10 juga):

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