如何将 StackPane 的可见性绑定到属性?
Posted
技术标签:
【中文标题】如何将 StackPane 的可见性绑定到属性?【英文标题】:How can I bind the visibility of a StackPane to a property? 【发布时间】:2020-10-01 08:19:40 【问题描述】:我有几个 StackPanes,我只想为 ComboBox 的特定值显示它们。我已经根据需要更改了属性,但由于某种原因,当 ComboBox 值更新时,StackPane 可见性不会更新。不知道我在这里做错了什么。
RegisteredServersView.xaml
<UserControl x:Class="WpfApp1.Servers.RegisteredServersView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:WpfApp1.Servers"
mc:Ignorable="d"
Height="250" Width="600">
<UserControl.DataContext>
<local:RegisteredServersViewModel/>
</UserControl.DataContext>
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="Server Instance:" Margin="30,10,10,10"/>
<TextBox Text="Binding ServerName, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True"
Width="140" Margin="10">
<Validation.ErrorTemplate>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<AdornedElementPlaceholder x:Name="textBox"/>
<TextBlock Margin="10" Text="Binding [0].ErrorContent" Foreground="Red"/>
</StackPanel>
</ControlTemplate>
</Validation.ErrorTemplate>
</TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="Authorization Type:" Margin="10"/>
<ComboBox Name="cbAuthType"
Margin="10"
ItemsSource="Binding Types"
SelectedItem="Binding AuthType, UpdateSourceTrigger=PropertyChanged"
Width="141"/>
</StackPanel>
<StackPanel Orientation="Horizontal"
Visibility="Binding Vis">
<Label Content="Login:" Margin="80,10,10,10"/>
<TextBox Text="Binding Login, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True"
Width="140" Margin="10">
<Validation.ErrorTemplate>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<AdornedElementPlaceholder x:Name="textBox"/>
<TextBlock Margin="10" Text="Binding [0].ErrorContent" Foreground="Red"/>
</StackPanel>
</ControlTemplate>
</Validation.ErrorTemplate>
</TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal"
Visibility="Binding Vis">
<Label Content="Password:" Margin="60,10,10,10"/>
<TextBox Text="Binding Password, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True"
Width="140" Margin="10">
<Validation.ErrorTemplate>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<AdornedElementPlaceholder x:Name="textBox"/>
<TextBlock Margin="10" Text="Binding [0].ErrorContent" Foreground="Red"/>
</StackPanel>
</ControlTemplate>
</Validation.ErrorTemplate>
</TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button x:Name="Reg"
Content="Register"
Click="OnSave"
Margin="145,10,10,10"
Width="60"
IsEnabled="Binding ButtonEnabled, ValidatesOnDataErrors=True"/>
<Button x:Name="Cancel"
Content="Cancel"
Click="OnCancel"
Margin="5,10,10,10"
Width="60"/>
</StackPanel>
</StackPanel>
</UserControl>
RegisteredServersView.xaml.cs
using Microsoft.Xaml.Behaviors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp1.Servers
public partial class RegisteredServersView : UserControl
public RegisteredServersView()
InitializeComponent();
DataContext = new RegisteredServersViewModel();
cbAuthType.SelectedItem = cbAuthType.Items[0];
public void OnCancel(object sender, RoutedEventArgs e)
var window = (Window)VisualParent.GetSelfAndAncestors().FirstOrDefault(a => a is Window);
window.Close();
public void OnSave(object sender, RoutedEventArgs e)
OnCancel(sender, e);
RegisteredServersViewModel.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Input;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WpfApp1.Data;
using WpfApp1.Repos;
using System.Windows;
namespace WpfApp1.Servers
public class RegisteredServersViewModel : INotifyPropertyChanged, IDataErrorInfo
private readonly RegisteredServerValidator _validator;
private string _serverName;
private string _authType;
private string _login;
private string _password;
private Visibility _vis;
public IEnumerable<string> _types;
public RegisteredServersViewModel()
_types = new List<string>() "SQLAuth", "Integrated" ;
_validator = new RegisteredServerValidator();
public IEnumerable<string> Types
get return _types;
public string ServerName
get return _serverName;
set
_serverName = value;
CheckButtonEnabled();
OnPropertyChanged("ServerName");
public string AuthType
get return _authType;
set
_authType = value;
if(value.Equals("SQLAuth"))
Vis = Visibility.Visible;
else
Vis = Visibility.Hidden;
CheckButtonEnabled();
OnPropertyChanged("AuthType");
public Visibility Vis
get return _vis;
private set
_vis = value;
Console.WriteLine(_vis);
OnPropertyChanged("Vis");
public string Login
get return _login;
set
_login = value;
CheckButtonEnabled();
OnPropertyChanged("Login");
public string Password
get return _password;
set
_password = value;
CheckButtonEnabled();
OnPropertyChanged("Password");
public string this[string columnName]
get
var firstOrDefault = _validator.Validate(this).Errors.FirstOrDefault(lol => lol.PropertyName == columnName);
if(firstOrDefault != null)
return _validator != null ? firstOrDefault.ErrorMessage : "";
return "";
public string Error
get
if(_validator != null)
var results = _validator.Validate(this);
if(results != null && results.Errors.Any())
var errors = string.Join(Environment.NewLine, results.Errors.Select(x => x.ErrorMessage).ToArray());
return errors;
return string.Empty;
private bool _buttonEnabled;
public bool ButtonEnabled
get return _buttonEnabled;
set
_buttonEnabled = value;
//Console.WriteLine(_buttonEnabled);
OnPropertyChanged("ButtonEnabled");
public void CheckButtonEnabled()
if(ServerName != null && AuthType.Equals("SQLAuth") && Login != null && Password != null)
ButtonEnabled = true;
else if(ServerName != null && !AuthType.Equals("SQLAuth"))
ButtonEnabled = true;
else
ButtonEnabled = false;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
RegisteredServerValidator.cs
using FluentValidation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WpfApp1.Data;
using WpfApp1.Servers;
namespace WpfApp1
class RegisteredServerValidator : AbstractValidator<RegisteredServersViewModel>
public RegisteredServerValidator()
RuleFor(instance => instance.ServerName)
.NotEmpty()
.WithMessage("This field cannot be left blank.");
RuleFor(instance => instance.Login)
.NotEmpty()
.WithMessage("This field cannot be left blank.");
RuleFor(instance => instance.Password)
.NotEmpty()
.WithMessage("This field cannot be left blank");
INotifyPropertyChanged.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace WpfApp1
public class INotifyPropertyChanged : System.ComponentModel.INotifyPropertyChanged
protected virtual void SetProperty<T>(ref T member, T val,
[CallerMemberName]string propertyName = null)
if (object.Equals(member, val)) return;
member = val;
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
protected virtual void OnPropertyChanged(string propertyName)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
public event PropertyChangedEventHandler PropertyChanged = delegate ;
RegisteredServersWindow.xaml
<Window x:Class="WpfApp1.Servers.RegisteredServersWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp1.Servers"
mc:Ignorable="d"
Height="300" Width="500"
Title="Registered Servers">
<!--This contains the UserControl with the form.-->
<Grid>
<local:RegisteredServersView HorizontalAlignment="Left"
Margin="0, 0, 0, 0"
VerticalAlignment="Top"/>
</Grid>
</Window>
RegisteredServersWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp1.Servers
/// <summary>
/// Interaction logic for RegisteredServersWindow.xaml
/// </summary>
public partial class RegisteredServersWindow : Window
public RegisteredServersWindow()
InitializeComponent();
我也尝试过使用 Visibilty 类而不是布尔值,但也无法让它工作。任何帮助将不胜感激!
【问题讨论】:
旁注,由于您自己定义 Vis,它不必是布尔值,它可以是 Visibility,然后您就不需要转换器了。 cbAuthType 填充在视图的构造函数中。我有一个单独的类,将值定义为枚举。 @UuDdLrLrSs 谢谢,这似乎是一种更简单的方法。 【参考方案1】:我将代码从我的“测试项目”移到了实际的项目中,突然它就可以工作了。不知道发生了什么变化,但它现在正在运行。感谢大家的帮助。
【讨论】:
【参考方案2】:我会订阅组合框的SelectionChange Event 并在那里翻转状态。
【讨论】:
以上是关于如何将 StackPane 的可见性绑定到属性?的主要内容,如果未能解决你的问题,请参考以下文章