简体   繁体   中英

C# WPF MVVM - Merge multiple csv to datagrid

I've been working on this little program, that needs to take file inputs of CSV files, store them in a listbox, and then update automatically the datagrid. When there is added more files, the datagrid needs to expand with the new file data and add next to it.

  1. What works is adding files to the listbox with the binding in the XAML code and codebehind.
  2. What doesn't work is merging the data to display dynamically with the binding to the datagrid. Property changed are raised, but grid aren't updating.

In DataGridViewModel is where my csv merge code is:

public class DataGridViewModel 
    {
   static public DataGridModel _dataGridModel = new DataGridModel();

    public static void ReturnDataTableForGridView()
    {
        DataTable mainTable = new DataTable();
        //-- #3 Test merge 
        foreach (var item in SidePanelViewModel.GetPathFileList())
        {
            DataTable dataTable = new DataTable();
            try
            {

                string[] Lines = File.ReadAllLines(item.Filepath);
                string[] Fields;
                Fields = Lines[0].Split(new char[] { ';' });
                int Cols = Fields.GetLength(0);

                //1st row skal være kolonne navn; 
                for (int X = 0; X < Cols; X++)
                    dataTable.Columns.Add(Fields[X].ToLower(), typeof(string));

                DataRow Row;
                for (int T = 1; T < Lines.GetLength(0); T++)
                {
                    Fields = Lines[T].Split(new char[] { ';' });
                    Row = dataTable.NewRow();
                    for (int f = 0; f < Cols; f++)
                        Row[f] = Fields[f];
                    dataTable.Rows.Add(Row);
                }
                //-- Merges every files(tables) into one.
                mainTable.Merge(dataTable);                   
            }
            catch (Exception)
            {
                return null;
            }
        }
        //-- Sets the datatablemerger which raises the propertychanged 
        _dataGridModel.DatatableMerger = mainTable;

    }
}

The DataGridModel class

   public class DataGridModel : INotifyPropertyChanged
{


    DataTable _dataTableMerger { get; set; } = new DataTable();

    public DataTable DatatableMerger
    {
        get
        {
            return _dataTableMerger;
        }
        set
        {
            _dataTableMerger = value;
            OnPropertychanged("DatatableMerger");
        }
    } 


    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertychanged([CallerMemberName] string caller = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(caller));
    }

}

The dataGridview class

    public DataGridView()
    {
        InitializeComponent();
    }

The XAML code:

        <DataGrid x:Name="MainDataGrid"  Grid.Row="1" VerticalAlignment="Stretch" Height="auto" ItemsSource="{Binding Path=DatatableMerger, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" >
    </DataGrid>
</Grid>
<UserControl.DataContext>
     <Model:DataGridModel/>
</UserControl.DataContext>

Currently output:

当前输出-图片

Wished output:

希望输出-图片

Propertychanged getting raised

My friend of mine helped me out with an example.

Following ansvar:

Your DataContext in the XAML is wrong. Your view must cummunicate with your ViewModel and not your Model.

If you run MVVM, then it's wrong to use button click events in your Views codebehind. It must be done in the ViewModel.

Besides this, your CSV parser is wrong implementet. It will break as soon as a field contains semikolon, new lines, or if komma is used as a fieldseparator instead of semikolon.

Read more about etc. RFC specifikation about CSV files HERE or use a libary that can parse the files correctly. ex. ExcelDataReader ANd if you want it into your DataTable; ExcelDataReader.DataSet

Regarding an example of functional and correct binding follow below examble:

MainWindow.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

The XAML

    <Window.DataContext>
    <local:DataGridViewModel/>
</Window.DataContext>
<Grid>
    <DataGrid Margin="0,0,0,35" ItemsSource="{Binding DatatableMerger}"/>
    <Button Content="Add rows" Margin="0,0,10,10" Command="{Binding AddRowsButtonClickCommand}" Height="20" VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="75"/>
</Grid>

The DataGridModel.cs

    public class DataGridModel
{
    public DataTable DatatableMerger { get; set; }
}

The DataGridViewModel.cs

    public class DataGridViewModel : INotifyPropertyChanged
{
    private readonly DataGridModel _dataGridModel = new DataGridModel();

    public DataTable DatatableMerger => _dataGridModel.DatatableMerger;

    public ICommand AddRowsButtonClickCommand => new DelegateCommand(o => ReturnDataTableForGridView());

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    public void ReturnDataTableForGridView()
    {
        var dt = new DataTable();

        dt.Columns.Add("Foo");
        dt.Columns.Add("Bar");
        dt.Columns.Add("Baz");

        for (var i = 0; i < 5; i++)
            dt.Rows.Add($"Value {i}", i, DateTime.Now.AddSeconds(i));

        _dataGridModel.DatatableMerger = dt;
        OnPropertyChanged(nameof(DatatableMerger));
    }
}

The delegate commands

    public class DelegateCommand : ICommand
{
    private readonly Predicate<object> _canExecute;
    private readonly Action<object> _execute;

    public event EventHandler CanExecuteChanged;

    public DelegateCommand(Action<object> execute) : this(execute, null) { }

    public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        if (_canExecute is null)
            return true;

        return _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
}

And for the merge funktion. Call the function with YourMainTableName = Mergetables(Table1, table2);

        public DataTable MergeTables(DataTable Table1, DataTable Table2)
    {
        DataTable Mergetable = new DataTable();

        foreach (DataColumn d in Table1.Columns)
        {
            Mergetable.Columns.Add(d.ColumnName);
        }

        foreach (DataColumn d in Table2.Columns)
        {
            Mergetable.Columns.Add(d.ColumnName);
        }

        int Table1Cols = Table1.Columns.Count;
        int Table1Rows = Table1.Rows.Count;
        int Table2Cols = Table2.Columns.Count;
        int Table2Rows = Table2.Rows.Count;

        DataRow row2;
        bool end = false;
        int RowCount = 0;

        while (!end)
        {
            end = true;
            if (RowCount < Table1Rows || RowCount < Table2Rows)
            {
                end = false;
                row2 = Mergetable.NewRow();

                if (RowCount < Table1Rows)
                {
                    for (int col = 0; col < Table1Cols; col++)
                    {
                        row2[col] = Table1.Rows[RowCount][col];
                    }
                }

                if (RowCount < Table2Rows)
                {
                    for (int col = 0; col < Table2Cols; col++)
                    {
                        row2[col + Table1Cols] = Table2.Rows[RowCount][col];
                    }
                }
                Mergetable.Rows.Add(row2);
            }
            RowCount++;
        }
        return Mergetable;
    }

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