Zhanwen Chen
Zhanwen Chen

Reputation: 1463

Add Calculated Columns to WPF DataGrid Default View from Entity Data Model

I'm a n00b to WPF and Entity Framework. I imported a Code First Model from Database and dragged the generated context into a DataGrid XAML element. I'd like to add an additional column to the default view, derived from simple calculations.

Currently it displays

date  | revenue | cost

12/01 | 200     | 100

12/20 | 300     | 90

Without modifying the MS SQL database, how can I add a column to the view so that datagrid displays a "profit" column that is revenue - cost?

date  | revenue | cost | profit

12/01 | 200     | 100  | 100

12/20 | 300     | 90   | 210

Here's my MainWindow.xaml:

<Window x:Class="VenmeWPF.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:VenmeWPF"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Window.Resources>
    <CollectionViewSource x:Key="venmeContextViewSource" d:DesignSource="{d:DesignInstance {x:Type local:VenmeContext}, CreateList=True}"/>
</Window.Resources>
<Grid DataContext="{StaticResource venmeContextViewSource}">
    <DataGrid x:Name="dataGrid" HorizontalAlignment="Left" Margin="56,79,0,0" VerticalAlignment="Top" Height="141" Width="424" ItemsSource="{Binding}"/>

</Grid>

Here's my MainWindow.xaml.cs:

public partial class MainWindow : Window
{
    private VenmeContext _venmeContext = new VenmeContext();
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {

        System.Windows.Data.CollectionViewSource venmeContextViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("venmeContextViewSource")));
        // Load data by setting the CollectionViewSource.Source property:
        _venmeContext.Transactions.Load();
        venmeContextViewSource.Source = _venmeContext.Transactions.Local;
    }
}

VenmeContext.cs from ADO.NET Entity Data Model:

public partial class VenmeContext : DbContext
{
    public VenmeContext()
        : base("name=VenmeContext")
    {
    }

    public virtual DbSet<C__MigrationHistory> C__MigrationHistory { get; set; }
    public virtual DbSet<Transaction> Transactions { get; set; }
    public virtual DbSet<User> Users { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .Property(e => e.name)
            .IsUnicode(false);

        modelBuilder.Entity<User>()
            .HasMany(e => e.Transactions)
            .WithRequired(e => e.User)
            .HasForeignKey(e => e.FromUserId);
    }
}

Transactions.cs also from ADO.NET Entity Data Model:

public partial class Transaction
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int id { get; set; }

    public DateTime date { get; set; }

    public int revenue { get; set; }

    public int cost { get; set; }
}

Upvotes: 1

Views: 849

Answers (1)

mm8
mm8

Reputation: 169160

Add a column in your XAML markup:

<DataGrid x:Name="dataGrid" HorizontalAlignment="Left" Margin="56,79,0,0" 
          VerticalAlignment="Top" Height="141" Width="424" ItemsSource="{Binding}">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding profit}" IsReadOnly="True" />
    </DataGrid.Columns>
</DataGrid>

...and create another partial class where you define the additional property:

public partial class Transaction
{
    public int profit
    {
        get
        {
            return revenue - cost;
        }
    }
}

Note that the partial class must be defined in the same namespace and assembly (project) as the auto-generated one: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/partial-classes-and-methods

Upvotes: 1

Related Questions