Ràng buộc khả năng hiển thị của Nút với giá trị bool trong ViewModel


122

Làm cách nào để liên kết khả năng hiển thị của nút với giá trị bool trong ViewModel của tôi?

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

Hãy nhìn vào CalcBinding
VivekDev

Câu trả lời:


204

Giả sử AdvancedFormatlà a bool, bạn cần khai báo và sử dụng 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}}"/>

Lưu ý đã thêm Converter={StaticResource BoolToVis} .

Đây là một mẫu rất phổ biến khi làm việc với MVVM. Về lý thuyết, bạn có thể tự mình thực hiện chuyển đổi trên thuộc tính ViewModel (tức là chỉ tạo thuộc tính của chính nó Visibility) mặc dù tôi không muốn làm điều đó, vì bây giờ bạn đang lộn xộn với việc tách các mối quan tâm. Khả năng hiển thị của một mục thực sự phải tùy thuộc vào Chế độ xem.


2
@ raym0nd Chắc chắn rồi. ViewModel chỉ trả về một boolean, cho biết một điều kiện. Nếu Chế độ xem của bạn tình cờ diễn giải boolean đó là có hiển thị thứ gì đó hay không, thì đó là tùy thuộc vào Chế độ xem. Lưu ý rằng Chế độ xem khác vẫn có thể diễn giải nó theo cách khác.
dlev

2
Có, vì đây chỉ là một lớp trợ giúp xoa bóp giá trị. Chế độ xem sẽ vẫn nằm giữa mô hình và chế độ xem của bạn.
CodeWarrior

2
Ngoài ra, hãy nhớ rằng MVVM là một mẫu thiết kế, và do đó bạn phải thực thi các quy tắc của riêng mình về việc triển khai nó. Ngoài ra, sẽ có lúc cách duy nhất để hoàn thành điều gì đó sẽ nằm ngoài Model, ViewModel hoặc phần XAML của View. Nó không phải là một tội lỗi khi đặt một cái gì đó trong Codebehind. Nó chỉ phù hợp hơn với mẫu MVVM nếu có thể đưa nó vào ViewModel.
CodeWarrior

3
Cá nhân tôi không ngại đặt thuộc tính loại Visibility vào ViewModels của mình. Tôi biết điều đó là dị giáo của tôi, nhưng đối với tôi, điều này mang lại cho Chế độ xem sự linh hoạt hơn chứ không phải ít hơn. Nếu một Chế độ xem không muốn sử dụng nó, nó không cần phải làm như vậy và nếu có, nó sẽ giảm bớt nỗi đau khi phải sử dụng các bộ chuyển đổi hoặc trình kích hoạt kiểu. Vâng, mối quan hệ này ViewModel của tôi đến một công nghệ trình bày (WPF so với ASP.Net MVC, ví dụ) một chút, nhưng tôi hiếm khi cần phải kết hợp những công nghệ và refactoring nếu tôi đã từng làm không làm tôi sợ, nhiều.
Jacob Proffitt

1
BooleanToVisibilityConverter hiện không khả dụng với giao diện người dùng Windows Phone, tuy nhiên, câu trả lời này đã cung cấp phương thức triển khai stackoverflow.com/a/20344739/595473
CosworthTC

97

Có một cách thứ ba không yêu cầu bộ chuyển đổi hoặc thay đổi đối với mô hình chế độ xem của bạn: sử dụng kiểu:

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

Tôi có xu hướng thích kỹ thuật này hơn bởi vì tôi sử dụng nó trong nhiều trường hợp mà những gì tôi đang ràng buộc không phải là boolean - ví dụ: chỉ hiển thị một phần tử nếu nó DataContextkhông phải là null hoặc triển khai hiển thị đa trạng thái trong đó các bố cục khác nhau xuất hiện dựa trên thiết lập một enum trong mô hình xem.


