WPF DataGrid calculations - c#

I am very new to WPF and C# so please help to solve this problem.
I have a DataGrid, columns as follows: "One", "Two", "Multiply".
The idea that I am entering number "One" or "Two" and get result in the column "Multiply".
When I write my code and debug it, I can see that the value of the property is being re-calculated. However, I would not display in my last column unless I push space bar, or click on my last column.
Here is the code:
public class Numbers : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private double _one;
private double _two;
private double _multiply;
public double One
{
get { return _one; }
set { _one = value; UpdateValue(); }
}
public double Two
{
get { return _two; }
set { _two = value; UpdateValue(); }
}
public double Multiply
{
get { return _multiply; }
set { _multiply = value; UpdateValue(); }
}
public Numbers(double pOne, double pTwo)
{
_one = pOne;
_two = pTwo;
_multiply = GetMultiply();
}
private void UpdateValue()
{
OnPropertyChanged("One");
OnPropertyChanged("Two");
OnPropertyChanged("Multiply");
_multiply = GetMultiply();
}
private double GetMultiply()
{
return _one * _two;
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
public class Collection : ObservableCollection<Numbers>
{
public ObservableCollection<Numbers> Numbers { get; set; }
public Collection()
{
Numbers = new ObservableCollection<Numbers>();
Numbers.Add(new Numbers(1, 2));
Numbers.Add(new Numbers(2, 2));
}
}
XAML:
<DataGrid x:Name="StockData" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" ItemsSource="{Binding}" AutoGenerateColumns="False" LostFocus="StockData_LostFocus" >
<DataGrid.Columns >
<DataGridTextColumn Header="Number One" Width="100" Binding="{Binding One, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat=\{0:C\}}" />
<DataGridTextColumn Header="Number Two" Width="100" Binding="{Binding Two, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat=\{0:C\}}" />
<DataGridTextColumn Header="Total" Width="100" Binding="{Binding Multiply, BindsDirectlyToSource=True, Mode=TwoWay, StringFormat=\{0:C\}, UpdateSourceTrigger=PropertyChanged}" />
</DataGrid.Columns>
</DataGrid>

You are setting multiply after raising PropertyChanged event, so UI won't get notification that value has been changed.
Set Multiply and then raise PropertyChanged event:
private void UpdateValue()
{
_multiply = GetMultiply();
OnPropertyChanged("One");
OnPropertyChanged("Two");
OnPropertyChanged("Multiply");
}

Related

Update Cell value From another Cell value in datagrid

I want to Update a cell value according to another cell in datagrid.
for example i have a quantity column and a total price column
when i change the quantity i trigger a CellEditEnding event, which takes the quantity and do some logic operation and save it in the totalpricecolumn of the row itself.
after that, the totalprice not changing, only after i click the totalprice cell for editing mode, than i see the result.
my question is: how can see the result right after the CellEditEnding completes?
here's my xaml:
<DataGrid Name="itemsInSheet" CanUserAddRows="False" PreviewTextInput="PreviewQuantityChanged" CellEditEnding="itemsInSheet_CellEditEnding" ItemsSource="{Binding ItemsInPricingSheet , Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="1" Panel.ZIndex="-1" HorizontalAlignment="Center" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="סה''כ מחיר" Binding="{Binding TotalPrice, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Header="כמות" Binding="{Binding Quantity, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Header="שם פריט" IsReadOnly="True" Binding="{Binding ItemID, Mode=TwoWay, Converter={StaticResource ItemIDToItemName}}"/>
<DataGridTextColumn Header="שם קבוצה" IsReadOnly="True" Binding="{Binding GroupID, Mode=TwoWay, Converter={StaticResource GroupIDToGroupName}}"/>
</DataGrid.Columns>
</DataGrid>
Here's my CellEditEnding event:
private void itemsInSheet_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
if (e.EditAction == DataGridEditAction.Commit)
{
var column = e.Column as DataGridBoundColumn;
if (column != null)
{
var bindingPath = (column.Binding as Binding).Path.Path;
if (bindingPath == "Quantity")
{
int rowIndex = e.Row.GetIndex();
var el = e.EditingElement as TextBox;
m_engine.UpdateTotalPrice(rowIndex);
}
}
}
}
And here's the UpdateTotalPrice (for now i keep it simple and the total price equal to the Quantity):
internal void UpdateTotalPrice(int rowIndex)
{
sp_GetItemsInPricingSheets_Result data = m_PricingSheetManagerViewModel.ItemsInPricingSheet.ElementAt(rowIndex);
data.TotalPrice = (decimal)data.Quantity;
}
ADDITIONAL INFO:
here's the viewmodel i'm using:
public class PricingSheetManagerViewModel : INotifyPropertyChanged
{
private ObservableCollection<sp_GetGroups_Result> m_groups;
public ObservableCollection<sp_GetGroups_Result> Groups
{
get { return m_groups; }
set
{
m_groups = value;
NotifyPropertyChanged("Groups");
}
}
private ObservableCollection<sp_GetItems_Result> m_items;
public ObservableCollection<sp_GetItems_Result> Items
{
get { return m_items; }
set
{
m_items = value;
NotifyPropertyChanged("Items");
}
}
private ObservableCollection<sp_GetItemsInPricingSheets_Result> m_itemsInPricingSheet;
public ObservableCollection<sp_GetItemsInPricingSheets_Result> ItemsInPricingSheet
{
get { return m_itemsInPricingSheet; }
set
{
m_itemsInPricingSheet = value;
NotifyPropertyChanged("ItemsInPricingSheet");
}
}
private sp_GetPricingSheets_Result m_pricingSheet = new sp_GetPricingSheets_Result();
public sp_GetPricingSheets_Result PricingSheet
{
get { return m_pricingSheet; }
set
{
m_pricingSheet = value;
NotifyPropertyChanged("PricingSheet");
}
}
#region "PropertyChanged Event"
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
I managed to see the item after i update it by focus the data grid, set the current cell to the required cell, and set begin edit
this i added inside the itemsInSheet_CellEditEnding event
here's the code after update:
private void itemsInSheet_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
if (e.EditAction == DataGridEditAction.Commit)
{
var column = e.Column as DataGridBoundColumn;
if (column != null)
{
var bindingPath = (column.Binding as Binding).Path.Path;
if (bindingPath == "Quantity")
{
int rowIndex = e.Row.GetIndex();
var el = e.EditingElement as TextBox;
m_engine.UpdateTotalPrice(rowIndex);
itemsInSheet.Focus();
itemsInSheet.CurrentCell = new DataGridCellInfo(itemsInSheet.Items[rowIndex], itemsInSheet.Columns[0]);
itemsInSheet.BeginEdit();
}
}
}
}

when click dataGridview column Visiblity change of a textbox in WPF-MVVM?

I want to make a text Box Visible when clicking a DataGrid Column. I use this text box for description of a data Grid column
My two column has grid view (Item and Amount columns)
<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Item" Width="*">
<DataGridTemplateColumn.CellTemplate>
<TextBlock Text="{Binding Item}" VerticalAlignment="Center"/>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Amount" Width="*">
<DataGridTemplateColumn.CellTemplate>
<TextBlock Text="{Binding Amount}" VerticalAlignment="Center"/>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
I want get the sum of Column [Amount] and show it on a textbox, that is visible only when I click [Amount] Column
Please try the next code:
1. Xaml:
<Window x:Class="DataGridSoHelpAttempt.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dataGridSoHelpAttempt="clr-namespace:DataGridSoHelpAttempt"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Title="MainWindow" Height="350" Width="525" x:Name="This">
<Window.DataContext>
<dataGridSoHelpAttempt:MainViewModel/>
</Window.DataContext>
<Grid x:Name="MyGrid">
<DataGrid x:Name="MyDataGrid" ItemsSource="{Binding DataSource}" AutoGenerateColumns="False">
<i:Interaction.Behaviors>
<dataGridSoHelpAttempt:ColumnSelectingBehavior TotalPresenterVisibility="{Binding TotalsVisibility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</i:Interaction.Behaviors>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridTextColumn Header="Comments" Binding="{Binding Comments}" Width="150"/>
<DataGridTextColumn Header="Price (click to see total)" Binding="{Binding Price, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Bottom">
<TextBlock Visibility="{Binding TotalsVisibility, UpdateSourceTrigger=PropertyChanged}">
<Run Text="Total price:"></Run>
<Run Text="{Binding TotalValue, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"></Run>
</TextBlock>
</StackPanel>
</Grid></Window>
2. View models and models code:
public class MainViewModel:BaseObservableObject
{
private Visibility _visibility;
private ICommand _command;
private Visibility _totalsVisibility;
private double _totalValue;
public MainViewModel()
{
Visibility = Visibility.Collapsed;
TotalsVisibility = Visibility.Collapsed;
DataSource = new ObservableCollection<BaseData>(new List<BaseData>
{
new BaseData {Name = "Uncle Vania", Description = "A.Chekhov, play", Comments = "worth reading", Price = 25},
new BaseData {Name = "Anna Karenine", Description = "L.Tolstoy, roman", Comments = "worth reading", Price = 35},
new BaseData {Name = "The Master and Margarita", Description = "M.Bulgakov, novel", Comments = "worth reading", Price = 56},
});
}
public ICommand Command
{
get
{
return _command ?? (_command = new RelayCommand(VisibilityChangingCommand));
}
}
private void VisibilityChangingCommand()
{
Visibility = Visibility == Visibility.Collapsed ? Visibility.Visible : Visibility.Collapsed;
}
public ObservableCollection<BaseData> DataSource { get; set; }
public Visibility Visibility
{
get { return _visibility; }
set
{
_visibility = value;
OnPropertyChanged();
}
}
public ObservableCollection<BaseData> ColumnCollection
{
get { return DataSource; }
}
public Visibility TotalsVisibility
{
get { return _totalsVisibility; }
set
{
_totalsVisibility = value;
OnPropertyChanged();
}
}
public double TotalValue
{
get { return ColumnCollection.Sum(x => x.Price); }
}
}
public class BaseData:BaseObservableObject
{
private string _name;
private string _description;
private string _comments;
private int _price;
public virtual string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
public virtual object Description
{
get { return _description; }
set
{
_description = (string) value;
OnPropertyChanged();
}
}
public string Comments
{
get { return _comments; }
set
{
_comments = value;
OnPropertyChanged();
}
}
public int Price
{
get { return _price; }
set
{
_price = value;
OnPropertyChanged();
}
}
}
3. Behavior code:
public class ColumnSelectingBehavior : Behavior<DataGrid>
{
public static readonly DependencyProperty TotalPresenterVisibilityProperty = DependencyProperty.Register(
"TotalPresenterVisibility", typeof (Visibility), typeof (ColumnSelectingBehavior), new PropertyMetadata(Visibility.Collapsed));
public Visibility TotalPresenterVisibility
{
get { return (Visibility) GetValue(TotalPresenterVisibilityProperty); }
set { SetValue(TotalPresenterVisibilityProperty, value); }
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Sorting += AssociatedObjectOnSorting;
}
private void AssociatedObjectOnSorting(object sender, DataGridSortingEventArgs dataGridSortingEventArgs)
{
var columnSortMemberPath = dataGridSortingEventArgs.Column.SortMemberPath;
if(columnSortMemberPath != "Price")
return;
TotalPresenterVisibility = TotalPresenterVisibility == Visibility.Visible
? Visibility.Collapsed
: Visibility.Visible;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.Sorting -= AssociatedObjectOnSorting;
}
}
4. BaseObservableObject code (for .net 4.5):
public class BaseObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser)
{
var propName = ((MemberExpression)raiser.Body).Member.Name;
OnPropertyChanged(propName);
}
protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(name);
return true;
}
return false;
}
}
I'll glad to help in case you will have problems wit the code. Regards.

