I curretly have a View which is supposed to show data from two different Objects. Tod do so i created a view model which contains a list of an object type that contains the two different objects mentioned before. The two objects are Suppliers and Items. Items class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.Json.Serialization;
namespace MLaRealERP.Models
{
public class Insumo
{
[JsonPropertyName("Id")]
public int Id { get; set; }
[JsonPropertyName("proveedorId")]
public int ProveedorId { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("tipo")]
public string Tipo { get; set; }
[JsonPropertyName("unidad")]
public string Unidad { get; set; }
[JsonPropertyName("precio")]
public float Precio { get; set; }
}
}
Suppliers Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.Json.Serialization;
namespace MLaRealERP.Models
{
public class Proveedor
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("celular")]
public string Celular { get; set; }
public void NuevoProveedor(string n, string c)
{
Name = n;
Celular = c;
}
}
}
ViewModel
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MLaRealERP.Models;
namespace MLaRealERP.ViewModels
{
public class InsumosViewModel
{
public class InsumoVM
{
public Insumo insumo { get; set; }
public Proveedor proveedor { get; set; }
}
List<Insumo> repo;
List<Proveedor> proveedores;
public List<InsumoVM> insumos;
//IOrderedEnumerable<Proveedor> proveedores;
public InsumosViewModel()
{
repo = new List<Insumo>();
proveedores = new List<Proveedor>();
insumos = new List<InsumoVM>();
}
public async void InitializeViewModel()
{
repo = await Funciones.GetAll<Insumo>("insumos", App.client);
proveedores = await Funciones.GetAll<Proveedor>("proveedors", App.client);
proveedores = proveedores.OrderBy(p => p.Id).ToList();
//proveedores = repo.OrderBy(repo => repo.Id);
foreach(Insumo insumo in repo)
{
newInsumoVM(insumo);
}
}
private void newInsumoVM(Insumo ins)
{
InsumoVM insumoVM = new InsumoVM();
insumoVM.insumo = ins;
insumoVM.proveedor = proveedores[ins.ProveedorId - 1];
insumos.Add(insumoVM);
}
}
}
Data Grid Xaml
<Window x:Class="MLaRealERP.Views.InsumosView"
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:MLaRealERP.Views"
mc:Ignorable="d"
Title="InsumosView" Height="450" Width="800">
<DockPanel Margin="10">
<Canvas DockPanel.Dock="Top" Margin="0,0,0,20">
<TextBox Canvas.Left="10" Name="txtFilter" TextChanged="txtFilter_TextChanged" Width="171" />
<Button Canvas.Right="10" Name="btnAddInsumo" Click="btnAddInsumo_Click">Agregar Nuevo Producto</Button>
</Canvas>
<DataGrid ItemsSource="{Binding insumos}" Name="dgInsumos" Margin="10" ColumnWidth="*" CanUserAddRows="False" >
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Background" Value="LightBlue" />
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="BorderThickness" Value="0.5" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Id" Binding="{Binding insumos.insumo.Id}" />
<DataGridTextColumn Header="Nombre" Binding="{Binding insumos.insumo.Name}" />
<DataGridTextColumn Header="Tipo" Binding="{Binding insumos.insumo.Tipo}" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Window>
Datagrid cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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.Shapes;
using MLaRealERP.ViewModels;
namespace MLaRealERP.Views
{
/// <summary>
/// Interaction logic for InsumosView.xaml
/// </summary>
public partial class InsumosView : Window
{
InsumosViewModel insumos;
public InsumosView()
{
InitializeComponent();
insumos = new InsumosViewModel();
insumos.InitializeViewModel();
dgInsumos.DataContext = insumos;
}
//public async void LoadViewItems()
//{
// insumos.InitializeViewModel();
//}
private void txtFilter_TextChanged(object sender, TextChangedEventArgs e)
{
}
private void btnAddInsumo_Click(object sender, RoutedEventArgs e)
{
}
}
}
I want to show Isumos id
, name
, and tipo
along with proveedores name
.
EDIT: Current View.xaml for the grid
<Window x:Class="MLaRealERP.Views.InsumosView"
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:MLaRealERP.Views"
mc:Ignorable="d"
Title="InsumosView" Height="450" Width="800">
<DockPanel Margin="10">
<Canvas DockPanel.Dock="Top" Margin="0,0,0,20">
<TextBox Canvas.Left="10" Name="txtFilter" TextChanged="txtFilter_TextChanged" Width="171" />
<Button Canvas.Right="10" Name="btnAddInsumo" Click="btnAddInsumo_Click">Agregar Nuevo Producto</Button>
</Canvas>
<DataGrid ItemsSource="{Binding insumos}" DataContext="{Binding InsumoVM}" Name="dgInsumos" Margin="10" ColumnWidth="*" CanUserAddRows="False" >
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Background" Value="LightBlue" />
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="BorderThickness" Value="0.5" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Id" Binding="{Binding insumo.Id}" />
<DataGridTextColumn Header="Nombre" Binding="{Binding insumo.Name}" />
<DataGridTextColumn Header="Tipo" Binding="{Binding insumo.Tipo}" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Window>
CodePudding user response:
There are some issue with your code:
- Required Fix: You can only bind to public properties and not fields. This means
insumos
must be a public property. Additionally the binding source, in this case theInsumosViewModel
and theInsumoVM
classes, must implementINotifyPropertyChanged
(see Microsoft Docs for complete example) - even when you don't expect property changes.
InsumoVM.cs
public class InsumoVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Insumo Insumo { get; set; }
public Proveedor Proveedor { get; set; }
}
InsumosViewModel.cs
public class InsumosViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<InsumoVM> Insumos { get; }
private List<Insumo> Repo { get; set; }
private List<Proveedor> Proveedores { get; set; }
public InsumosViewModel()
{
this.Repo = new List<Insumo>();
this.Proveedores = new List<Proveedor>();
this.Insumos = new ObservableCollection<InsumoVM>();
}
public async Task InitializeViewModel()
{
this.Repo = await Funciones.GetAll<Insumo>("insumos", App.client);
this.Proveedores = (await Funciones.GetAll<Proveedor>("proveedors", App.client)).
OrderBy(p => p.Id)
.ToList();
this.Insumos.Clear();
foreach(Insumo insumo in this.Repo)
{
NewInsumoVM(insumo);
}
}
private void NewInsumoVM(Insumo ins)
{
InsumoVM insumoVM = new InsumoVM()
{
Insumo = ins,
Proveedor = proveedores[ins.ProveedorId - 1]
};
this.Insumos.Add(insumoVM);
}
}
- Required Fix: You must use the correct
Binding.Path
. The items are of typeInsumoVM
. ThereforeInsumoVM
is the type of theDataContext
of each column:
<DataGrid ItemsSource="{Binding Insumos}">
<DataGridTextColumn Header="Insumo Name"
Binding="{Binding Insumo.Name}" />
<DataGridTextColumn Header="Proveedor Name"
Binding="{Binding Proveedor.Name}" />
</DataGrid>
- Never return
void
from anasync
method (except this method is an event handler). Aasync
method must returnTask
orTask<T>
:
public async Task InitializeViewModel()
{}
Also when using MVVM you should not pass data directly to the view. For example, instead of passing a
List<Cliente>
to theClientesView
, let theClientesView
bind its controls likedgClients
to a property on theDataContext
/view model class.List<Cliente>
must be a property of the view model class.To filter data for
ItemsControl
like aDataGrid
use the collection view. Don't create a new collection that you assign to the ItemsSource for this purpose. It will become difficult to maintain very quick.
dgClientes.Items.Filter = item => (items as Cliente).Apellidos.ToLower().Contains(txtFilter.Text.ToLower());