Как передать значимый тип в ViewModel что бы при изменении его, в ViewModel он изменялся тоже и срабатывал binding?

Я реализую в своем приложении выпадающее меню, в котором находится список кнопок. Через ItemsControl и класс ActionButton(String ImgUrl, string Text) я отрисовываю список в xaml.

Условно в ViewModel выпадающего меню мы передаем некоторые классы с INotifyPropertyChanged И допустим нужно сделать такую возможность, что бы когда в классе с INotifyPropertyChanged изменялось некоторое свойство, то кнопка могла отреагировать на это и поменять текст на дополнительный(Или любой заданный другой)

Для реализации INotifyPropertyChanged я использую библиотеку CommunityToolkit.Mvvm.ComponentModel

Перейдем немного к коду:

    public partial class DropdownMenuViewModel : ObservableObject
    {
        public Server Server;
        public Profile Profile;
        public ObservableCollection<ActionButton> Buttons { get; set; }

        public DropdownMenuViewModel(Server server, Profile profile)
        {
            Server = server;
            Profile = profile;
            Buttons = new ObservableCollection<ActionButton>
            {
                new ActionButton("Img", "Включить сервер", Server.IsEnabled, "Выключить сервер"),
                new ActionButton("Img", "Войти", Profile.IsOnline, "Выйти"),
            };
        }
    }

    public partial class Server : ObservableObject
    {
        [ObservableProperty]
        private bool _isEnabled;
    }

    public partial class Profile : ObservableObject
    {
        [ObservableProperty]
        private bool _isOnline;
    }

    public class ActionButton(string imageUrl, string text, bool? condition = null, string? additionalText = null)
    {
        public string ImageUrl { get; set; } = imageUrl;

        public string Text { get; set; } = text;

        public bool? Condition { get; set; } = condition;

        public string? AdditionalText { get; set; } = additionalText;
    }

И код UserControl:

    <Grid>
        <ItemsControl Width="150" ItemsSource="{Binding Buttons}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Background="Aqua">
                        <TextBlock Text="{Binding ImageUrl}" />
                        <TextBlock HorizontalAlignment="Left">
                            <TextBlock.Style>
                                <Style TargetType="TextBlock">
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding Condition}" Value="{x:Null}">
                                            <Setter Property="Text" Value="{Binding Text}" />
                                        </DataTrigger>
                                        <DataTrigger Binding="{Binding Condition}" Value="False">
                                            <Setter Property="Text" Value="{Binding Text}" />
                                        </DataTrigger>
                                        <DataTrigger Binding="{Binding Condition}" Value="True">
                                            <Setter Property="Text" Value="{Binding AdditionalText}" />
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </TextBlock.Style>
                        </TextBlock>
                        <TextBlock Text="-----" />
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>

То есть я хочу добится такого поведения, что при изменении переменных внутри любого класса (Server.IsEnabled или Profile.IsOnline к примеру) внутри соответствующих элементов изменялся текст

Server.IsEnabled --> ActionButton.Condition --> Изменения в xaml

Но так как мы передаем не ссылки на переменные, то когда эти переменные изменяется в классе, изменения не изменяются в ActionButton.

Передать bool из класса используя ref нельзя. (Property 'x' access returns temporary value. 'ref' argument must be an assignable variable, field, or an array element)

Единственное к чему я пришел это использование интерфейса, который содержит bool переменную

Измененный код:

    public partial class DropdownMenuViewModel : ObservableObject
    {
        public Server Server;
        public Profile Profile;
        public ObservableCollection<ActionButton> Buttons { get; set; }

        public DropdownMenuViewModel(Server server, Profile profile)
        {
            Server = server;
            Profile = profile;
            Buttons = new ObservableCollection<ActionButton>
            {
                new ActionButton("Img", "Включить сервер", Server, "Выключить"),
                new ActionButton("Img", "Войти", Profile, "Выйти"),
            };
        }
    }

    public partial class Server : ObservableObject, IConditionChanged
    {
        [ObservableProperty]
        [NotifyPropertyChangedFor(nameof(Condition))]
        private bool _isEnabled;

        public bool Condition => IsEnabled;
    }


    public partial class Profile : ObservableObject, IConditionChanged
    {
        [ObservableProperty]
        [NotifyPropertyChangedFor(nameof(Condition))]
        private bool _isOnline;

        public bool Condition => IsOnline;
    }

    public class ActionButton(string imageUrl, string text, IConditionChanged? condition = null, string? additionalText = null)
    {
        public string ImageUrl { get; set; } = imageUrl;

        public string Text { get; set; } = text;

        public IConditionChanged? Condition { get; set; } = condition;

        public string? AdditionalText { get; set; } = additionalText;

        public bool IsHasCondition => Condition != null;
    }

    public interface IConditionChanged
    {
        bool Condition { get; }
    }

И код XAML:

    <Grid>
        <ItemsControl Width="150" ItemsSource="{Binding Buttons}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Background="Aqua">
                        <TextBlock Text="{Binding ImageUrl}" />
                        <TextBlock HorizontalAlignment="Left">
                            <TextBlock.Style>
                                <Style TargetType="TextBlock">
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding IsHasCondition}" Value="False">
                                            <Setter Property="Text" Value="{Binding Text}" />
                                        </DataTrigger>
                                        <MultiDataTrigger>
                                            <MultiDataTrigger.Conditions>
                                                <Condition Binding="{Binding IsHasCondition}" Value="True" />
                                                <Condition Binding="{Binding Condition.Condition}" Value="False" />
                                            </MultiDataTrigger.Conditions>
                                            <MultiDataTrigger.Setters>
                                                <Setter Property="Text" Value="{Binding Text}" />
                                            </MultiDataTrigger.Setters>
                                        </MultiDataTrigger>
                                        <MultiDataTrigger>
                                            <MultiDataTrigger.Conditions>
                                                <Condition Binding="{Binding IsHasCondition}" Value="True" />
                                                <Condition Binding="{Binding Condition.Condition}" Value="True" />
                                            </MultiDataTrigger.Conditions>
                                            <MultiDataTrigger.Setters>
                                                <Setter Property="Text" Value="{Binding AdditionalText}" />
                                            </MultiDataTrigger.Setters>
                                        </MultiDataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </TextBlock.Style>
                        </TextBlock>
                        <TextBlock Text="-----" />
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>

Как реализовать этот функционал правильным образом?

Является ли использование в классах которые являются представлением обьекта(model) использование INotifyPropertyChanged обобщенной практикой?


Ответы (0 шт):