Change the value in a cell in a datagrid (binding)

this is my issue.
When I select a single row and I click on the button, the cell must change value, but it doesn't change anything
This is XAML code.
<DataGrid
ItemsSource="{Binding Dati_Viaggio, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectDati_Viaggio, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
AutoGenerateColumns="False" HorizontalAlignment="Left" Height="119" Margin="10,10,0,0" VerticalAlignment="Top" Width="497">
<DataGrid.Columns>
<DataGridTextColumn x:Name="NumOrd" Binding="{Binding Path=NumOrd, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="NumOrd" Width="150" />
</DataGrid.Columns>
</DataGrid>
and this is c# code
Public ObservableCollection<Model_Ricerca_Dati_Viaggio> Dati_Viaggio
{ get; set; }
private Model_Ricerca_Dati_Viaggio _SelectDati_Viaggio;
public Model_Ricerca_Dati_Viaggio SelectDati_Viaggio {
get { return _SelectDati_Viaggio; }
set {
_SelectDati_Viaggio = value;
OnPropertyChanged("SelectDati_Viaggio");}}
private string _NumOrd { get; set; }
public string NumOrd {
get { return _NumOrd; }
set {
_NumOrd = value;
OnPropertyChanged("NumOrd");}}
Private void Cmd_TrovaExe()
{
SelectDati_Viaggio.NumOrd = Now.#string;
OnPropertyChanged("NumOrd");
OnPropertyChanged("Dati_Viaggio");
OnPropertyChanged("SelectDati_Viaggio");
}
Why the cell doesn't refres after SelectDati_Viaggio.NumOrd = Now.#string; ?
Your class Model_Ricerca_Dati_Viaggio must as well implements the INotifyChangedinterface in order to the changed to be exposed to the UI :
public class Model_Ricerca_Dati_Viaggio:INotifyPropertyChanged
{
private string _numOrd ;
public string NumOrd
{
get
{
return _numOrd;
}
set
{
if (_numOrd == value)
{
return;
}
_numOrd = value;
OnPropertyChanged("NumOrd");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}

WPF DataGrid Column Total MVVM Patern

I have one column in my DataGrid that is a Price field.
In a TextBlock at the bottom of my form.
How to show the total value in the TextBlock based on the values of the Price column?
XAML-code:
<Grid>
<DataGrid HorizontalAlignment="Left" ItemsSource="{Binding Path=SaleryDetailsCollection, Mode=TwoWay}" AutoGenerateColumns="False" VerticalAlignment="Top" Width="640" Height="192" >
<DataGrid.Columns>
<DataGridTextColumn Header="Type" Binding="{Binding Type, Mode=TwoWay, NotifyOnTargetUpdated=True, ValidatesOnDataErrors=True}" Width="*" />
<DataGridTextColumn Header="Amount" Binding="{Binding Price, Mode=TwoWay, NotifyOnTargetUpdated=True, ValidatesOnDataErrors=True}" Width="*" />
</DataGrid.Columns>
</DataGrid>
<TextBlock HorizontalAlignment="Left" Margin="415,358,0,0" TextWrapping="Wrap" Text="{Binding SalaryTotal}" VerticalAlignment="Top"/>
</Grid>
ViewModel:
public ObservableCollection<SaleryDetailsModel> SaleryDetailsCollection
{
get { return _SaleryDetailsCollection; }
set
{
SalaryTotal = SaleryDetailsCollection.Sum(x => x.Amount);
_SaleryDetailsCollection = value;
NotifyPropertyChanged("SaleryDetailsCollection");
}
}
public Double SalaryTotal
{
get { return _SalaryTotal; }
set
{
_SalaryTotal = value;
NotifyPropertyChanged("SalaryTotal");
}
}
Class SaleryDetailsMode
class SaleryDetailsModel:ViewModel
{
private Double _Amount;
private String _Type;
public Double Amount
{
get { return _Amount; }
set
{
_Amount = value;
NotifyPropertyChanged("Amount");
}
}
public String Type { get { return _Type; } set { _Type = value; NotifyPropertyChanged("Type"); } }
}
Class ViewModel
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Add this code inside the Constructor
SaleryDetailsCollection = new ObservableCollection<SaleryDetailsModel>();
SaleryDetailsCollection.CollectionChanged += MyItemsSource_CollectionChanged;
In ViewModel
void MyItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
foreach (SaleryDetailsModel item in e.NewItems)
item.PropertyChanged += MyType_PropertyChanged;
if (e.OldItems != null)
foreach (SaleryDetailsModel item in e.OldItems)
item.PropertyChanged -= MyType_PropertyChanged;
}
void MyType_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Amount")
DoWork();
}
private void DoWork()
{
SalaryTotal = SaleryDetailsCollection.Sum(x => x.Amount);
}
XAML
<Grid>
<DataGrid HorizontalAlignment="Left" ItemsSource="{Binding Path=SaleryDetailsCollection, Mode=TwoWay}" AutoGenerateColumns="False" VerticalAlignment="Top" Width="640" Height="192" >
<DataGrid.Columns>
<DataGridTextColumn Header="Type" Binding="{Binding Type, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Width="*" />
<DataGridTextColumn Header="Amount" Binding="{Binding Price, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Width="*" />
</DataGrid.Columns>
</DataGrid>
<TextBlock HorizontalAlignment="Left" Margin="415,358,0,0" TextWrapping="Wrap" Text="{Binding SalaryTotal}" VerticalAlignment="Top"/>
The calculation must be done after the field assignment:
public ObservableCollection<SaleryDetailsModel> SaleryDetailsCollection
{
get { return _SaleryDetailsCollection; }
set
{
_SaleryDetailsCollection = value;
SalaryTotal = SaleryDetailsCollection.Sum(x => x.Amount); // This line must be after the field assignment.
NotifyPropertyChanged("SaleryDetailsCollection");
}
}
You need to use a collection which will get notification when its property getting changed. Refer the link https://social.msdn.microsoft.com/Forums/silverlight/en-US/12915e07-be95-4fc5-b8f0-b0a49b10bc57/observablecollection-item-changed. It has NotifyableCollection. I have used it for the below code.
<Grid>
<StackPanel>
<DataGrid x:Name="dgr" HorizontalAlignment="Left" ItemsSource="{Binding Path=Salaries, Mode=TwoWay}"
AutoGenerateColumns="True" VerticalAlignment="Top" Width="640" Height="192" >
</DataGrid>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Text="{Binding TotalSalary}">
</TextBlock>
</StackPanel>
</Grid>
class ViewModel : INotifyPropertyChanged
{
private NotifiableCollection<Salary> salaries;
double _totalSal;
public double TotalSalary
{
get { return _totalSal = Salaries.Sum(x => x.Amount); }
set { _totalSal = value; }
}
public NotifiableCollection<Salary> Salaries
{
get { return salaries; }
set
{
salaries = value;
if (salaries != null)
{
salaries.ItemChanged += salaries_ItemChanged;
}
}
}
void salaries_ItemChanged(object sender, NotifyCollectionChangeEventArgs e)
{
OnPropertyChanged("TotalSalary");
}
public ViewModel()
{
Salaries = new NotifiableCollection<Salary>();
for (int i = 0; i < 10; i++)
{
Salary s = new Salary() { Type="Type"+i,Amount=new Random().Next(20000,30000)};
Salaries.Add(s);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
class Salary : INotifyPropertyChanged
{
private string type;
public string Type
{
get { return type; }
set { type = value; OnPropertyChanged("Type"); }
}
private double amount;
public double Amount
{
get { return amount; }
set { amount = value; OnPropertyChanged("Amount"); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
public class NotifyCollectionChangeEventArgs : PropertyChangedEventArgs
{
public int Index { get; set; }
public NotifyCollectionChangeEventArgs(int index, string propertyName) : base(propertyName) { Index = index; }
}
public class NotifiableCollection<T> : ObservableCollection<T> where T : class, INotifyPropertyChanged
{
public event EventHandler<NotifyCollectionChangeEventArgs> ItemChanged;
protected override void ClearItems()
{
foreach (var item in this.Items)
item.PropertyChanged -= ItemPropertyChanged;
base.ClearItems();
}
protected override void SetItem(int index, T item)
{
this.Items[index].PropertyChanged -= ItemPropertyChanged;
base.SetItem(index, item);
this.Items[index].PropertyChanged += ItemPropertyChanged;
}
protected override void RemoveItem(int index)
{
this.Items[index].PropertyChanged -= ItemPropertyChanged;
base.RemoveItem(index);
}
protected override void InsertItem(int index, T item)
{
base.InsertItem(index, item);
item.PropertyChanged += ItemPropertyChanged;
}
private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
T changedItem = sender as T;
OnItemChanged(this.IndexOf(changedItem), e.PropertyName);
}
private void OnItemChanged(int index, string propertyName)
{
if (ItemChanged != null)
this.ItemChanged(this, new NotifyCollectionChangeEventArgs(index, propertyName));
}
}

Remove row from DataGridView in WPF

run into a problem, i have a datagrid, columns as follow
One, Two, Multiply
i can delete row buy clicking del KEY on the keyboard but when im trying to program my own remove function it does not work
and the message im getting is
An unhandled exception of type 'System.InvalidOperationException' occurred in PresentationFramework.dll
Additional information: Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead.
Here is my code:
private void buttonRemove_Click(object sender, RoutedEventArgs e)
{
NumberData.Items.Remove(NumberData.SelectedItems);
}
public class Numbers : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private double? _one;
private double? _two;
private double? _multiply;
public double? One { get { return _one; } set { _one = value; UpdateValue(); } }
public double? Two { get { return _two; } set { _two = value; UpdateValue(); } }
public double? Multiply
{
get { return _multiply; }
set
{
_multiply = value; UpdateValue();
}
}
public Numbers(double? pOne, double? pTwo)
{
_one = pOne;
_two = pTwo;
_multiply = GetMultiply();
}
private void UpdateValue()
{
_multiply = GetMultiply();
OnPropertyChanged("One");
OnPropertyChanged("Two");
OnPropertyChanged("Multiply");
}
private double? GetMultiply()
{
return _one * _two;
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
public class Collection : ObservableCollection<Numbers>
{
public ObservableCollection<Numbers> Numbers { get; set; }
public Collection()
{
Numbers = new ObservableCollection<Numbers>();
//Numbers.Add(new Numbers(1, 2));
//Numbers.Add(new Numbers(2, 2));
}
public void AddNumbers(double pOne, double pTwo)
{
Numbers.Add(new Numbers(pOne,pTwo));
}
public void AddNumbersRow()
{
Numbers.Add(new Numbers(null, null));
}
}
<Grid>
<DataGrid x:Name="NumberData" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" ItemsSource="{Binding}" AutoGenerateColumns="False" LostFocus="StockData_LostFocus" >
<DataGrid.Columns >
<DataGridTextColumn Header="Number One" Width="100" Binding="{Binding One, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat=\{0:C\}}" />
<DataGridTextColumn Header="Number Two" Width="100" Binding="{Binding Two, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat=\{0:C\}}" />
<DataGridTextColumn Header="Total" Width="100" Binding="{Binding Multiply, BindsDirectlyToSource=True, Mode=TwoWay, StringFormat=\{0:C\}, UpdateSourceTrigger=PropertyChanged}" />
</DataGrid.Columns>
</DataGrid>
<Button x:Name="buttonSave" Content="Save" HorizontalAlignment="Left" Margin="411,11,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
<Button x:Name="buttonAddRow" Content="Add Row" HorizontalAlignment="Left" Margin="411,49,0,0" VerticalAlignment="Top" Width="75" Click="buttonAddRow_Click"/>
<Button x:Name="buttonRemove" Content="Remove" HorizontalAlignment="Left" Margin="411,88,0,0" VerticalAlignment="Top" Width="75" Click="buttonRemove_Click"/>
</Grid>
It looks like you have everything set up right, with a single oddity:
<DataGrid ItemsSource="{Binding}">
Not sure why the ItemsSource is the DataContext. The DataContext should be a View Model class with some ObservableCollection property that you then bind to.
But beyond that, since you said your code was working; you shouldn't be deleting items manually like that.
Your button should be bound to a command, that goes to the view model and modifies the bound collection. A sample would look like:
myObservableCollection.RemoveAt(0);
Since its an ObservableCollection, the modification will propagate to the UI.
Thanks a lot, i got the idea from your answers , here is what i have done to remove the item
if (NumberData.SelectedIndex == -1)
{
System.Windows.MessageBox.Show("nothing selected");
}
else
{
int indexSelected = Convert.ToInt32(NumberData.SelectedIndex);
mycollection.Numbers.RemoveAt(indexSelected);
}

Categories