Using the MVVM pattern in a WPF application, I want to set on the 'Editing State' of a records in row.
Every time the user starts editing a record by clicking on Edit button, that row should switch to the 'editing' mode.
Finished, he can save all changes in the row by clicking the same or another button
How can I set edit mode (IsReadOnly=true/false) for All cells in selected Row on click "Edit" button?
Any help is appreciated!
This is my current code:
XAML
<Window x:Class="TotalRows.TotalRowsWindow"
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:TotalRows"
mc:Ignorable="d"
x:Name="xMainWindow"
Title="RowsTotalWindow" Height="450" Width="800">
<Window.DataContext>
<local:ExampleData/>
</Window.DataContext>
<Grid>
<StackPanel >
<DataGrid x:Name="myGrid" IsReadOnly="True" CanUserAddRows="False" SelectionMode="Single" CanUserDeleteRows="False"
ItemsSource="{Binding ItemsViewCollection}" RowDetailsVisibilityMode="Collapsed"
SelectedItem="{Binding SelectedItemRow, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DockPanel HorizontalAlignment="Stretch">
<ToggleButton x:Name="btnEditItem" Content="Edit" Width="50" Height="20" Margin="0 0 3 0"
Command="{Binding RelativeSource={RelativeSource AncestorType=DataGrid}, Path=DataContext.UpdateItemCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Path=DataContext}"/>
</DockPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn x:Name="gr" Binding="{Binding Group}" Header="Gr" Width="30" />
<DataGridTextColumn x:Name="one" Binding="{Binding Col_1}" Header="h1" Width="30" />
<DataGridTextColumn x:Name="two" Binding="{Binding Col_2}" Header="h2" Width="30" />
<DataGridTextColumn x:Name="tree" Binding="{Binding Col_3}" Header="h3" Width="30" />
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</Grid>
</Window>
Code Behind
namespace TotalRows
{
public class ItemClass
{
public int Group { get; set; }
public string Title { get; set; }
public int Col_1 { get; set; }
public int Col_2 { get; set; }
public int Col_3 { get; set; }
}
public class ExampleData
{
private bool _IsReadMode;
public bool IsReadMode
{
get { return _IsReadMode; }
set
{
_IsReadMode = value;
OnPropertyChanged(nameof(IsReadMode));
}
}
private ItemClass _selectedItem = null;
public ItemClass SelectedItemRow
{
get { return _selectedItem; }
set
{
_selectedItem = value;
OnPropertyChanged(nameof(SelectedItemRow));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private ObservableCollection<ItemClass> _items;
public ObservableCollection<ItemClass> Items
{
get
{
return _items;
}
set
{
if (_items != value)
{
_items = value;
OnPropertyChanged(nameof(Items));
}
}
}
private ICollectionView _itemsViewCollection;
public ICollectionView ItemsViewCollection
{
get
{
return _itemsViewCollection;
}
set
{
if (_itemsViewCollection != value)
{
_itemsViewCollection = value;
OnPropertyChanged(nameof(ItemsViewCollection));
}
}
}
public ICommand UpdateItemCommand { get; private set; }
public ExampleData()
{
IsReadMode = true;
UpdateItemCommand = new ViewModelCommand(param => updateItemCommand(param));
Items = new ObservableCollection<ItemClass>()
{
new ItemClass() {Group=1, Title="Item1", Col_1=100, Col_2=150, Col_3=250},
new ItemClass() {Group=2, Title="Item1", Col_1=50, Col_2=2, Col_3=200},
new ItemClass() {Group=2, Title="Item2", Col_1=50, Col_2=100, Col_3=40},
new ItemClass() {Group=3, Title="Item1", Col_1=60, Col_2=25, Col_3=230},
new ItemClass() {Group=3, Title="Item2", Col_1=30, Col_2=25, Col_3=0},
new ItemClass() {Group=3, Title="Item3", Col_1=9, Col_2=100, Col_3=20},
new ItemClass() {Group=4, Title="Item1", Col_1=46, Col_2=32, Col_3=30},
};
ItemsViewCollection = CollectionViewSource.GetDefaultView(Items);
ItemsViewCollection.GroupDescriptions.Add(new PropertyGroupDescription("Group"));
}
private void updateItemCommand(object param)
{
IsReadMode = !IsReadMode;
}
}
}
Do you realise f2 switches the current row into edit mode?
You could bind your edit button to a command in the ExampleData viewmodel and pass a reference to the specific ItemClass as a command parameter.
Use relativesource binding to get to that command.
ExampleData owns that collection so you can set properties on that instance and stash a reference or index to the last one they edited set the flag back. Or iterate through the whole collection.
Seems you know how to write a command but I recommend the community mvvm toolkit and relaycommand.
Your binding would be something like
The command parameter passes the row to an Icommand so will be a parameter passed to your command.
A similar command I happen to have.
You would of course have EditThisOneCommand
You then have to tell the UI to issue a BeginEditCommand.
And then you need to tell the UI to issue a CommitEditCommand when you finish.
These commands are source from the datagrid.
You could instead just bind those datagrid commands to buttons and not have this flag.
A datagridrow has a property IsEditing. You might be able to bind that onewaytosource to your flag. You'd set that binding via a style. Not sure why you'd want to, but you could take a look at that.
https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.datagridrow.isediting?view=windowsdesktop-7.0