Home > Enterprise >  I can't retrieve the message/text left in a textbox through a relay commands as it always retur
I can't retrieve the message/text left in a textbox through a relay commands as it always retur

Time:10-07

This is my main body which handles the data. I invoke a command through XAML which should retrieve the data which is currently contained in the textbox in my xaml. When I try to print it or display it it doesn't work because it returns null.

namespace DoctorApplication.MVVM.ViewModel
{
    internal class DataViewModel : ObservableObject
    {
        private string message;

        public string Message
        {
            get { return message; }
            set 
            { 
                message = value;
                OnPropertyChanged();
            }
        }

        public RelayCommand SendCommand { get; set; }  

        public BindableCollection<UserDataModel> users { get; set; }
        public ObservableCollection<MessageModel> messages { get; set; }

        public RelayCommand MessageCommand { get; set; }
        public RelayCommand ConsoleLogcommand { get; set; }
        
        private UserDataModel selectedUser;

        public UserDataModel SelectedUser
        {
            get { return selectedUser; }
            set
            {
                selectedUser = value;
                OnPropertyChanged();
            }
        }

        public DataViewModel()
        {
            users = new BindableCollection<UserDataModel>();

            UserDataModel test1 = new UserDataModel("user1", "0612345678", 12345, 20, 80);
            UserDataModel test2 = new UserDataModel("user2", "0698765432", 67890, 30, 70);
            test1.AddMessage("Hello");
            test1.AddMessage("I'm a console!");
            test1.AddMessage("Goodbye!");
            test2.AddMessage("Hi!");
            test2.AddMessage("What's up?");
            users.Add(test1);
            users.Add(test2);

            MessageCommand = new RelayCommand(DisplayInMessageBox);

            SendCommand = new RelayCommand(DisplayInMessageBox);
        }
      
        public void DisplayInMessageBox(object message)
        {
            Console.WriteLine(message);
        }
    }
}

This is my XAML. It's a UserControl being displayed on my Main window.

<Grid Grid.Row="2" DockPanel.Dock="Bottom" Name="ChatTextBoxPanel">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="8*" />
                        <ColumnDefinition Width="2*" />
                    </Grid.ColumnDefinitions>
                    <TextBox
                        Grid.Column="0"
                        Text="{Binding Message, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"
                        >
                        <TextBox.DataContext>
                            <m:DataViewModel/>
                        </TextBox.DataContext>
                    </TextBox>
                    <Button
                        Command="{Binding SendCommand}"
                        Background="#FF1B47F5"
                        BorderBrush="#FF1B1B1B"
                        Content="➤"
                        Foreground="#FFFFF7F7"
                        Grid.Column="1"
                        >
                        <Button.DataContext>
                            <m:DataViewModel/>
                        </Button.DataContext>
                    </Button>
                </Grid>

And this is the relay command I use to invoke the command through XAML

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace DoctorApplication.Core
{
    /* > The RelayCommand class implements the ICommand interface and is used to relay a command from the View to the
    ViewModel */
    internal class RelayCommand : ICommand
    {
        readonly Action<object> execute;
        readonly Predicate<object> canExecute;

        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
            {
                throw new NullReferenceException("execute");
            }

            this.execute = execute;
            this.canExecute = canExecute;
        }

        public RelayCommand(Action<object> execute) : this(execute, null)
        {
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested  = value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public bool CanExecute(object parameter)
        {
            return canExecute == null ? true : canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            execute.Invoke(parameter);
        }
    }
}

I would appreciate any tips on anything I can improve or anything that could possibly help in this situation as I am clueless to what I can change.

Update: By setting adding the command parameter as such:

CommandParameter="{Binding ElementName=ChatTextBox}"

I now receive the value of the text in the textbox but it now also include the following before the result (input: "test"): System.Windows.Controls.TextBox: test

Setting it toString() or (string) doesn't have any effect.

CodePudding user response:

Setting the DataContext of the TextBox and the Button to two different view model instances is a programming error.

There should only be one assignment at the top level element of the view:

<Window ...>
    <Window.DataContext>
        <m:DataViewModel/>
    </Window.DataContext>
    <Grid Grid.Row="2" DockPanel.Dock="Bottom" Name="ChatTextBoxPanel">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="8*" />
            <ColumnDefinition Width="2*" />
        </Grid.ColumnDefinitions>
        <TextBox
            Grid.Column="0"
            Text="{Binding Message, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" />
        <Button
            Grid.Column="1"
            Command="{Binding SendCommand}"
            Background="#FF1B47F5" BorderBrush="#FF1B1B1B"
            Foreground="#FFFFF7F7" Content="➤"/>
    </Grid>
</Window>

Since the TextBox's Text property is bound to the Message property of the same view model object, the SendCommand may directly access the Message property.

public void DisplayInMessageBox(object p)
{
    Console.WriteLine(Message);
}

CodePudding user response:

Solved it by adding the following parameter:

CommandParameter="{Binding Text, ElementName=ChatTextBox}"
  • Related