Bind visibility property to a variable

前端 未结 5 683
伪装坚强ぢ
伪装坚强ぢ 2020-12-05 14:12

I have a Border with Label inside a Window,



        
相关标签:
5条回答
  • 2020-12-05 14:20

    You don't need to make any converter.

    Add a binding to a Visibility property for the border:

    <Border x:Name="Border1" Visibility="{Binding Visibility}"    BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Left" Height="21" Margin="229,164,0,0" VerticalAlignment="Top" Width="90" Opacity="0.5">
        <Grid>
            <Label Content="test"/>
        </Grid>
    </Border>
    

    And then create the property Visibility in a viewmodel like this:

    private Visibility visibility;
    public Visibility Visibility
        {
            get
            {
                return visibility;
            }
            set
            {
                visibility = value;
    
                OnPropertyChanged("Visibility");
            }
        }
    

    So, now you can set Visible or Hidden to your Visibility property as follow:

    Visibility = Visibility.Visible;
    // or
    Visibility = Visibility.Hidden;
    

    But remember, Visibility enum is located in System.Windows namespace, so your viewmodel has to contain using System.Windows;.

    0 讨论(0)
  • 2020-12-05 14:22

    First you will need to make vis a Property:

    private bool _vis;
    
    public bool Vis
    {
        get{return _vis;}
        set
        {
            if(_vis != value)
            {
                _vis = value;
            }
        }
    }
    

    Then you will need a ValueConverter.

    [ValueConversion(typeof(bool), typeof(Visibility))]
        public class VisibilityConverter : IValueConverter
        {
            public const string Invert = "Invert";
    
            #region IValueConverter Members
    
            public object Convert(object value, Type targetType, object parameter,
                System.Globalization.CultureInfo culture)
            {
                if (targetType != typeof(Visibility))
                    throw new InvalidOperationException("The target must be a Visibility.");
    
                bool? bValue = (bool?)value;
    
                if (parameter != null && parameter as string == Invert)
                    bValue = !bValue;
    
                return bValue.HasValue && bValue.Value ? Visibility.Visible : Visibility.Collapsed;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter,
                System.Globalization.CultureInfo culture)
            {
                throw new NotSupportedException();
            }
            #endregion
        }
    

    You will need to create an instance of the converter like so in your resources:

    <UserControl.Resources>
        <cvt:VisibilityConverter x:Key="VisibilityConverter" />
    </UserControl.Resources>
    

    Then you can bind your border like so:

    <Border x:Name="Border1" Visibility="{Binding vis, Converter={StaticResource VisibilityConverter}}>
        <Grid>
            <Label Content="test"/>
        </Grid>
    </Border>
    
    0 讨论(0)
  • 2020-12-05 14:26

    You can't bind field. You can only bind public properties or dependency properties.

    Using public property (you have to implement INotifyPropertyChanged interface to have property->binding):

    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private bool vis;
        public bool Vis
        {
            get { return vis; }
            set
            {
                if (vis != value)
                {
                    vis = value;
                    OnPropertyChanged("Vis");  // To notify when the property is changed
                }
            }
        }
    
        public MainWindow()
        {
            InitializeComponent();
    
            Vis = true;
            // DataContext explains WPF in which object WPF has to check the binding path. Here Vis is in "this" then:
            DataContext = this;          
        }
    
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Vis = !Vis;  // Test Code
        }
    
        #region INotifyPropertyChanged implementation
        // Basically, the UI thread subscribes to this event and update the binding if the received Property Name correspond to the Binding Path element
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }
    

    The XAML code is:

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/netfx/2009/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"
            xmlns:System="clr-namespace:System;assembly=mscorlib"
            Title="MainWindow2" Height="233" Width="392">
    
        <Window.Resources>
            <!-- You can implement your own BooleanToVisibilityConverter but there is one already implemented. So the next line creates an instance of the BooleanToVisibilityConverter that you will be able to reference with the specified key -->
            <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
        </Window.Resources>
    
        <Grid>
            <Button Content="Click on the button to test" Click="Button_Click" Margin="0,0,0,165" />
            <Border x:Name="Border1" BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Left" Height="21" Margin="229,164,0,0" VerticalAlignment="Top" Width="90" Opacity="0.5"
                    Visibility="{Binding Vis, Converter={StaticResource BooleanToVisibilityConverter}}">
                <!-- The previous line define the binding : the path = Vis and the Converter to use -->
                <Grid>
                    <Label Content="test"/>
                </Grid>
            </Border>
        </Grid>
    </Window>
    
    0 讨论(0)
  • 2020-12-05 14:39

    Another solution is to use Trigger Style:

    <Border x:Name="Border1" BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Left" Height="21" Margin="229,164,0,0" VerticalAlignment="Top" Width="90" Opacity="0.5">
        <Border.Style>
            <Style TargetType="Border">
                <Setter Property="Visibility" Value="Visible"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=vis, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged }" Value="False">
                        <Setter Property="Visibility" Value="Hidden"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Border.Style>
        <Grid>
            <Label Content="test"/>
        </Grid>
    </Border>
    

    In the model class:

    public class ModelClass: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void NotifyPropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    
        private bool _vis;
        public bool vis
        {
            get => _vis;
            set
            {
                _vis = value;
                NotifyPropertyChanged("vis");
            }
        }
    }
    

    Don't forget to bind DataContext with your model !

    DataContext = new ModelClass();
    
    0 讨论(0)
  • 2020-12-05 14:41

    If you already have your bool variable in a viewmodel, you have two things to do:

    1. make it a property, like:

      public bool vis { get; set; }

    And you need a visibility converter for your property then:

    It is described here:

    http://social.msdn.microsoft.com/Forums/en/wpf/thread/3c0bef93-9daf-462f-b5da-b830cdee23d9

    The example assumes that you have a viewmodel and use Binding

    Here is some demo code that I made from your snippet:

    ViewModel:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
    
    namespace StackOverflowWpf2
    {
        public class BorderViewModel : INotifyPropertyChanged
        {
            private bool borderVisible = false;
    
            public bool BorderVisible 
            {
                get
                {
                    return borderVisible;
                }
    
                set
                {
                    borderVisible = value;
                    NotifyPropertyChanged("BorderVisible");
                }
            }
    
            private void NotifyPropertyChanged(string info)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(info));
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
        }
    }
    

    XAML:

    <Window x:Class="StackOverflowWpf2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
        </Window.Resources>
        <Grid>
            <Border x:Name="Border1" BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Left" Height="21" Margin="229,164,0,0" VerticalAlignment="Top" Width="90" Opacity="0.5"
                    Visibility="{Binding Path=BorderVisible, Converter={StaticResource BoolToVisConverter} }" >
                <Grid>
                    <Label Content="test"/>
                </Grid>
            </Border>
            <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="381,35,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" 
                    />
        </Grid>
    </Window>
    

    Some Codebehind quick testcode: (actually is MainWindow.xaml.cs)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    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 StackOverflowWpf2
    {
        /// <summary>
        /// Interaktionslogik für MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public BorderViewModel ViewModel { get; set; }
    
            public MainWindow()
            {
                InitializeComponent();
    
                ViewModel = new BorderViewModel();
    
                this.DataContext = ViewModel;
    
            }
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                var vis = (this.DataContext as BorderViewModel).BorderVisible;
    
                (this.DataContext as BorderViewModel).BorderVisible = !vis;
    
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题