Search code examples
c#wpfuser-interface

A Button In My WPF Page Doesn't Get Updated Unless I Reopen The Page


I have a page in my WPF app. I need a button which can be active and deactive. It works actually but when it becomes active, I can't see that on the screen. If I open another page and then open my page again, it becomes active.

UserControl code:

<UserControl x:Class="MediaAuthentication.UserControls.LandingFooterUserControl"
             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:MediaAuthentication.UserControls"
             xmlns:vm="clr-namespace:MediaAuthentication.ViewModels"
             mc:Ignorable="d" 
             d:DataContext="{d:DesignInstance Type=vm:LandingFooterViewModel}"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Button Content="Apply" 
                HorizontalAlignment="Center" 
                VerticalAlignment="Center" 
                Width="200" Height="50"
                IsEnabled="{Binding IsButtonEnabled}" 
                Command="{Binding ButtonCommand}" />
    </Grid>
</UserControl>

ViewModel code:

using MediaAuthentication.Models;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using MediaAuthentication.Business.Services.Logging;
using MediaAuthentication.Business.Services.Metadata;

namespace MediaAuthentication.ViewModels
{
    public class LandingFooterViewModel
    {
        private ILoggerService _loggerService;
        private IVideoMetadataService _videoMetadataService;

        private MetaDataFooterViewModel _metaFooterViewModel;

        public int markBeginning = -1;
        public int markEnd = -1;

        private bool _isButtonEnabled;
        public bool IsButtonEnabled
        {
            get => _isButtonEnabled;
            set
            {
                if (_isButtonEnabled != value)
                {
                    _isButtonEnabled = value;
                    OnPropertyChanged(nameof(IsButtonEnabled));
                    (ButtonCommand as RelayCommand)?.RaiseCanExecuteChanged();
                }
            }
        }

        // ICommand Property
        public ICommand ButtonCommand { get; }

        public LandingFooterViewModel(ILoggerService loggerService, IVideoMetadataService videoMetadataService, MetaDataFooterViewModel metaFooterViewModel)
        {
            _loggerService = loggerService;
            _videoMetadataService = videoMetadataService;

            _metaFooterViewModel = metaFooterViewModel;

            IsButtonEnabled = false;

            ButtonCommand = new RelayCommand(OnButtonClicked, () => IsButtonEnabled);
        }

        private void OnButtonClicked()
        {
            Storage.firstFrameIndex = markBeginning;
            Storage.lastFrameIndex = markEnd;

            if (Storage.media == null || string.IsNullOrEmpty(Storage.path))
            {
                _loggerService.LogWarning("No media file loaded. Please upload a file first.");
                return;
            }
            //IsLoading = true;
            try
            {
                if (Storage.media.StreamList != null)
                {
                    foreach (var stream in Storage.media.StreamList)
                    {
                        stream.FrameList.Clear();
                    }
                    Storage.media.StreamList.Clear();
                }

                _videoMetadataService.ExtractMetadata(Storage.media);

                _metaFooterViewModel.UpdateMetadata(Storage.media);

                _loggerService.LogInfo("Metadata extraction completed successfully.");

                _metaFooterViewModel.UpdateMetadata(Storage.media);

                /*
                List<string> frameTypes = new List<string>();
                foreach (Frame frame in media.StreamList[0].FrameList)
                {
                    frameTypes.Add(frame.Metadata[FrameMetadataKey.FrameType]);
                } */
            }
            catch (Exception ex)
            {
                _loggerService.LogError($"Error extracting metadata: {ex.Message}");
            }
            finally
            {
             //   IsLoading = false;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

I inserted a breakpoint to IsButtonEnabled line but, it works fine. Whenever I want to change activity of the button, the breakpoint works and the value of that bool variable is right.


Solution

  • WPF bindings rely on INotifyPropertyChanged to detect changes to the underlying data. When you raise the PropertyChanged event in your property setter, WPF's binding system listens for it and updates the UI accordingly.

    You implemented interface, but didn't mark class with it:

    public class LandingFooterViewModel : INotifyPropertyChanged