将 Button 的可见性绑定到 ViewModel 中的 bool 值

Posted

技术标签:

【中文标题】将 Button 的可见性绑定到 ViewModel 中的 bool 值【英文标题】:Binding a Button's visibility to a bool value in ViewModel 【发布时间】:2011-10-23 11:16:25 【问题描述】:

如何将按钮的可见性绑定到 ViewModel 中的布尔值?

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

【问题讨论】:

看看CalcBinding 【参考方案1】:

假设AdvancedFormatbool,你需要声明并使用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 类型)虽然我不希望这样做,因为现在您 搞乱了担忧。一个项目的可见性应该由视图决定。

【讨论】:

@raym0nd 当然。 ViewModel 只返回一个布尔值,表示一个条件。如果您的视图碰巧将该布尔值解释为是否显示某些内容,那取决于视图。请注意,另一个 View 仍然可以以不同的方式解释它。 是的,因为这只是一个按摩值的辅助类。视图模型仍将位于您的模型和视图之间。 另外,请记住,MVVM 是一种设计模式,因此您必须强制执行有关其实现的自己的规则。此外,有时完成某事的唯一方法是在 Model、ViewModel 或 View 的 XAML 部分之外。在 Codebehind 中放置一些东西并不是一种罪过。如果可能的话,把它放在 ViewModel 中更符合 MVVM 模式。 就我个人而言,我不介意在我的 ViewModel 中放置 Visibility 类型的属性。我知道这是我的异端,但对我来说,这给了 View 更多的灵活性,而不是更少。如果 View 不想使用它,它就不必使用它,如果使用它,它就减少了必须使用转换器或样式触发器的痛苦。是的,这将我的 ViewModel 与表示技术(例如 WPF 与 ASP.Net MVC)联系了一点,但如果我不害怕,我很少需要混合这些技术和重构我,很多。 BooleanToVisibilityConverter 目前不适用于 Windows Phone UI,但是这个答案提供了一个实现 ***.com/a/20344739/595473【参考方案2】:

通常有两种方法可以做到这一点,一个转换器类或 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 属性上调用它以正确更新。

【讨论】:

WPF 已经内置了BooleanToVisibilityConverter。 我没有意识到这一点。这实际上是我为适应这种情况而编辑的其他东西。如果有一个预建的就更好了。【参考方案3】:

第三种方式不需要转换器或更改视图模型:使用样式:

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

我更喜欢这种技术,因为我在很多情况下都使用它,我绑定的对象是 not 布尔值 - 例如仅当元素的DataContext 不为空时才显示元素,或者根据视图模型中的枚举设置实现不同布局的多状态显示。

【讨论】:

一般来说,我觉得转换器是一个黑客,我不喜欢它们。我认为这是我胡思乱想的个人品味的问题,而不是从工程角度对利弊进行清醒的评估,但我避免了它们。 我也不能说我经常使用它们。他们往往有点挑剔(原文如此?)。在你的帖子之后,我记得我在以前的项目中使用了很多样式/触发器...... 我有一个 TextBlock 给了 TextWrapping="Wrap"。现在没有在其中设置包装属性。 +1,这非常有用,我现在可以避免使用自定义代码进行任何与外观相关的转换,例如基于数据中某些值的背景颜色【参考方案4】:

在视图中:

<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

 getreturn _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 设置为您想要的可见性。

【讨论】:

private Visibility _advancedFormat = Visibility.visible 这在UWP 上运行良好,谢谢。【参考方案5】:

c# 中从布尔值到可见性的 2 路转换

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;
        
    

【讨论】:

如前所述,WPF 中已经内置了一个。你不需要自己做。【参考方案6】:

这可以通过非常简单的方式实现 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>

    以下是保存真/假值的布尔属性。下面是代码sn-p。在我的示例中,此属性位于 UserNote 类中。

    public bool _isHide = false;
    
    public bool IsHide
    
    
    get  return _isHide; 
    
    set
        
            _isHide = value;
                OnPropertyChanged("IsHide");
        
     
    

    这是 IsHide 属性获取值的方式。

    userNote.IsHide = userNote.IsNoteDeleted;
    

【讨论】:

【参考方案7】:

自 Windows 10 15063 以上版本

自 Windows 10 build 15063 起,有一个名为“隐式可见性转换”的新功能将可见性绑定到本机布尔值 - 不再需要使用转换器。

(见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(); 

【讨论】:

这应该是新的最佳答案。我们应该停止使用转换器。 该问题要求 WPF 答案。 WPF 当前不支持已编译的绑定,即 x:Bind。这是相关问题,带有指向用户制作的 x:Bind 实现的链接:https://github.com/dotnet/wpf/issues/130

以上是关于将 Button 的可见性绑定到 ViewModel 中的 bool 值的主要内容,如果未能解决你的问题,请参考以下文章

如何将 StackPane 的可见性绑定到属性?

将控件的可见性绑定到 IEnumerable 的“计数”

WPF 触发器绑定:将枚举值绑定到可见性的最佳方法是啥?

WPF - 将 UserControl 可见性绑定到属性

将 Bool 绑定到 ListBox 中 TextBlock 的可见性

WPF 绑定不更新可见性