5
Nói chung, tôi cảm thấy như bộ chuyển đổi là một cuộc tấn công và tôi không thích chúng. Tôi nghĩ đây là vấn đề thuộc sở thích cá nhân khó tính của tôi hơn là một đánh giá tỉnh táo về ưu và nhược điểm từ quan điểm kỹ thuật, nhưng tôi tránh chúng.
Robert Rossney

1
Tôi không thể nói rằng tôi sử dụng chúng thường xuyên. Họ có xu hướng là loại khó tính (sic?). Sau khi bài viết của bạn, tôi nhớ rằng tôi sử dụng khá một vài phong cách / trigger trong các dự án trước đây ...
CodeWarrior

Tôi đã có một TextBlockcái TextWrapping="Wrap"đã được đưa ra. Bây giờ thuộc tính gói đó không được đặt trong đó.
amit jha

10

Chuyển đổi 2 chiều trong c # từ boolean sang khả năng hiển thị

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
Như đã được đề cập, có một cái đã được tích hợp sẵn trong WPF. Bạn không cần phải làm của riêng bạn.
Giày vào

4

Nói chung, có hai cách để làm điều đó, một lớp chuyển đổi hoặc một thuộc tính trong Viewmodel về cơ bản chuyển đổi giá trị cho bạn.

Tôi có xu hướng sử dụng cách tiếp cận thuộc tính nếu nó là một chuyển đổi một lần. Nếu bạn muốn sử dụng lại nó, hãy sử dụng công cụ chuyển đổi. Dưới đây, hãy tìm một ví dụ về bộ chuyển đổi:

<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

Phương thức thuộc tính ViewModel sẽ chỉ kiểm tra giá trị thuộc tính boolean và trả về khả năng hiển thị dựa trên đó. Đảm bảo triển khai INotifyPropertyChanged và gọi nó trên cả thuộc tính Boolean và Visibility để cập nhật đúng cách.


12
WPF đã có một BooleanToVisibilityConverter xây dựng trong.
CodeNaked

Tôi đã không nhận ra điều đó. Cái này thực sự là một cái gì đó khác mà tôi đã chỉnh sửa để phù hợp với kịch bản này. Vì vậy, tốt hơn nhiều nếu có một bản dựng sẵn.
CodeWarrior

3

Điều này có thể đạt được bằng một cách rất đơn giản 1. Viết điều này trong khung nhìn.

<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. Sau đây là thuộc tính Boolean chứa giá trị true / false. Sau đây là đoạn mã. Trong ví dụ của tôi, thuộc tính này nằm trong lớp UserNote.

    public bool _isHide = false;
    
    public bool IsHide
    {
    
    get { return _isHide; }
    
    set
        {
            _isHide = value;
                OnPropertyChanged("IsHide");
        }
    } 
  2. Đây là cách thuộc tính IsHide nhận giá trị.

    userNote.IsHide = userNote.IsNoteDeleted;

2

Đang xem:

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

Trong chế độ xem Mô hình:

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

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

Bạn sẽ cần có một sự kiện thay đổi thuộc tính

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

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

Đây là cách họ sử dụng Model-view-viewmodel

Nhưng vì bạn muốn nó được liên kết với một boolean, bạn sẽ cần một số công cụ chuyển đổi. Một cách khác là đặt boolean bên ngoài và khi nút đó được nhấp vào thì đặt property_advancedFormat thành khả năng hiển thị mong muốn của bạn.


private Visibility _advancedFormat = Visibility.visibleĐiều này hoạt động tốt UWPcảm ơn.
rubStackOverflow

1

Kể từ Windows 10 15063 trở lên

Kể từ phiên bản Windows 10 build 15063, có một tính năng mới được gọi là "Chuyển đổi mức độ hiển thị ngầm" liên kết Mức độ hiển thị với giá trị bool nguyên bản - Không cần sử dụng trình chuyển đổi nữa.

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

Mã của tôi (giả sử rằng MVVM được sử dụng và cả Mẫu 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(); }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.