简体   繁体   中英

How to update visibility at runtime in WPF

I am currently developing a hamburger style menu in WPF. In this menu, there are some categories that each have an icon. When the menu is collapsed you can still see those icons. When you expand the menu, there should appear text next to it. My idea was to just set their visibility to Visible as soon as the menu opens but I've had a lot of trouble realizing this. Right now I'm trying to change their visibility by binding them to a property.

XAML:

<ListView x:Name="menuItemsListView" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
                <ListViewItem>
                    <StackPanel Orientation="Horizontal">
                        <Image x:Uid="Test" Name="InhoudImage" Source="Images/noimage.png" Height="30" Width="auto" VerticalAlignment="Center" Margin="3,0,0,0"></Image>
                        <TextBlock x:Uid="Test" Text="{Binding Path=TextboxVisibility}" Visibility="{Binding Path=TextboxVisibility}" VerticalAlignment="Center"></TextBlock>
                    </StackPanel>
                </ListViewItem>
            </ListView>

C# CS Class:

using System.Windows;
using System.Windows.Controls;

namespace APP
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private bool menuOpen = false;
        private int closedMenuWidth = 50;
        private int openMenuWidth = 210;
        private string textboxVisibility;

        public string TextboxVisibility
        {
            get { return textboxVisibility; }
            set { textboxVisibility = value; }
        }


        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            this.TextboxVisibility = "Hidden";
        }

        private void MenuButton_Click(object sender, RoutedEventArgs e)
        {
            if (menuOpen)
            {
                menuGrid.Width = closedMenuWidth;
                menuOpen = false;
                this.TextboxVisibility = "Hidden";
            }
            else
            {
                menuGrid.Width = openMenuWidth;
                menuOpen = true;
                this.TextboxVisibility = "Visible";

                //foreach (ListViewItem item in menuItemsListView.Items)
                //{
                //    item.
                //    if (item.Uid == "Test")
                //    {
                //        item.Visibility = Visibility.Visible;
                //    }
                //}
            }
        }
    }
}

When I change the value within the MainWindow function, it does have an effect on it when it first starts. But the other times I try to change it, which is at runtime, nothing happens. I have tried all sorts of things with booleans and binding the actual Visibility type but nothing worked.

You should implemente INotifyPropertyChanged on your MainWindow class like this:

public partial class MainWindow: Window,INotifyPropertyChanged {
   private string textboxVisibility;
   public string TextboxVisibility {
    get {
      return textboxVisibility;
    }
    set {
      textboxVisibility = value;
      OnPropertyChanged();
    }
  }

  //The rest of your code goes here

  public event PropertyChangedEventHandler PropertyChanged;

  protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
    PropertyChanged ? .Invoke(this, new PropertyChangedEventArgs(propertyName));
  }
}

What OnPropertyChanged method does is, whenever the value is setted, it notifies the view and refreshes it. This will solve the problem but isn't the right way to use MVVM.

The way you should do this is to change the visibility property of the TextBox instead of binding the visibility property to a value:

First you have to add a name to the TextBlock you want to hide:

<ListView x:Name="menuItemsListView" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
   <ListViewItem>
      <StackPanel Orientation="Horizontal">
         <Image x:Uid="Test" Name="InhoudImage" Source="Images/noimage.png" Height="30" Width="auto" VerticalAlignment="Center" Margin="3,0,0,0"></Image>
         <TextBlock Name="textblock" x:Uid="Test" Text="{Binding Path=TextboxVisibility}" Visibility="{Binding Path=TextboxVisibility}" VerticalAlignment="Center"></TextBlock>
      </StackPanel>
   </ListViewItem>
</ListView>

And then you change the visibility in the code

private void MenuButton_Click(object sender, RoutedEventArgs e) {
  if (menuOpen) {
    menuGrid.Width = closedMenuWidth;
    menuOpen = false;
    textblock.Visibility = System.Windows.Visibility.Hidden;
  }
  else {
    menuGrid.Width = openMenuWidth;
    menuOpen = true;
    textblock.Visibility = System.Windows.Visibility.Visible;

    //foreach (ListViewItem item in menuItemsListView.Items)
    //{
    //    item.
    //    if (item.Uid == "Test")
    //    {
    //        item.Visibility = Visibility.Visible;
    //    }
    //}
  }
}

If you want to implement MVVM the right way you have to create a ViewModel class and add it as Data Context to your view:

<Window.DataContext>
        <local:MainWindowViewModel/>
</Window.DataContext>

And then on you MainWindowViewModel is where you change the property:

 public class MainWindowViewModel: INotifyPropertyChanged {
      private string textboxVisibility;
      public string TextboxVisibility {
        get {
          return textboxVisibility;
        }
        set {
          textboxVisibility = value;
          OnPropertyChanged();
        }
      }
    
      //The rest of your code goes here
    
      public event PropertyChangedEventHandler PropertyChanged;
    
      protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
        PropertyChanged ? .Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM