如何将 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 的可见性绑定到属性?的主要内容,如果未能解决你的问题,请参考以下文章

将 XAML 中的可见性绑定到可见性属性

如何使用 WPF 中的代码绑定 DataGridTextColumn 的可见性属性?

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

WPF - 可以将标签的属性(可见性)绑定到标签的目标吗?

如何绑定可见性属性

绑定到可见性属性时动画不正确(奇数)