简体   繁体   中英

Load DataTable to WPF DataGrid MVVM

I have been trying to move my project to MVVM for some time.

There is a DataTable I am getting from Database:

MainProcess.cs:

    public static DataTable CustomersInLiinos = new DataTable();

    public static void MergedTable()
    {
        var t1 = ConnectAndRetriveDatatatableS(); // t1
        var t2 = ConnectAndRetriveDatatatableF(); // t2

        CustomersInLiinos = t1.Copy();
        CustomersInLiinos.Merge(t2);
    }

ViewModel.cs:

    private async Task ExecuteLoadMainTableDataAsync(object commandParameter)
    {
        if (MainProcess.CheckForVPNInterface())
        {
            if (MainProcess.CustomersInLiinos != null)
            {
                this.HasProgress = true;

                IEnumerable<Item> resultItems = await LoadMainTableDataAsync();
                this.Items = new ObservableCollection<Item>(resultItems);
                EnableItemsFiltering();

                this.HasProgress = false;
            }
        }
        else
        {
            throw new VpnInterfaceException("Please, check your VPN connection!");
        }
    }

Inside ViewModel.cs I have also this:

    public Task<DataView> LoadMainTableDataAsync()
    {
        return Task.Run(() =>
        {
            MainProcess.MergedTable();

            return MainProcess.CustomersInLiinos.DefaultView;
        });
    }

Curently I am having an error pointing at await LoadMainTableDataAsync(); :

Severity Code Description Project File Line Suppression State Error CS0266 Cannot implicitly convert type 'System.Data.DataView' to 'System.Collections.Generic.IEnumerable<Liinos_inspector_FilterTest.Item>'. An explicit conversion exists (are you missing a cast?)

I understand that there is an error in LoadMainTableDataAsync ? I am loading data to DataView and should load to IEnumerable instead?

Would it be easier to utilize this:

    public class JoinedFandS
    {
       public string YRNRO { get; set; }
       public string HAKUNIMI { get; set; }
       public string NIMIA { get; set; }
       public string NIMIB { get; set; }
    }

    public static IEnumerable<JoinedFandS> GetMyJoinedResult()
    {
        var t1 = ConnectAndRetriveDatatatableS(); // t1
        var t2 = ConnectAndRetriveDatatatableF(); // t2

        var firstTable = ...

        var secondTable = ...

        var results = firstTable.Concat(secondTable);

        return results;
    }

EDIT:

<Window x:Class="Liinos_inspector_FilterTest.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:Liinos_inspector_FilterTest="clr-namespace:Liinos_inspector_FilterTest" 
        mc:Ignorable="d"
        Title="Liinos database inspector" Height="672" Width="1000" Icon="Images/logo_icon-small.jpg" Background="White" MinWidth="1000">

  <Window.DataContext>
    <ViewModel />
  </Window.DataContext>

Severity Code Description Project File Line Suppression State Error XLS0414 The type 'ViewModel' was not found. Verify that you are not missing an assembly reference and that all referenced assemblies have been built. Liinos inspector FilterTest MainWindow.xaml 11

and

Severity Code Description Project File Line Suppression State Error XDG0008 ViewModel is not supported in a Windows Presentation Foundation (WPF) project. Liinos inspector FilterTest MainWindow.xaml 11

What should I use instead of ViewModel?

This is a data type mismatch. You cannot press a DataView into a collection. It's also more practicable to store the DataTable instead of the DataView . It's cheaper to get the view from the table, than getting the table from the view (in case you need to operate on the DataTable later).
Fixing this error also needs fixing the filtering.

DataGrid can handle a DataTable directly.

Note that you must await the return value of LoadMainTableDataAsync . Otherwise this method would return prematurely (because the result is computed in a background thread). I am sure, that this part of you code doesn't even compile. Maybe this is just example code.

This example also adjusts the filtering based on the new data structure. To filter a DataTable.DataView you must use the DataView.RowFilter property (see Expression Syntax for help). You need to adjust the actual filter logic to your requirements:

ViewModel.cs

class ViewModel : INotifyPropertyChanged
{
  public ICommand LoadMainTableDataCommand => new RelayCommand(async param => ExecuteLoadMainTableDataAsync());

  private DataTable mainDataTable;   
  public DataTable MainDataTable 
  {
    get => this.mainDataTable;
    set 
    { 
      this.mainDataTable = value; 
      OnPropertyChanged();  
      
      // Set the DataTable filter expression
      EnableRowFiltering();
    }
  }

  // Binding source for the first name TextBox
  private string firstNameSearchKey;   
  public string FirstNameSearchKey
  {
    get => this.firstNameSearchKey;
    set 
    { 
      this.firstNameSearchKey = value; 
      OnPropertyChanged();  
      
      // Refresh the DataTable filter expression
      EnableRowFiltering();
    }
  }

  // Binding source for the last name TextBox
  private string lastNameSearchKey;   
  public string LastNameSearchKey
  {
    get => this.lastNameSearchKey;
    set 
    { 
      this.lastNameSearchKey = value; 
      OnPropertyChanged();  
      
      // Refresh the DataTable filter expression
      EnableRowFiltering();
    }
  }

  private bool hasProgress;   
  public bool HasProgress
  {
    get => this.hasProgress;
    set 
    { 
      this.hasProgress = value; 
      OnPropertyChanged();
    }
  }

  public void EnableRowFiltering()
  {
    // The filter assumes a column 'FirstName' and a column 'LastName' in the DataView. 
    // The filter expression mimics string.StartsWith.
    this.MainDataTable.DefaultView.RowFilter = 
      $"FirstName LIKE '{this.FirstNameSearchKey}*' " + 
      $"OR LastName LIKE '{this.LastNameSearchKey}*'";
  }

  private async Task ExecuteLoadMainTableDataAsync()
  {
    if (MainProcess.CheckForVPNInterface())
    {
      if (MainProcess.Customers != null)
      {
        this.HasProgress = true;

        this.MainDataTable = await LoadMainTableDataAsync();

        this.HasProgress = false;
      }
    }
    else
    {
      throw new VpnInterfaceException("Please, check your VPN connection!");
    }
  } 

  public async Task<DataTable> LoadMainTableDataAsync()
  {
    return await Task.Run(() =>
    {
      MainProcess.MergedTable();

      return MainProcess.CustomersInLiinos;
    });
  }

  public event PropertyChangedEventHandler PropertyChanged;
  protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

MainWindow.xaml

<Window>
  <Window.DataContext>
    <ViewModel />
  </Window.DataContext>

  <Window.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
  </Window.Resources>
 
  <StackPanel>
    <ProgressBar IsIndeterminate="True"
                 Visibility="{Binding HasProgress, Converter={StaticResource BooleanToVisibilityConverter}}" />

    <Button Command="{Binding LoadMainTableDataCommand}" 
            Content="Load Data" />

    <TextBox Text="{Binding FirstNameSearchKey}" />
    <TextBox Text="{Binding LastNameSearchKey}" />
    <DataGrid ItemsSource="{Binding MainDataTable}" />
  <StackPanel>
</Window>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM