Resolved Clearing Textbox With MVVM

madaxe2020

Well-known member
Joined
Sep 7, 2020
Messages
50
Programming Experience
5-10
The behavior I wont is for the textbox to clear after the button is selected and the record added to the combobox and the datagridview

I'm using MVVM as my pattern, and have bound the textbox to a property which I'm setting to string.Empty after the new record is created, but the textbox wont update.

Thanks

Madaxe

XAML:
<Window x:Class="WPFBinding.MainWindow"
        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:WPFBinding"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="530">
    <Grid>
        <StackPanel Width="500">
            <TextBox x:Name="TextInput" Text="{Binding  myContinentName,
                                                        Mode=TwoWay,
                                                        NotifyOnSourceUpdated=True,
                                                        UpdateSourceTrigger=PropertyChanged}"/>
            <Button Command="{Binding ButtonCommand}"
                    CommandParameter="{Binding  ElementName=TextInput,
                                                Path=Text}"
                    Content="Add to ComboBox"/>
            <ComboBox ItemsSource="{Binding myMessages}"/>
            <DataGrid x:Name="DGD_UserList"
                        AutoGenerateColumns="False" 
                        ItemsSource="{Binding   myContinents,
                                                Mode=TwoWay,
                                                NotifyOnSourceUpdated=True,
                                                UpdateSourceTrigger=PropertyChanged}"                 
                        Margin="0,5,5,5"
                        ColumnWidth="*"
                        Background="#FF9F9E9E" HorizontalAlignment="Right" Width="481">
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding continent_name}" Header="Continent Name" IsReadOnly="True"/>
                    <DataGridTextColumn Binding="{Binding modifying_user_id}" Header="Modifying User" IsReadOnly="True"/>
                    <DataGridTextColumn Binding="{Binding modifying_date}" Header="Modification Date" IsReadOnly="True"/>
                </DataGrid.Columns>
            </DataGrid>
        </StackPanel>
    </Grid>
</Window>

Relay:
using System;
using System.Windows.Input;

namespace WPFBinding
{
    public 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");
            }
            else
            {
                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 this._canExecute == null ? true : this._canExecute(parameter);
        }
        public void Execute(object parameter)
        {
            this._execute.Invoke(parameter);
        }
    }
}


View Model Base:
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WPFBinding.Models.Base
{
    public class ViewModelBase : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}

View Model:
using System;
using System.Collections.ObjectModel;
using WPFBinding.Models;
using WPFBinding.Models.Base;

namespace WPFBinding.ViewModels
{
    public class DataViewModel : ViewModelBase
    {
        public string myContinentName { get; set; }

        public ObservableCollection<Continent> myContinents { get; set; }
        public ObservableCollection<string> myMessages { get; private set; }
        public RelayCommand ButtonCommand { get; private set; }

        public DataViewModel()
        {
            this.myMessages = new ObservableCollection<string>() { };
            this.myContinents = new ObservableCollection<Continent>() { };

            this.ButtonCommand = new RelayCommand(AddtoComboBox, ComboboxCanAdd);
        }

        public void AddtoComboBox(object message)
        {
            if (this.myMessages.Contains((string)message) == false)
            {
                Continent continent = new Continent((string)message, 1, DateTime.Now);
                this.myContinents.Add(continent);
                this.myMessages.Add((string)message);

                this.myContinentName = string.Empty;
            }
        }

        public bool ComboboxCanAdd(object message)
        {
            if (string.IsNullOrWhiteSpace((string)message) == true || this.myMessages.Contains((string)message) == true)
            {
                return false;
            }
            else
            {
                return true;
            }
        }   
    }
}

Model:
using System;

namespace WPFBinding.Models
{
    public class Continent
    {
        public string continent_name { get; set; }
        public int modifying_user_id { get; set; }
        public DateTime modifying_date { get; set; }

        public Continent(string ContinentName, int ModifyingUserId, DateTime ModifyingDate)
        {
            this.continent_name = ContinentName;
            this.modifying_user_id = ModifyingUserId;
            this.modifying_date = ModifyingDate;
        }
    }
}
 
I had to change the ViewModelbase to an abstract class and change the NotifyPropertyChanged to protected virtual void

then in the viewmodel

private string _myContinentName;
public string myContinentName { get { return this._myContinentName; } set { this._myContinentName = value; base.NotifyPropertyChanged(); } }

change my property

Can I simplify this with Linq or other approach

Thanks

Madaxe


ViewModelBase:
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WPFBinding.Models.Base
{
    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}
 
If you want something less verbose, assuming you are using the latest C#, try something like:
C#:
string _myContinentName;
public string MyContinentName
{
    get => _myContinentName;
    set
    {
        _myContinentName = value;
        NotifyPropertyChanged();
    }
}

Ignore ReSharper and StyleCop when it suggests using the this. and base.. The compiler will tell you when there is any ambiguity. You are already using the Hungarian naming convention of using the underscore to denote that the variable is a class field, so there should not be any confusion or ambiguity in the eyes of people reading your code.

The only times you need to use these two keywords are:
If you want to be extremely explicit about which member you are trying to access. Some teams have this as a naming convention, and/or force the StyleCop or ReSharper rules;
If you need to be that explicit is when you have a deep hierarchy and you have overridden some of the members using the new.

You don't need to explicitly declare things as private, unless the team you are working with has a coding convention of always writing out private.

Explore using expression bodied getters/setters. Above, I tried to make the getter terser.
 
Last edited:
Back
Top Bottom