การผูกการมองเห็นของปุ่มกับค่าบูลใน ViewModel


122

ฉันจะผูกการมองเห็นของปุ่มกับค่าบูลใน 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คุณต้องประกาศและใช้ a 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


2
@ raym0nd แน่นอน. ViewModel ส่งคืนเฉพาะบูลีนซึ่งระบุเงื่อนไข หาก View ของคุณตีความบูลีนนั้นว่าจะแสดงบางสิ่งหรือไม่นั่นก็ขึ้นอยู่กับ View โปรดทราบว่ามุมมองอื่นยังสามารถตีความแตกต่างกันได้
dlev

2
ใช่เนื่องจากนี่เป็นเพียงคลาสผู้ช่วยที่นวดอย่างคุ้มค่า โมเดลมุมมองจะยังคงนั่งอยู่ระหว่างโมเดลและมุมมองของคุณ
CodeWarrior

2
นอกจากนี้โปรดทราบว่า MVVM เป็นรูปแบบการออกแบบดังนั้นคุณต้องบังคับใช้กฎของคุณเองเกี่ยวกับการใช้งาน นอกจากนี้จะมีบางครั้งที่วิธีเดียวที่จะทำบางสิ่งให้สำเร็จจะอยู่นอก Model, ViewModel หรือส่วน XAML ของ View การใส่บางสิ่งใน Codebehind ไม่ใช่เรื่องผิด มันสอดคล้องกับรูปแบบ MVVM มากกว่าที่จะใส่ไว้ใน ViewModel ถ้าเป็นไปได้
CodeWarrior

3
โดยส่วนตัวแล้วฉันไม่สนใจที่จะใส่คุณสมบัติประเภท Visibility ใน ViewModels ของฉัน ฉันรู้ว่านั่นเป็นคนนอกรีตของฉัน แต่สำหรับฉันแล้วสิ่งนี้ทำให้มุมมองมีความยืดหยุ่นมากขึ้นไม่ใช่น้อย หาก View ไม่ต้องการใช้งานก็ไม่จำเป็นต้องทำและถ้ามีก็จะช่วยลดความเจ็บปวดจากการต้องเล่นกับตัวแปลงหรือทริกเกอร์สไตล์ ใช่ความสัมพันธ์นี้ ViewModel ของฉันที่จะเป็นเทคโนโลยีที่นำเสนอ (WPF กับ ASP.Net MVC ตัวอย่างเช่น) เล็กน้อย แต่ผมไม่ค่อยจำเป็นต้องผสมเทคโนโลยีเหล่านั้นและ refactoring ถ้าฉันเคยทำไม่ได้ฉันตกใจมาก
Jacob Proffitt

1
ขณะนี้ BooleanToVisibilityConverter ยังไม่พร้อมใช้งานกับ UI ของ 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ไม่เป็นโมฆะหรือใช้การแสดงผลแบบหลายสถานะโดยที่รูปแบบต่างๆจะปรากฏขึ้นตาม การตั้งค่า enum ในโมเดลมุมมอง


5
โดยทั่วไปฉันรู้สึกว่าผู้แปลงเป็นแฮ็กและฉันไม่ชอบพวกเขา ฉันคิดว่านี่เป็นเรื่องของรสนิยมส่วนตัวที่บ้าๆบอ ๆ ของฉันมากกว่าการประเมินข้อดีข้อเสียจากมุมมองทางวิศวกรรมอย่างเงียบ ๆ แต่ฉันก็หลีกเลี่ยงพวกเขา
Robert Rossney

1
บอกไม่ถูกว่าใช้บ่อยเหมือนกัน พวกเขามักจะจู้จี้จุกจิก (sic?) หลังจากโพสต์ของคุณฉันจำได้ว่าฉันใช้สไตล์ / ทริกเกอร์ค่อนข้างน้อยในโครงการก่อนหน้านี้ ...
CodeWarrior

ฉันมีสิ่งTextBlockที่TextWrapping="Wrap"ได้รับ ขณะนี้ไม่ได้ตั้งค่าคุณสมบัติการห่อไว้
amit jha

10

การแปลง 2 ทางใน 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 และเรียกใช้ทั้งบนคุณสมบัติบูลีนและการมองเห็นเพื่ออัปเดตอย่างถูกต้อง


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)); 
    } 

นี่คือวิธีที่พวกเขาใช้ Model-view-viewmodel

แต่เนื่องจากคุณต้องการให้มันเชื่อมโยงกับบูลีนคุณจึงต้องมีตัวแปลง อีกวิธีหนึ่งคือการตั้งค่าบูลีนภายนอกและเมื่อคลิกปุ่มนั้นแล้วให้ตั้งค่า property_advancedFormat เป็นระดับการมองเห็นที่คุณต้องการ


private Visibility _advancedFormat = Visibility.visibleสิ่งนี้ใช้ได้ดีเมื่อUWPขอบคุณ
rubStackOverflow

1

ตั้งแต่ Windows 10 15063 ขึ้นไป

ตั้งแต่ Windows 10 build 15063 มีคุณลักษณะใหม่ที่เรียกว่า "Implicit Visibility conversion" ที่ผูกการมองเห็นเข้ากับค่าบูลโดยกำเนิด - ไม่จำเป็นต้องใช้ตัวแปลงอีกต่อไป

(ดู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(); }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.