Cannot collapse element from event handler in ViewModel

Viewed 46

I have a simple XAML page with two buttons. I am trying to dynamically collapse the button that has been clicked on and display the other one, but can't seem to make it work.

For simplicity, button visibility is bound directly to Visibility properties in the TestPageViewModel class. Event handlers are bound to its methods.

TestPage.xaml

<Page
    x:Class="CollapseElementTest.TestPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:CollapseElementTest"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" d:DesignWidth="500" d:DesignHeight="500">
    <StackPanel>
        <Button Background="Blue" 
                Click="{x:Bind TestPageViewModel.HideBlueButton}" 
                Visibility="{x:Bind TestPageViewModel.BlueButtonVisibility, Mode=OneWay}"></Button>
        <Button Background="Red" 
                Click="{x:Bind TestPageViewModel.HideRedButton}"
                Visibility="{x:Bind TestPageViewModel.RedButtonVisibility, Mode=OneWay}"></Button>
    </StackPanel>
</Page>

TestPage.xaml.cs

using Windows.UI.Xaml.Controls;

namespace CollapseElementTest
{
    public sealed partial class TestPage : Page
    {
        public TestPageViewModel TestPageViewModel { get; set; }
        public TestPage()
        {
            this.InitializeComponent();
            TestPageViewModel = new TestPageViewModel();
        }
    }
}

TestPageViewModel properties are updated on the UI thread.

TestPageViewModel.cs

using System;
using Windows.ApplicationModel.Core;
using Windows.UI.Core;
using Windows.UI.Xaml;

namespace CollapseElementTest
{
    public class TestPageViewModel
    {
        public Visibility BlueButtonVisibility { get; set; } = Visibility.Visible;

        public Visibility RedButtonVisibility { get; set; } = Visibility.Collapsed;

        public async void HideBlueButton()
        {
            await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
            () =>
            {
                BlueButtonVisibility = Visibility.Collapsed;
                RedButtonVisibility = Visibility.Visible;
            });
        }

        public async void HideRedButton()
        {
            await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
            () =>
            {
                BlueButtonVisibility = Visibility.Visible;
                RedButtonVisibility = Visibility.Collapsed;
            });
        }
    }
}

After the application is started, blue button is shown, but after the button click nothing changes. What am I doing wrong?

1 Answers

you missed the part INotifyPropertyChanged. When you changed one property, you need to notify the app, saying here is changed, let the app do the next steps.

I modified you ViewModel file to the following, and it works. Please check.

public class TestPageViewModel : INotifyPropertyChanged
    {
        private Visibility _BlueButtonVisibility;

        public Visibility BlueButtonVisibility
        {
            get { return _BlueButtonVisibility; }
            set { Set(ref _BlueButtonVisibility, value); }
        }
        private Visibility _RedButtonVisibility;

        public Visibility RedButtonVisibility
        {
            get { return _RedButtonVisibility; }
            set { Set(ref _RedButtonVisibility, value); }
        }

        public async void HideBlueButton()
        {
            await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
            () =>
            {
                BlueButtonVisibility = Visibility.Collapsed;
                RedButtonVisibility = Visibility.Visible;

                
            });
        }

        public async void HideRedButton()
        {
            await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
            () =>
            {
                BlueButtonVisibility = Visibility.Visible;
                RedButtonVisibility = Visibility.Collapsed;
            });
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void Set<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (Equals(storage, value))
            {
                return;
            }

            storage = value;
            OnPropertyChanged(propertyName);
        }

        protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
Related