How to clear textbox in WPF MVVM with clear button - c#

Okay, so I wanna clear the text in my textbox with a click from a button. Both are placed within the first stackpanel in the XAML code. I'm trying to make it work with commands and bindings, but I just can't seem to make it work.. Any suggestions? SqlQueryCommand is bound to the clear button, SqlQueryString is bound to the textbox.
Vievmodel:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using WpfMVVM.Commands;
namespace PoC.ViewModels
{
class MainWindowViewModel
{
public RelayCommand ClearSqlQueryCommand { get; private set; }
public RelayCommand ClearFilterCommand { get; private set; }
public RelayCommand ClearFilterByIdCommand { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
private string sqlQueryString;
private string filterString;
private string filterByIdString;
public string SqlQueryString
{
get
{
return sqlQueryString;
}
set
{
sqlQueryString = value;
OnPropertyChanged(nameof(SqlQueryString));
}
}
public string FilterString
{
get
{
return filterString;
}
set
{
filterString = value;
OnPropertyChanged(nameof(FilterString));
}
}
public string FilterByIdString
{
get
{
return filterByIdString;
}
set
{
filterByIdString = value;
OnPropertyChanged(nameof(FilterByIdString));
}
}
public MainWindowViewModel()
{
ClearSqlQueryCommand = new RelayCommand(ClearSqlQuery, CanClearSqlQuery);
ClearFilterCommand = new RelayCommand(ClearFilter, CanClearFilter);
ClearFilterByIdCommand = new RelayCommand(ClearFilterById, CanClearFilterById);
}
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public void ClearSqlQuery(object parameter)
{
SqlQueryString = string.Empty;
}
public bool CanClearSqlQuery(object parameter)
{
return true;
}
public void ClearFilter(object parameter)
{
}
public bool CanClearFilter(object parameter)
{
return true;
}
public void ClearFilterById(object parameter)
{
}
public bool CanClearFilterById(object parameter)
{
return true;
}
}
}
RelayCommand:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Input;
namespace WpfMVVM.Commands
{
public class RelayCommand : ICommand
{
Action<object> _execute;
Func<object, bool> _canExecute;
public RelayCommand(Action<object> execute, Func<object, bool> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (_canExecute != null)
{
return _canExecute(parameter);
}
else
{
return false;
}
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
}
XAML:
<Window x:Class="PoC.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:PoC"
xmlns:viewModels="clr-namespace:PoC.ViewModels"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<viewModels:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<TreeView>
</TreeView>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="1*"/>
<RowDefinition Height="5*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" BorderThickness="0 0 0 1" BorderBrush="Black"/>
<StackPanel Grid.Row="0" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBox Text="{Binding SqlQueryString, UpdateSourceTrigger=PropertyChanged}" Height="30" Width="450" TextAlignment="Center"/>
<Button Content="Execute" Margin="10 0" Padding="5 0"/>
<Button Content="Clear" Padding="5 0" Command="{Binding ClearSqlQueryCommand}"/>
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBox Text="{Binding FilterString}" Grid.Row="0" Height="30" Width="200"/>
<Button Content="Filter" Margin="10 0" Padding="5 0"/>
<Button Content="Clear" Padding="5 0" Margin="0 0 115 0"/>
<TextBox Text="{Binding FilterByIdString}" Grid.Row="0" Height="30" Width="100"/>
<Button Content="Filter" Margin="10 0 0 0" Padding="5 0"/>
</StackPanel>
<DataGrid Grid.Row="2" VerticalScrollBarVisibility="Visible" BorderThickness="0 1 1 1"/>
</Grid>
</Grid>

You seem to be missing : INotifyPropertyChangedon the MainWindowViewModelclass.

You can easily do that by setting its value to "".
texbox.Text="";

Related

Using Update button in WPF ListView to update Selected Item

I have to make a WPF App to add, delete and update Items for Client Management purposes. I have so far been able to add and remove the items to the List using MVVM but I am unable to update the selected items. I require help in this regard.
The code for the project is as follows:
Details Class.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assignment_2.Model
{
public class Details :INotifyPropertyChanged
{
private string name;
public string Name
{ get { return name; } set { name = value; OnPropertyChanged(Name); } }
private string company;
public string Company
{ get { return company; } set { company = value; OnPropertyChanged(Company); } }
private string region;
public string Region
{ get { return region; } set { region = value; OnPropertyChanged(Region); } }
private string hra;
public string HRA
{
get { return hra; }
set
{
hra = value;
OnPropertyChanged(HRA);
}
}
private string basic;
public string Basic
{ get { return basic; }
set { basic = value;
OnPropertyChanged(Basic);
}
}
private string pf;
public string PF
{ get { return pf; }
set
{
pf = value;
OnPropertyChanged(PF);
}
}
private string salary;
public string Salary
{ get { return salary; }
set
{
salary = value;
OnPropertyChanged(Salary);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string det)
{
PropertyChangedEventHandler pc = PropertyChanged;
if (pc != null)
pc(this, new PropertyChangedEventArgs(det));
}
}
}
DetailsViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using Assignment_2.Commands;
using Assignment_2.Model;
namespace Assignment_2.ViewModel
{
public class DetailsViewModel : INotifyPropertyChanged
{
private Details record;
public Details Record
{
get { return record; }
set { record = value; NotifyPropertyChanged("Record"); }
}
private ObservableCollection<Details> records;
public ObservableCollection<Details> Records
{
get { return records; }
set { records = value; } // NotifyPropertyChanged("Records");
}
private ICommand _SubmitCommand;
public ICommand SubmitCommand
{
get
{
if (_SubmitCommand == null)
{
_SubmitCommand = new RelayCommand(SubmitExecute, CanSubmitExecute, false);
}
return _SubmitCommand;
}
}
public DetailsViewModel()
{
Record = new Details();
Records = new ObservableCollection<Details>();
}
private void SubmitExecute(object parameter)
{
var TempRecord = new Details();
//TempRecord = Record;
TempRecord.Name = Record.Name;
TempRecord.Company = Record.Company;
TempRecord.Region = Record.Region;
TempRecord.HRA = Record.HRA;
TempRecord.Salary = Record.Salary;
TempRecord.Basic = Record.Basic;
TempRecord.PF = Record.PF;
Records.Add(TempRecord);
}
private bool CanSubmitExecute(object parameter)
{
if (string.IsNullOrEmpty(Record.Name) || string.IsNullOrEmpty(Record.Company))
{
return false;
}
else
{
return true;
}
}
private ICommand _SubmitCommand1;
public ICommand SubmitCommand1
{
get
{
if (_SubmitCommand1 == null)
{
_SubmitCommand1 = new RelayCommand(SubmitExecute1, CanSubmitExecute1, false);
}
return _SubmitCommand1;
}
}
public int findIndex(Details myDetails)
{
int count = 0;
for (int i = 0; i < Records.Count; i++)
{
count = 0;
Details myRecord = Records[i];
if (myRecord.Name == myDetails.Name)
count++;
else continue;
if (myRecord.Company == myDetails.Company)
count++;
else continue;
if (myRecord.Region == myDetails.Region)
count++;
else continue;
if (myRecord.Salary == myDetails.Salary)
count++;
else continue;
if (myRecord.HRA == myDetails.HRA)
count++;
else continue;
if (myRecord.Basic == myDetails.Basic)
count++;
else continue;
if (myRecord.PF == myDetails.PF)
count++;
else continue;
if (count == 7)
return i;
}
return -1;
}
private void SubmitExecute1(object parameter)
{
Records.Remove((Details)parameter);
}
private bool CanSubmitExecute1(object parameter)
{
if (string.IsNullOrEmpty(Record.Name) || string.IsNullOrEmpty(Record.Company))
{
return false;
}
else
{
return true;
}
}
private ICommand _SubmitCommand2;
public ICommand SubmitCommand2
{
get
{
if (_SubmitCommand2 == null)
{
_SubmitCommand2 = new RelayCommand(SubmitExecute2, CanSubmitExecute2, false);
}
return _SubmitCommand2;
}
}
private void SubmitExecute2(object parameter)
{
}
private bool CanSubmitExecute2(object parameter)
{
if (string.IsNullOrEmpty(Record.Name) || string.IsNullOrEmpty(Record.Company))
{
return false;
}
else
{
return true;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string de)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(de));
}
}
}
RelayCommand.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Assignment_2.Commands
{
class RelayCommand : ICommand
{
Action<object> executeAction;
Func<object, bool> canExecute;
bool canExecuteCache;
public RelayCommand(Action<object> executeAction, Func<object, bool> canExecute, bool canExecuteCache)
{
this.canExecute = canExecute;
this.executeAction = executeAction;
canExecuteCache = canExecuteCache;
}
public bool CanExecute(object parameter)
{
if (canExecute == null)
{
return true;
}
else
{
return canExecute(parameter);
}
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public void Execute(object parameter)
{
executeAction(parameter);
}
}
}
MainWindow.xaml
<Window x:Class="Assignment_2.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:vm="clr-namespace:Assignment_2.ViewModel"
Title="MainWindow" Height="401" Width="472">
<Window.Resources>
<vm:DetailsViewModel x:Key="DetailsViewModel"/>
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource DetailsViewModel}}" RenderTransformOrigin="0.5,0.5" Margin="0,0,1,1">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-0.21"/>
<TranslateTransform/>
</TransformGroup>
</Grid.RenderTransform>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="20.59"/>
<RowDefinition Height="22.906"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="29*"/>
<RowDefinition Height="293*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Text=" Name" HorizontalAlignment="Center" Margin="0,0,0,4" Grid.RowSpan="2" Width="35" />
<TextBox Grid.Column="1" Width="100" HorizontalAlignment="Left" Text="{Binding Record.Name,UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="2,0,0,1" Grid.RowSpan="2"/>
<TextBlock Text="Company" HorizontalAlignment="Center" Margin="0,2,0,3" Width="51" Grid.RowSpan="2" Grid.Row="1"/>
<TextBox Grid.Column="1" Width="100" HorizontalAlignment="Left" Text="{Binding Record.Company,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" Margin="2,2,0,1" Grid.Row="1"/>
<TextBlock Grid.Row="2" Text="Region" HorizontalAlignment="Center" Margin="0,1,0,4" Width="37"/>
<TextBox Grid.Row="2" Grid.Column="1" Width="100" HorizontalAlignment="Left" Text="{Binding Record.Region,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" Margin="3,1,0,4"/>
<TextBlock Grid.Column="1" Text="HRA" HorizontalAlignment="Left" Margin="131,-1,0,2" Width="23"/>
<TextBox Grid.Column="1" Width="83" HorizontalAlignment="Left" Text="{Binding Record.HRA,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" Margin="162,0,0,1"/>
<TextBlock Grid.Column="1" Text="Basic" HorizontalAlignment="Left" Margin="129,2,0,13" Width="26" Grid.RowSpan="2" Grid.Row="1"/>
<TextBox Grid.Column="1" Width="81" HorizontalAlignment="Left" Text="{Binding Record.Basic,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" Margin="162,2,0,3" Grid.Row="1"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="PF" HorizontalAlignment="Left" Margin="144,1,0,5" Width="12"/>
<TextBox Grid.Row="2" Grid.Column="1" Width="100" HorizontalAlignment="Left" Text="{Binding Record.PF,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" Margin="162,2,0,1"/>
<TextBlock Grid.Column="1" Text="Salary" HorizontalAlignment="Left" Margin="268,-1,0,1" Width="36"/>
<TextBox Grid.Column="1" Width="100" HorizontalAlignment="Left" Text="{Binding Record.Salary,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" Margin="304,0,0,21" Grid.RowSpan="2"/>
<Button Content="Add" Command="{Binding SubmitCommand }" HorizontalAlignment="Left" Grid.Row="4" Margin="121,4,0,5" Width="44" Grid.Column="1"/>
<ListView x:Name="ListedView" ItemsSource="{Binding Records}" Width="Auto" Grid.Row="5" Margin="38,3,13,36" Grid.ColumnSpan="2">
<ListView.View >
<GridView >
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="Auto" />
<GridViewColumn Header="Company" DisplayMemberBinding="{Binding Company}" Width="Auto"/>
<GridViewColumn Header="Region" DisplayMemberBinding="{Binding Region}" Width="Auto" />
<GridViewColumn Header="HRA" DisplayMemberBinding="{Binding HRA}" Width="Auto" />
<GridViewColumn Header="Basic" DisplayMemberBinding="{Binding Basic}" Width="Auto" />
<GridViewColumn Header="PF" DisplayMemberBinding="{Binding PF}" Width="Auto" />
<GridViewColumn Header="Salary" DisplayMemberBinding="{Binding Salary}" Width="Auto" />
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="Remove" Margin="1,36,50,150" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListView},Path=DataContext.SubmitCommand1}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
Any help is appreciated in this regard. Thanks
If I understand your issue correctly, you should bind the SelectedItem property of the ListView to be able to edit the currently selected item in the TextBox elements above the ListView:
<ListView SelectedItem="{Binding Record}" ... />
With or without Binding you can do it like this :
if ((sender as ListView).SelectedValue != null)
{
string item = (sender as ListView).SelectedValue.ToString();
SelectedIndex = (sender as ListView).SelectedIndex;
list.Items[SelectedIndex] = "Updated";
}
(I like to add a ContextMenu on my ListViewItems so it is easier for users to modify the specified clicked item) :
<ListView x:Name="list">
<ListView.ContextMenu>
<ContextMenu x:Name="contextmenu">
<MenuItem x:Name="Add" Header="Add" Click="Add_Click"/>
<MenuItem x:Name="Del" Header="Delete" Click="Del_Click"/>
<MenuItem x:Name="Update" Header="Update" Click="Update_Click"/>
</ContextMenu>
</ListView.ContextMenu>
</ListView>

