Search code examples
c#mvvmmauicollectionview

the collectionview contains an editor, how to change the text in the ViewModel with changes in the editor #maui


when a user changes the text in the Editor, I need the changes to be displayed in private MessageModel messagemodel,the same with the button that should add new messages

<CollectionView ItemsSource="{Binding MessageModels.messege}"
                 x:Name="collectionView">
    <CollectionView.Header>
        <HorizontalStackLayout HorizontalOptions="Center" >
            <Label TextColor="Black" Text="Messages" VerticalOptions="Center"></Label>
            <Button MinimumWidthRequest="10"
                    MinimumHeightRequest="10"
                    Command="{Binding  addNewmessageCommand}"
                    Text="Add New message"></Button>

        </HorizontalStackLayout>
    </CollectionView.Header>
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <HorizontalStackLayout Padding="2">
                <Editor AutoSize="TextChanges" Text="{Binding . }"  WidthRequest="300" FontSize="16" TextColor="#1565C0" />
                <Button Background="Red"
                        Command="{Binding Source={x:Reference collectionView}, Path=BindingContext.DeleteCommand}"
                        CommandParameter="{Binding .}"
                        Text="X" />
            </HorizontalStackLayout>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

I tried to use INotifyPropertyChanged, but it didn't help either

public partial class MessageModelEllementVM : CommunityToolkit.Mvvm.ComponentModel.ObservableObject
{
    AddNewWayD addNewWayD;
    public event PropertyChangedEventHandler PropertyChanged;
    public MessageModelEllementVM(MessageModel messageModel, List<string> ways, int gridPosition, AddNewWayD addNewWay)
    {
        this.addNewWayD = addNewWay;
        this.messageModels = messageModel;
        GridPosition = gridPosition;
        photoURL = "фото не выбрали";
        dialogimage = new Image();
        messageModels.Plot_twist.ToList().ForEach(i => plot_twist += "," + i.ToString());
        answers = AnswerTextConverter.Convert(messageModels.AnswerText, ways);
    }

    public MessageModelEllementVM()
    {
        this.messageModels = new MessageModel();
        dialogimage = new Image();
    }

    private int GridPosition;

    [ObservableProperty]
    public ObservableCollection<AnswerText> answers;

    [ObservableProperty]
    Image dialogimage;
    FileResult? uploadedFile;

    [ObservableProperty]
    string plot_twist;
    [ObservableProperty]
    private MessageModel messageModels;

    [ObservableProperty]
    string photoURL;
    [RelayCommand]

    public void AddWay()
    {
        //addNewWayD(GridPosition,messageModels);

    }

    [RelayCommand]
    async void AddImge()
    {
        uploadedFile = await MediaPicker.PickPhotoAsync();

        if (uploadedFile != null)
        {
            dialogimage.Source = uploadedFile.FullPath;
        }
    }

    [RelayCommand]
    void addNewmessage()
    {
        messageModels.messege.Add(string.Empty);
    }

    [RelayCommand]
    private void Delete(string text)
    {
        foreach (var item in messageModels.messege)
        {
            if (item == text)
            {
                messageModels.messege.Remove(item);
                break;
            }
        }
    }
}

Code MessageModel I tried to add events there too but it didn't help

public class MessageModel
{
    public MessageModel()
    {
        Plot_twist = new List<int>();
        messege = new ObservableCollection<string>();
        AnswerText = new ObservableCollection<(string Answer, List<int> way)>();
    }

    public List<MessageModel> messageModel = new List<MessageModel>();
    public List<int> Plot_twist { get; set; } //номер диалога по типу  ["0","1","1"] - глава 0 подветка 1 в подветке подветка 1
    public ObservableCollection<string> messege { get; set; } //сообщения от Алисы (массив чтобы несколько подряд ) 
    public string photoURL { get; set; }

    public ObservableCollection<(string Answer, List<int> way)> AnswerText; //way - адрес на продолжение 
}

I need the data to change, but I'm still a beginner and I don't understand how to do it. can you please explain how it works and what ways it can be fixed


Solution

  • Your Editor's Text property is bound to a plain string. Data bindings don't change objects themselves (in your case - string), they change object's properties. That's why you need to bind to a property of some sort.
    The simplest way to fix this would be implementing a wrapper class with a string property for your message:

    public class Message
    {
        //note that binding to object's fields also doesn't work:
        //this works
        public string Text { get; set; }
    
        //this - does not!
        //public string Text;
    
        public Message(string text)
        {
            Text = text;
        }
    }
    

    And using it like
    public ObservableCollection<Message> messege { get; set; }
    In the MessageModelEllementVM, and
    <Editor Text="{Binding Text }" ... />
    In the xaml

    Also, there is no need to use foreach in your Delete command. Leave
    <Button CommandParameter="{Binding .}" ... />
    as it is and change the command to:

    [RelayCommand]
    private void Delete(Message msg)
    {
        messageModels.messege.Remove(msg);
    }
    

    This will remove the exact object you are passing in the CommandParameter