Search code examples
c#wpfobservablecollectionrelaycommandcommunity-toolkit-mvvm

Using MVVM Communitytoolkit to change property of initialed list of buttons using RelayCommand


I have WPF application with .NETCore 7 and when it load I have view and viewmodel

I generate a list of buttons using code in viewmodel as following

 public partial class DataViewModel : ObservableObject, INavigationAware
    {
        private bool _isInitialized = false;

        [ObservableProperty]
        private ObservableCollection<Scene> _scenes;


        public void OnNavigatedTo()
        {
            if (!_isInitialized)
                InitializeViewModel();
        }

        public void OnNavigatedFrom()
        {
        }

        private void InitializeViewModel()
        {
            var scenesCollection = new ObservableCollection<Scene>();

            for (int i = 0; i < 20; i++)
            {
                string name = "Scene " + (i + 1);
                var scene = new Scene
                {
                    Name = name,
                    Color = new SolidColorBrush(Color.FromArgb(200, 231, 129, 4)),
                    Icon = SymbolRegular.Play48,
                    IsPlaying = false
                };
                scene.PlayStopCommand = new RelayCommand(() => PlayStop(scene));
                scenesCollection.Add(scene);
            }

            Scenes = scenesCollection;

            _isInitialized = true;
        }

        [RelayCommand]
        public void PlayStop(Scene scene)
        {
            var random = new Random();
            if (scene.IsPlaying)
            {
                scene.Icon = SymbolRegular.Play48;
                scene.IsPlaying = false;
            }
            else
            {
                scene.Icon = SymbolRegular.Pause48; // Change the icon to the desired value
                scene.IsPlaying = true;
            }
            scene.Color = new SolidColorBrush(Color.FromArgb(
                (byte)200,
                (byte)random.Next(0, 250),
                (byte)random.Next(0, 250),
                (byte)random.Next(0, 250)));
        }
    }

Structure for scene are as followed

 public struct Scene
    {
        public int ID { get; set; }

        public string Name { get; set; }

        public Brush Color { get; set; }

        public RelayCommand PlayStopCommand { get; set; }

        public SymbolRegular Icon { get; set; }

        public bool IsPlaying { get; set; }
    }

XMAL code

<ui:VirtualizingItemsControl
            Foreground="{DynamicResource TextFillColorSecondaryBrush}"
            ItemsSource="{Binding ViewModel.Scenes, Mode=OneWay}"
            VirtualizingPanel.CacheLengthUnit="Item">
            <ItemsControl.ItemTemplate>
                <DataTemplate DataType="{x:Type models:Scene}">
                    <ui:Button
                        x:Name="buttin"
                        Width="600"
                        Height="50"
                        Margin="2"
                        Padding="0"
                        HorizontalAlignment="Center"
                        VerticalAlignment="Center"
                        Appearance="Secondary"
                        Background="{Binding Color, Mode=OneWay}"
                        Command="{Binding PlayStopCommand}"
                        Content="{Binding Name, Mode=TwoWay}"
                        FontFamily="Arial"
                        FontSize="25"
                        FontWeight="Bold"
                        Foreground="White"
                        Icon="{Binding Icon, Mode=TwoWay}"
                        IconFilled="True" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ui:VirtualizingItemsControl>

The buttons do initialize correctly, however, when I click on any buttons nothing changes.

I even tried to use Breakpoints and I found out that every time I call the PlayStopCommand scene.IsPlaying is always false and does not change, so this means that the code somehow changes another temporary scene, I'm not sure.


Solution

  • I ended up changing the Scene structure to ObservableObject

       public partial class Scene : ObservableObject
    {
        [ObservableProperty]
        public int _iD;
    
        [ObservableProperty]
        public string? name;
    
        [ObservableProperty]
        public Brush? color;
    
        [ObservableProperty]
        public RelayCommand? playStopCommand;
    
        [ObservableProperty]
        public SymbolRegular icon;
    
        [ObservableProperty]
        public bool isPlaying;
    }