Reputation: 11206
I'm running into a small problem where I'm trying to bind a DataTextColumn of a DataGrid to a Calculated Field.
WPF
<DataGrid ItemsSource="{Binding Path=CurrentRoster, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
AutoGenerateColumns="False"
AlternatingRowBackground="Gainsboro"
AlternationCount="2">
<DataGrid.Columns>
<DataGridComboBoxColumn Header="Student Enrolled"
ItemsSource="{Binding Source={StaticResource AvailableStudents}}"
SelectedItemBinding="{Binding Path=Student}">
</DataGridComboBoxColumn>
<DataGridTextColumn Header="Registration" Binding="{Binding Path=RegistrationCosts, StringFormat='{}{0:C}'}"/>
<DataGridTextColumn Header="Lodging" Binding="{Binding Path=LodgingCosts, StringFormat='{}{0:C}'}"/>
<DataGridTextColumn Header="Travel" Binding="{Binding Path=TravelCosts, StringFormat='{}{0:C}'}"/>
<DataGridTextColumn Header="Dining" Binding="{Binding Path=DiningCosts, StringFormat='{}{0:C}'}"/>
<DataGridTextColumn Header="Total Costs" IsReadOnly="True" Binding="{Binding Path=TotalCosts, StringFormat='{}{0:C}'}"/>
</DataGrid.Columns>
Where Student is a Entity object with one small addition. TotalCosts isn't a field on the db tables, so I created a partial class for this.
public partial class Student
{
public Decimal TotalCosts
{
get { return (LodgingCosts + RegistrationCosts + TravelCosts + DiningCosts); }
}
}
The problem I'm experiencing is that TotalCosts is not automatically updating when you fill in any of the other fields. My guess it is because it is not listed as a dependency property. How do I resolve this for a property where there is no set ?
Upvotes: 4
Views: 6350
Reputation: 11
Just change the DataSourceUpdateMode
to OnPropertyChanged
when you create DataBinding
to the TotalCosts
property.
Upvotes: 1
Reputation: 31
Hello o think i can help you i have this code for a data base in sqlServer and i have a Data source with a DataSet for my Data Base
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using TestDeDataGrid.TestDSTableAdapters;
namespace TestDeDataGrid
{
public partial class MainWindow : Window
{
//private ICollection<TablaTest> registros;
public MainWindow()
{
InitializeComponent();
TestDS ds = new TestDS();
TablaTestTableAdapter adapter = new TablaTestTableAdapter();
adapter.Fill(ds.TablaTest);
TablaTestGrid.ItemsSource = ds.TablaTest.DefaultView;
}
private void TablaTestGrid_CurrentCellChanged(object sender, EventArgs e)
{
if ((String)(((DataGrid)sender).CurrentColumn.Header) == "A/B")
((DataGrid)sender).CommitEdit(DataGridEditingUnit.Row, true);
}
}
}
With this trick the column C is calculated automatically after i have a value in columns A and B for example if i put 10 in columna A and 5 in column B then i just press Tab Key to move to the columnC and the value 2 appears automatically no need to click other row or press enter.
ColumnC is a calculated column whit the expression (ColumnaA/ColumnaB) and of type System.Decimal.
And there is my xaml code:
<DataGrid Name="TablaTestGrid" Grid.Row="1" AutoGenerateColumns="False"
CurrentCellChanged="TablaTestGrid_CurrentCellChanged">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding Path=IdTablaTest}" IsReadOnly="True"></DataGridTextColumn>
<DataGridTextColumn Header="Col A" Binding="{Binding Path=ColumnaA}"></DataGridTextColumn>
<DataGridTextColumn Header="Col B" Binding="{Binding Path=ColumnaB}"></DataGridTextColumn>
<DataGridTextColumn Header="A/B" Binding="{Binding Path=ColumnaC}" IsReadOnly="True" ></DataGridTextColumn>
<DataGridTextColumn Header="TestOnly"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
Upvotes: 3
Reputation: 1542
You need to implement the INotifyPropertyChanged
on the class. Here is the Example:
public class Person : INotifyPropertyChanged
{
//public int Id
//{ get; set; }
//public string Name { get; set; }
private int _Id;
public int Id
{
get { return _Id; }
set { _Id = value;
RaisePropertyChanged("Id");
}
}
private string _EmpNo
{
get
{
return Id.ToString() + Name.ToString();
}
}
private string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
RaisePropertyChanged("Name");
}
}
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
public event PropertyChangedEventHandler PropertyChanged;
}
XAML code:
<DockPanel>
<TextBox Text="{Binding P1.Id}" Height="50" Width="100" DockPanel.Dock="Top" />
<TextBox Text="{Binding P1.Name}" Height="50" Width="100" DockPanel.Dock="Top" />
<Button Content="OK" Click="Button_Click" DockPanel.Dock="Bottom"/>
</DockPanel>
Test:
public TestWindow()
{
InitializeComponent();
this.DataContext = this;
}
private Person _P1 = new Person();
public Person P1
{
get { return _P1; }
set { _P1 = value; }
}
private void Button_Click(object sender, RoutedEventArgs e)
{
}
type something in the 2 textboxes..and on the Button click see the value of the person P1 ..u will find the calculated field with the value.. hope it helps u.. Thanks, BHavik
Upvotes: 0
Reputation: 292695
You can call OnPropertyChanged("TotalCosts")
in the setters of each property that TotalCosts
depends on, it will refresh the binding
Upvotes: 3
Reputation: 7601
I'm assuming Student implements INotifyPropertyChanged. what you have to do is to register to the PropertyChanged Event for LodgingCosts + RegistrationCosts + TravelCosts + DiningCosts, and raise the PropertyChanged event for TotalCosts.
public partial class Student
{
public Decimal TotalCosts
{
get { return (LodgingCosts + RegistrationCosts + TravelCosts + DiningCosts); }
}
public Student()
{
this.PropertyChanged += new PropertyChangedEventHandler(Student_PropertyChanged);
}
void Student_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "LodgingCosts" ||
e.PropertyName == "RegistrationCosts" ||
e.PropertyName == "TravelCosts" ||
e.PropertyName == "DiningCosts")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("TotalCosts"));
}
}
}
Upvotes: 4