OnPropertyChanged not triggered

I'm new in MVVM and I tried to retrieve from 2 textboxes an username and a password. But OnPropertyChanged is not triggered even if I have UpdateSourceTriggered=PropertyChanged. Here is the code. I also tried with an class RelayCommand which uses the delegates Action<> and Func<> but neither that worked.
LogInCommand.cs
using LibraryApp.ViewModels;
using System;
using System.Windows.Input;
namespace LibraryApp.Commands
{
public class LogInCommand : ICommand
{
private LogInViewModel _logInViewModel;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public LogInCommand(LogInViewModel logInViewModel)
{
_logInViewModel = logInViewModel;
}
public bool CanExecute(object parameter) => _logInViewModel.CanUpdate;
public void Execute(object parameter) => _logInViewModel.Execute();
}
}
LogInModel.cs
using System.ComponentModel;
namespace LibraryApp.Models
{
public class LogInModel : INotifyPropertyChanged
{
private string _strUsername;
private string _strPassword;
public string Username
{
get { return _strUsername; }
set {
_strUsername = value;
OnPropertyChanged(Username);
}
}
public string Password
{
get { return _strPassword; }
set
{
_strPassword = value;
OnPropertyChanged(Password);
}
}
public LogInModel(string strUsername, string strPassword)
{
Username = strUsername;
Password = strPassword;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
#endregion
}
}
LogInViewModel.cs
using LibraryApp.Commands;
using LibraryApp.Models;
using LibraryApp.Models.DatabaseModel;
using LibraryApp.Views;
using System.Linq;
using System.Windows;
using System.Windows.Input;
namespace LibraryApp.ViewModels
{
public class LogInViewModel
{
private LogInModel _user;
private LibraryEntities _database;
public LogInModel User
{
get { return _user; }
}
public bool CanUpdate
{
get
{
if (User == null)
{
return false;
}
return !(string.IsNullOrWhiteSpace(User.Username) && string.IsNullOrWhiteSpace(User.Password));
}
}
public ICommand SubmitCommand { get; set; }
public void Execute()
{
if (IsUserInDatabase())
{
UserPage userPage = new UserPage();
userPage.Show();
}
else
{
MessageBox.Show("Username or password are incorrect.");
}
}
public LogInViewModel()
{
_user = new LogInModel("admin", "d7x2rt58");
_database = new LibraryEntities();
SubmitCommand = new LogInCommand(this);
}
public bool IsUserInDatabase()
{
if (_database.BookKeepers.First(it => it.Username == User.Username && it.Password == User.Password) != null)
{
return true;
}
return false;
}
}
}
LogIn.xaml
<Window x:Class="LibraryApp.Views.LogIn"
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:LibraryApp.Views"
mc:Ignorable="d"
Title="LogIn" Height="150" Width="300" WindowStartupLocation="CenterScreen" ResizeMode="NoResize">
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="1" Content="Log In" HorizontalAlignment="Center"/>
<Label Grid.Row="1" Grid.Column="0" Content="Username"/>
<Label Grid.Row="2" Grid.Column="0" Content="Password"/>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding LogInModel.Username, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding LogInModel.Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Button Grid.Row="3" Grid.Column="2" Command="{Binding SubmitCommand}" Content="Log In"/>
</Grid>
</Window>
LogIn.xaml.cs
using LibraryApp.ViewModels;
using System.Windows;
namespace LibraryApp.Views
{
/// <summary>
/// Interaction logic for LogIn.xaml
/// </summary>
public partial class LogIn : Window
{
public LogIn()
{
InitializeComponent();
LogInViewModel logInViewModel = new LogInViewModel();
DataContext = logInViewModel;
}
}
}
UserPage.xaml
<Window x:Class="LibraryApp.Views.UserPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:LibraryApp.Views"
mc:Ignorable="d"
Height="450" Width="800"
Title="UserPage">
<Grid>
<Label Content="Welcome" HorizontalAlignment="Center" Margin="0,50,0,0" VerticalAlignment="Top" Height="52" Width="134" FontSize="30"/>
<Button Content="Add book" HorizontalAlignment="Left" Margin="104,145,0,0" VerticalAlignment="Top" Width="75"/>
<Button Content="Borrow book" HorizontalAlignment="Left" Margin="104,190,0,0" VerticalAlignment="Top" Width="75"/>
<Button Content="Delete book" HorizontalAlignment="Left" Margin="104,242,0,0" VerticalAlignment="Top" Width="75"/>
<Button Content="Add user" HorizontalAlignment="Left" Margin="314,145,0,0" VerticalAlignment="Top" Width="75"/>
<Button Content="Delete user" HorizontalAlignment="Left" Margin="314,195,0,0" VerticalAlignment="Top" Width="75"/>
<Button Content="Search" HorizontalAlignment="Left" Margin="314,242,0,0" VerticalAlignment="Top" Width="75"/>
<Button Content="Back" HorizontalAlignment="Left" Margin="648,360,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
</Window>
UserPage.xaml.cs
using System.Windows;
namespace LibraryApp.Views
{
/// <summary>
/// Interaction logic for UserPage.xaml
/// </summary>
public partial class UserPage : Window
{
public UserPage()
{
InitializeComponent();
}
}
}
Welcome to SO. First of all, try to limit the amount of code you post to just the parts that are necessary. People will quickly skip your question when you post a wall of text.
To answer your question...
In LogInModel in the setters of Username and Password you are raising the event by passing in the values of the properties and not the property names themselves:
public string Username
{
get { return _strUsername; }
set
{
_strUsername = value;
OnPropertyChanged(Username);
}
}
Instead you should pass in the name of the property itself:
public string Username
{
get { return _strUsername; }
set
{
_strUsername = value;
OnPropertyChanged(nameof(Username));
// The above is the same as:
// OnPropertyChanged("Username");
}
}

How to Create a Method to save user input

I have the following view here where the user is able to input three different items: LockedOutBy, LockedOutFor, and LockedOutDate. I am having trouble creating a method within my view-model to allow the user to input these three items and once they hit 'ok', it will save the three items. Sorry if it is vague or if there is not enough info, please let me know if there is anything else needed.
Thank you.
View
<TextBlock VerticalAlignment="Center" Margin="5,5" Grid.Column="0" Grid.Row="1" Text="Locked Out By:"/>
<TextBox Grid.Column="1" Grid.Row="1" Text="{Binding LockedOutBy, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock VerticalAlignment="Center" Margin="5,5" Grid.Column="0" Grid.Row="2" Text="Locked Out For:"/>
<TextBox Grid.Column="1" Grid.Row="2" Text="{Binding LockedOutFor, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock VerticalAlignment="Center" Margin="5,5" Grid.Column="0" Grid.Row="3" Text="Locked Out Date:"/>
<TextBox Grid.Column="1" Grid.Row="3" Text="{Binding LockedOutDate, UpdateSourceTrigger=PropertyChanged}"/>
<Button Command="{Binding Path=OKCommand}"
View-Model
This is what I have so far in my view-model.
private string _LockedOutFor;
public string LockedOutFor
{
get { return _LockedOutFor; }
set
{
_LockedOutFor = value;
OnPropertyChanged("OwnerName");
}
}
private string _LockedOutBy;
public string LockedOutBy
{
get { return _LockedOutBy; }
set
{
_LockedOutBy = value;
OnPropertyChanged("Street");
}
}
private int _LockedOutDate;
public int LockedOutDate
{
get { return _LockedOutDate; }
set
{
_LockedOutDate = value;
OnPropertyChanged("StreetOverflow");
}
}
public ICommand CancelCommand
{
get { return new RelayCommand(c => OnCancelLock()); }
}
public ICommand OKCommand
{
get { return new RelayCommand(c => OnOKLock()); }
}
protected void OnOKLock()
{
OnOK(LockedOutFor, LockedOutBy, LockedOutDate);
}
protected void OnCancelLock()
{
OnCancel();
}
ANotifyPropertyChanged - base implementation for all of our view models
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace SO60269403
{
public abstract class ANotifyPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void SetProperty<T>(ref T backingStore, T newValue, [CallerMemberName] string propertyName = "")
{
var areEqual = ReferenceEquals(backingStore, newValue);
if (areEqual)
return;
backingStore = newValue;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
LockedOutViewModel - our view model
namespace SO60269403
{
public class LockedOutViewModel : ANotifyPropertyChanged
{
private string lockedOutBy;
private string lockedOutFor;
private int lockedOutDate;
public string LockedOutBy { get => lockedOutBy; set => SetProperty(ref lockedOutBy, value); }
public string LockedOutFor { get => lockedOutFor; set => SetProperty(ref lockedOutFor, value); }
public int LockedOutDate { get => lockedOutDate; set => SetProperty(ref lockedOutDate, value); }
}
}
ACommand - base implementation for all of our commands
using System;
using System.Windows.Input;
namespace SO60269403
{
public abstract class ACommand : ICommand
{
public event EventHandler CanExecuteChanged;
public virtual bool CanExecute(object parameter) => true;
public abstract void Execute(object parameter);
}
}
SaveCommand - our save command
namespace SO60269403
{
public class SaveCommand : ACommand
{
public LockedOutViewModel LockedOutViewModel { get; set; }
public override void Execute(object parameter)
{
//TODO
}
}
}
MainWindow - a view to data-bind our view model and hook up our save command
<Window
x:Class="SO60269403.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SO60269403">
<Window.Resources>
<local:LockedOutViewModel
x:Key="LockedOutViewModel" />
</Window.Resources>
<Grid
DataContext="{StaticResource LockedOutViewModel}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0">Locked Out By</TextBlock>
<TextBlock
Grid.Row="1"
Grid.Column="0">Locked Out For</TextBlock>
<TextBlock
Grid.Row="2"
Grid.Column="0">Locked Out Date</TextBlock>
<TextBox
Grid.Row="0"
Grid.Column="1"
Text="{Binding LockedOutBy}" />
<TextBox
Grid.Row="1"
Grid.Column="1"
Text="{Binding LockedOutFor}" />
<TextBox
Grid.Row="2"
Grid.Column="1"
Text="{Binding LockedOutDate}" />
<StackPanel
Grid.Row="3"
Grid.Column="0"
Grid.ColumnSpan="2"
Orientation="Horizontal"
HorizontalAlignment="Right">
<StackPanel.Resources>
<Style
TargetType="Button">
<Setter
Property="Width"
Value="100" />
</Style>
</StackPanel.Resources>
<Button>Cancel</Button>
<Button>
<Button.Command>
<local:SaveCommand
LockedOutViewModel="{StaticResource LockedOutViewModel}" />
</Button.Command>
OK
</Button>
</StackPanel>
</Grid>
</Window>
if we put a breakpoint in SaveCommand.Execute then run the app, fill in some values and click the OK button, the debugger should break on our breakpoint and we can observe that the view model's properties match what we entered. this demonstrates that the data is in place ready to be saved.

How to update Datagrid using mvvm databinding

I have 3 text boxes and when user enter value in them and press save button then they should add the data they contain to the data grid.
Every thing works fine and binding to the textboxes and button is done well but i do not understand how to update datagrid using the value user entered in textboxes.
My full code is here :
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="1" Grid.Row="0" Text="{Binding TextName}" Height="20" Width="80" HorizontalAlignment="Center"></TextBox>
<TextBox Grid.Column="1" Grid.Row="1" Text="{Binding RollNumber}" Height="20" Width="80"></TextBox>
<TextBox Grid.Column="1" Grid.Row="2" Text="{Binding Class}" Height="20" Width="80"></TextBox>
<Label Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center">Name</Label>
<Label Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center">RollNumber</Label>
<Label Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center">Class</Label>
</Grid>
<Grid Grid.Row="1" >
<Button Width="80" Height="20" Command="{Binding SaveStudentRecord}"> Save</Button>
</Grid>
<Grid Grid.Row="2">
<DataGrid ItemsSource="{Binding DGrid}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding DgName}" Width="150"></DataGridTextColumn>
<DataGridTextColumn Header="Rollnumber" Binding="{Binding dgRollnumber}" Width="150"></DataGridTextColumn>
<DataGridTextColumn Header="Class" Binding="{Binding dgClass}" Width="150"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Grid>
</Window>
ViewModel is:
class ViewModel
{
private string textName;
private string rollNumber;
private string cclass;
private RelayCommand saveStudentRecord;
private Model editModel;
public string TextName
{
get { return textName; }
set
{
textName = value;
PropertyChangedEventArgs("TextName");
}
}
public string RollNumber
{
get { return rollNumber; }
set
{
rollNumber = value;
PropertyChangedEventArgs("RollNumber");
}
}
public string Class
{
get { return cclass; }
set
{
rollNumber = value;
PropertyChangedEventArgs("Class");
}
}
public bool canExecute { get; set; }
public Model EditModel
{
get
{
return editModel ;
}
set
{
editModel = value;
PropertyChangedEventArgs("EditModel");
}
}
public ViewModel()
{
canExecute = true;
}
public RelayCommand SaveStudentRecord
{
get { return saveStudentRecord = new RelayCommand(() => MyAction(), canExecute); }
}
private void MyAction()
{
string chck1 = TextName; //I see on debugging that TextName contains the text entered so how to add this text to Datagrid column
string chck2 = Class;
string chck3 = RollNumber;
// How to add this data to datagrid
MessageBox.Show("Hii");
}
public event PropertyChangedEventHandler PropertyChanged;
private void PropertyChangedEventArgs(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
What exactly i mean is how to bind the datagrid inside the MyAction() such that all the three textbox strings will be added to the respective columns ?
As others have suggested in comments I'm not sure what Dgrid represents, but I think a simple example should help:
This is just a window with a DataGrid, TextBox and a button. When you type something in the datagrid and press the button it adds the value to the datagrid. It's done MVVM, I hope this demonstrates the process.
(.NET 4.6 syntax. If it doesn't work change the observable collection and move the creation of it to the constructor)
MainView.xaml
<Window x:Class="WpfApplication4.MainView"
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"
mc:Ignorable="d"
Title="MainView" Height="350" Width="525">
<Grid>
<DataGrid HorizontalAlignment="Left" Height="207" Margin="103,46,0,0" VerticalAlignment="Top" Width="311" ItemsSource="{Binding Stuff}" AutoGenerateColumns="false">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding}"/>
</DataGrid.Columns>
</DataGrid>
<TextBox HorizontalAlignment="Left" Height="20" Margin="167,9,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="179" Text="{Binding TextValue, Mode=TwoWay}"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="351,8,0,0" VerticalAlignment="Top" Width="75" Command="{Binding GoCommand}"/>
</Grid>
</Window>
MainViewModel.cs
using System.Collections.ObjectModel;
using System.Windows.Input;
namespace WpfApplication4
{
public class MainViewModel
{
public ObservableCollection<string> Stuff { get; set; } = new ObservableCollection<string>();
public ICommand GoCommand { get; set; }
public string TextValue { get; set; }
public MainViewModel()
{
Stuff.Add("a");
Stuff.Add("b");
Stuff.Add("c");
Stuff.Add("d");
GoCommand = new RelayCommand((p) => Stuff.Add(TextValue));
}
}
}
MainView.xaml.cs
using System.Windows;
namespace WpfApplication4
{
public partial class MainView : Window
{
public MainView()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
}
RelayCommand.cs
using System;
using System.Diagnostics;
using System.Windows.Input;
namespace WpfApplication4
{
public class RelayCommand : ICommand
{
private readonly Action<object> execute;
private readonly Predicate<object> canExecute;
public RelayCommand(Action<object> execute) : this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null) throw new ArgumentNullException("execute");
this.execute = execute;
this.canExecute = canExecute;
}
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return canExecute == null || canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
execute(parameter);
}
}
}

How to share data between ViewModel class and ICommand classes using MVVM in WPF application?

I am writing a WPF application and trying to teach myself the MVVM pattern. I am using the instructions located on Samuel Jack's site:
http://blog.functionalfun.net/2008/09/hooking-up-commands-to-events-in-wpf.html
I have bound my commands to the buttons and hooked everything up. The command classes are inner classes of the ViewModel class, which implement ICommand. The complex part is when the commands that run from my buttons need to access data on my view. Since C# inner classes can not access members of the outer class, I find myself having to declare public static variables in the ViewModel calss just to get data over to the inner classes. This seems to be a hackish and inelegant solution. Does anyone have a better way to do this?
My ViewModel code:
public class ApplicationViewModel
{
public ObservableCollection<App> AppCollection { get; set; }
static string searchString;
static string emailString;
public App SelectedApp { get; set; }
public string AppToSearch
{
get
{
return searchString;
}
set
{
searchString = value;
}
}
public string AppToRequest
{
get
{
get emailString;
}
set
{
// set static email String here
}
}
private SearchButtonCommand searchButtonCmd;
private ClearButtonCommand clearButtonCmd;
private EmailButtonCommand emailButtonCmd;
public ApplicationViewModel()
{
this.AppCollection = ApplicationsModel.Current;
}
public ICommand SearchButtonPressed
{
get
{
if (this.searchButtonCmd == null)
{
this.searchButtonCmd = new SearchButtonCommand();
}
return this.searchButtonCmd;
}
}
public ICommand ClearButtonPressed
{
get
{
if (this.clearButtonCmd == null)
{
this.clearButtonCmd = new ClearButtonCommand();
}
return this.clearButtonCmd;
}
}
public ICommand EmailButtonPressed
{
get
{
if (this.emailButtonCmd == null)
{
this.emailButtonCmd = new EmailButtonCommand();
}
return this.emailButtonCmd;
}
}
private class SearchButtonCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
string searchkey = ApplicationViewModel.searchString;
ApplicationsModel.Current.Search(searchkey);
}
public bool CanExecute(object parameter)
{
return true;
}
}
private class ClearButtonCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
ApplicationsModel.Current.ClearSearch();
}
public bool CanExecute(object parameter)
{
return true;
}
}
private class EmailButtonCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
string targetEmail = ApplicationViewModel.emailString;
}
public bool CanExecute(object parameter)
{
return true;
}
}
}
My XAML:
<Window.DataContext>
<vm:ApplicationViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Row="0" Height="84" HorizontalAlignment="Left" Margin="0,5,5,5" Name="imgLogo" Stretch="Fill" VerticalAlignment="Top" Width="600" Source="C:\Images\bannerlong.png" />
<Grid Grid.Row="1" HorizontalAlignment="Center" Margin="0,5,5,5" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Search for Application">
<Label.Foreground>
<SolidColorBrush Color="LightCyan" />
</Label.Foreground>
</Label>
<TextBox Grid.Row="0" Grid.Column="1" Margin="3" Width="500" Text="{Binding AppToSearch}" />
<Button Grid.Row="0" Grid.Column="2" HorizontalAlignment="Right" Width="100" Height="20" Margin="3" Background="LightCyan" Content="Search" vm:ButtonBehaviour.SearchCommand="{Binding SearchButtonPressed}" />
<Button Grid.Row="0" Grid.Column="3" HorizontalAlignment="Right" Width="100" Height="20" Margin="3" Background="LightCyan" Content="Clear Search" vm:ButtonBehaviour.ClearCommand="{Binding ClearButtonPressed}"/>
</Grid>
<ListView Grid.Row="2" BorderBrush="Black" HorizontalAlignment="Stretch" ItemsSource="{Binding Path=AppCollection}" SelectedItem="{Binding SelectedApp}">
<ListView.View>
<GridView>
<GridViewColumn Header="Application Name" Width="100" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Application Description" Width="800" DisplayMemberBinding="{Binding Description}"/>
<GridViewColumn Header="Application Owner" Width="100" DisplayMemberBinding="{Binding Owner}"/>
</GridView>
</ListView.View>
</ListView>
<Button Grid.Row="3" HorizontalAlignment="Center" Width="200" Height="30" Margin="3" Background="LightCyan" Content="Request Application" vm:ButtonBehaviour.EmailCommand="{Binding EmailButtonPressed}" />
</Grid>
Thanks a lot!
You can define a RelayCommand class that allows you to invoke delegates. With this approach, you don't need to declare a class for each Command.
public class RelayCommand : ICommand
{
#region Miembros
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion
#region Constructor
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
_execute = execute;
_canExecute = canExecute;
}
#endregion
#region Miembros de ICommand
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion
}
Then your ViewModel class will be something like:
public class ApplicationViewModel
{
public ObservableCollection<App> AppCollection { get; set; }
private string searchString;
private string emailString;
public App SelectedApp { get; set; }
public string AppToSearch
{
get
{
return searchString;
}
set
{
searchString = value;
}
}
public string AppToRequest
{
get
{
return emailString;
}
set { emailString = value; }
}
private ICommand searchButtonCmd;
private ICommand clearButtonCmd;
private ICommand emailButtonCmd;
public ApplicationViewModel()
{
this.AppCollection = ApplicationsModel.Current;
}
public ICommand SearchButtonPressed
{
get
{
if (this.searchButtonCmd == null)
{
this.searchButtonCmd = new RelayCommand(SearchButtonPressedExecute, c=>CanSearch);
}
return this.searchButtonCmd;
}
}
private void SearchButtonPressedExecute(object parameter)
{
ApplicationsModel.Current.Search(searchString);
}
public bool CanSearch
{
get { return true; }
}
// TODO: You can figure out the rest of the code
}
Don't forget update your Button's XAML like:
<Button Grid.Row="0" Grid.Column="2" HorizontalAlignment="Right" Width="100" Height="20" Margin="3" Background="LightCyan" Content="Search" Command="{Binding SearchButtonPressed}" />
And the same for the other buttons.
Hope this helps!
You can have a delegate or event in your viewmodel that your command classes use to get the data
.. or you can pass data from the view to the command via command parameter.
Button Command="{Binding SaveCommand}"
CommandParameter="{Binding SelectedItem, Element=listBox}" />

Categories