Home > other >  C#/WPF - View does not update, no known fix works
C#/WPF - View does not update, no known fix works

Time:07-22

Greetings StackOverflow!

I'm trying to create a simple launcher that asks a set of questions. Six pages/views(that i'm yet to implement) - one question each. The idea is that user is able to switch between pages using two big side-buttons or to pick a specific page by pressing a corresponding radio button.

Template binding works, button calls correct method but UI does not reflect changes of ObservableCollection. I'm new to .NET so i'm certainly missing something. Please help. I've searched and applied all sorts of solutions proposed in similiar threads - nothing works.

Function in question is PageBarViewModel.NextPage() - it is called and excuted properly so it must be the UI that does not reflect changes. Only if called from constructor do the changes become visible.

Launcher.xaml

<Window x:Class="automeas_ui.Launcher"
    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:local="clr-namespace:automeas_ui"
    xmlns:view="clr-namespace:automeas_ui.MWM.View"
    xmlns:viewm="clr-namespace:automeas_ui.MWM.ViewModel"
    mc:Ignorable="d"
    Title="MainWindow" Height="600" Width="920"
    WindowStyle="None"
    ResizeMode="NoResize"
    WindowStartupLocation="CenterScreen"
    Background="Transparent"
    AllowsTransparency="True">
<Window.DataContext>
    <viewm:PageBarViewModel/>
</Window.DataContext>
<Border Background="#272537"
        CornerRadius="10">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.25*"/>
            <ColumnDefinition Width="3*"/>
            <ColumnDefinition Width="0.25*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.45*"/>
            <RowDefinition Height="3*"/>
            <RowDefinition Height="0.25*"/>
        </Grid.RowDefinitions>
        <Button Grid.Row="0"
                Grid.Column="2"
                Width="50"
                Height="50"
                Content="❌"
                FontSize="32"
                Style="{StaticResource FOC_SquareButtonTheme}"
                Click="Button_Clicked"/>
        <Button Grid.Row="1"
                Grid.Column="2"
                Content="&#9655;"
                Foreground="#323232"
                Background="Transparent"
                BorderThickness="0"
                FontSize="72" Command="{Binding Path=NpCommad}"/>
        <Button Grid.Row="1"
                Grid.Column="0"
                Content="&#9665;"
                Foreground="#323232"
                Background="Transparent"
                BorderThickness="0"
                FontSize="72"/>
        <Label Grid.Row="0"
                   Grid.Column="1"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center"
                   FontSize="44"
                   FontFamily="Verdana"
                   Content="Some text"
                   Foreground="White"/>
        <view:PageBarView Grid.Column="1" 
                          Grid.Row="2"/>
    </Grid>
</Border>

How it looks like - Intended layout

PageBarViewModel.xaml

<UserControl x:Class="automeas_ui.MWM.View.PageBarView"
             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:automeas_ui.MWM.View"
             xmlns:model="clr-namespace:automeas_ui.MWM.ViewModel" 
             xmlns:viewm="clr-namespace:automeas_ui.MWM.ViewModel"
             d:DataContext="{d:DesignInstance Type=model:PageBarViewModel}"
             mc:Ignorable="d" 
             d:DesignHeight="50" d:DesignWidth="800">
    <UserControl.DataContext>
        <viewm:PageBarViewModel/>
    </UserControl.DataContext>
    <Border CornerRadius="20"
                Background="#323232"
            Margin="150,0,150,0">
        <ItemsControl ItemsSource="{Binding Pages}" 
                          Grid.Column="1"
                          Grid.Row="1">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"
                                Margin="0,0,10,0"
                                HorizontalAlignment="Center"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Viewbox Height="40" 
                             Margin="10,0,0,0">
                        <RadioButton
                            GroupName="pgs"
                            IsChecked="{Binding IsFocused, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
                    </Viewbox>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Border>
</UserControl>

PageBarViewModel.xaml.cs

namespace automeas_ui.MWM.ViewModel
{
    
    public class ViewedPage: INotifyPropertyChanged
    {
        private bool m_IsFocused;

        public bool IsFocused
        {
            get { return m_IsFocused; }
            set { m_IsFocused = value;
                OnPropertyChanged("IsFocused");
            }
        }
        public ViewedPage(bool focused = false)
        {
            IsFocused = focused;
        }
        private void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler? PropertyChanged;
    }
    public class PageBarViewModel
    {
        // internal interface
        const int NumberOfPages = 5;
        // eof
        private TrulyObservableCollection<ViewedPage> _Pages;
        public TrulyObservableCollection<ViewedPage> Pages
        {
            get { return _Pages; }
            set
            {
                if (_Pages == value) return;
                _Pages = value;
                NotifyPropertyChanged();
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public PageBarViewModel()
        {
            Pages = new TrulyObservableCollection<ViewedPage>();
            Pages.Add(new ViewedPage(true));
            for (int i = 1; i < NumberOfPages; i  )
            {
                Pages.Add(new ViewedPage());
            }
        }
        private ICommand? _npCommand;
        public ICommand NpCommad
        {
            get
            {
                if (_npCommand == null)
                {
                    _npCommand = new JSRelayCommand(
                        param => this.NextPage(),
                        param => this.CanSave()
                    );
                }
                return _npCommand;
            }
        }
        private bool CanSave()
        {
            // Verify command can be executed here
            return true;
        }

        private void NextPage()
        {
            int pgn = 1;
            foreach (var item in Pages)
            {
                if (item.IsFocused)
                {
                    item.IsFocused = false;
                    break;
                }
                pgn  ;
            }
            Pages[pgn].IsFocused = true;
            CollectionViewSource.GetDefaultView(Pages).Refresh();
        }

    }
}

----------FIXES THAT HAVE BEEN TRIED----------

  1. Use ObservableCollection and implement INotifyChanged for T
  2. Try to force update by adding/removing items from collection
  3. CollectionViewSource.GetDefaultView(Pages).Refresh();
  4. Implement TrulyObservableCollection
  5. Grouped RadioButtons are janky - ungroup them

Any fix is deeply appreciated

CodePudding user response:

you have two instances of PageBarViewModel:

in Window

<Window.DataContext>
    <viewm:PageBarViewModel/>
</Window.DataContext>

in UserControl

<UserControl.DataContext>
    <viewm:PageBarViewModel/>
</UserControl.DataContext>

remove UserControl.DataContext

CodePudding user response:

Maybe I am missing something, but in NextPage() it looks like

Pages[pgn] = true;

should be

Pages[pgn].IsFocused = true;
  • Related