Home > database >  Where do File Parsers belong in MVVM Design Pattern?
Where do File Parsers belong in MVVM Design Pattern?

Time:09-23

I have tried to find a good consistent folder structure in Visual Studio to capture all the possibilities. This so far has been what I've came up with for my project. Folder Structure

My Application looks like: My Application

The xaml is pretty straight forward:

<Window x:Class="Check.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:viewModels="clr-namespace:SA_BOM_Check.ViewModels"
        mc:Ignorable="d"
          d:DataContext="{d:DesignInstance Type=viewModels:MainWindowViewModel, IsDesignTimeCreatable=True}"
        Height="600" Width="800"
        DataContext="{StaticResource ResourceKey=MainWindowViewModel}">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150" />
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="20"></RowDefinition>
            <RowDefinition Height="40"></RowDefinition>
            <RowDefinition Height="40"></RowDefinition>
            <RowDefinition Height="10"></RowDefinition>
            <RowDefinition Height="30"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="30"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="1"  Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Text="XA File: " Height="30" FontSize="20" FontWeight="Bold"/>
        <TextBox x:Name="TxtXAFile" Grid.Row="1" Grid.Column="1"  Text="{Binding Path=XAFile, Mode=TwoWay}" VerticalAlignment="Center" FontSize="15"></TextBox>
        <Button x:Name="BtnXaBrowse" Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" Margin="10,5,80,1" FontSize="20" FontWeight="DemiBold" Click="BtnXaBrowse_OnClick">Browse...</Button>
        <TextBlock Grid.Row="2"  Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right"  Text="Inventor File: " Height="30" FontSize="20" FontWeight="Bold"/>
        <TextBox Grid.Row="2" Grid.Column="1" x:Name="TxtInventorFile" Text="{Binding Path=InventorFile, Mode=TwoWay}" VerticalAlignment="Center" FontSize="15"/>
        <Button x:Name="BtnInventorBrowse" Grid.Row="2" Grid.Column="2" VerticalAlignment="Center"  Margin="10,0,80,0" FontSize="20" FontWeight="DemiBold" Click="BtnInventorBrowse_OnClick">Browse...</Button>
        <Button x:Name="BtnDiff" Grid.Row="2" Grid.Column="3" VerticalAlignment="Center"  Margin="10,5,80,1" FontSize="20" FontWeight="DemiBold" Command="{Binding GetDifferences}">Differences</Button>
        <Line Grid.Row="3" Grid.Column="0"  Grid.ColumnSpan="4" X1="0" Y1="0" X2="1" Y2="0" Stroke="Black" StrokeThickness="2" Stretch="Uniform"></Line>
        <Label Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="4" Content="Missing in Inventor (Inventor - XA)" FontSize="15" FontStyle="Normal" HorizontalAlignment="Center" FontWeight="Bold"  Foreground="Black"/>
        <DataGrid AutoGenerateColumns="True" Grid.Row="5" Grid.Column="0"  Grid.ColumnSpan="4" IsReadOnly="True"
                  FontSize="18" ItemsSource="{Binding Path=XADiffDataTable}"
                  ColumnWidth="*">
            <DataGrid.ColumnHeaderStyle>
                <Style TargetType="{x:Type DataGridColumnHeader}">
                    <Setter Property="FontWeight" Value="Bold"></Setter>
                </Style>
            </DataGrid.ColumnHeaderStyle>
        </DataGrid>
        <Label Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="4" 
               Content="Missing In XA (XA - Inventor)" FontSize="15" FontStyle="Normal" 
               HorizontalAlignment="Center" FontWeight="Bold"  Foreground="Black"/>
        <DataGrid Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="4" 
                  AutoGenerateColumns="True" IsReadOnly="True"
                  FontSize="18" ItemsSource="{Binding Path=InventorDiffDataTable}"
                  ColumnWidth="*">
            <DataGrid.ColumnHeaderStyle>
                <Style TargetType="{x:Type DataGridColumnHeader}">
                    <Setter Property="FontWeight" Value="Bold"></Setter>
                </Style>
            </DataGrid.ColumnHeaderStyle>
        </DataGrid>
    </Grid>
</Window>

Code Behind:

using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;
using SA_BOM_Check.ViewModels;

namespace SA_BOM_Check.Views
{

    public partial class MainWindow : Window
    {
        //private readonly MainWindowViewModel _vm;

        public MainWindow()
        {
            InitializeComponent();
            //_vm = (MainWindowViewModel) this.DataContext;
        }

        private void BtnXaBrowse_OnClick(object sender, RoutedEventArgs e)
        {
            TxtXAFile.Text = OpenFileDialog();
            TxtXAFile.GetBindingExpression(TextBox.TextProperty)?.UpdateSource();
            //_vm.XAFile = OpenFileDialog();
        }

        private void BtnInventorBrowse_OnClick(object sender, RoutedEventArgs e)
        {
            TxtInventorFile.Text = OpenFileDialog();
            TxtInventorFile.GetBindingExpression((TextBox.TextProperty))?.UpdateSource();
        }

        private string OpenFileDialog()
        {
            OpenFileDialog openFileDialog = new();
            return openFileDialog.ShowDialog() == true ? openFileDialog.FileName : "";
        }
    }
}

Keeping the ShowDialog inside the code behind was inspired by BionicCode https://stackoverflow.com/users/3141792/bioniccode Where he answered the question about OpenFileDialogs Open File Dialog MVVM Actual Answer (which should have been the answer to the question) is at https://stackoverflow.com/a/64861760/4162851

The InventorAndXACompare class in summary is

        private static readonly Dictionary<string, Part> INVENTOR_PARTS 
            = new Dictionary<string, Part>();
        private static readonly Dictionary<string, Part> XA_PARTS = new Dictionary<string, Part>();
        private static readonly Dictionary<string, Part> XA_PARTS_OMIT = new Dictionary<string, Part>();
        private static readonly DataTable MISSING_IN_INVENTOR = new DataTable("XACompared");
        private static readonly DataTable MISSING_IN_XA = new DataTable("InventorCompared");

public static DataTable[] CompareFiles(string xaFile, string inventorFile)
private static void ParseInventor(string inventorFile)
private static void ParseXA(string xaFile)
private static void CompareXAToInventor()
private static void CompareInventorToXA()

The compare files takes two files. It then parses those files into two dictionaries that are compared in both directions where there are differences it adds those rows to a datatable inside the MainWindowViewModel those are then binded to the View by

        private DataTable _xaDiffDataTable;
        public DataTable XADiffDataTable
        {
            get { return _xaDiffDataTable;}
            set
            {
                _xaDiffDataTable = value;
                OnPropertyChanged("XADiffDataTable");
            }
        }

        private DataTable _inventorDiffDataTable;
        public DataTable InventorDiffDataTable
        {
            get { return _inventorDiffDataTable;}
            set
            {
                _inventorDiffDataTable = value;
                OnPropertyChanged("InventorDiffDataTable");
            }
        }

I would like to know if there is a better way of structuring this and if InventorAndXACompare would be better placed in the Models folder?

CodePudding user response:

In an MVVM architecture you would usually find parsers in the Model component. The View Model generally does not process data. Usually it may convert data to meet the constraints of the Model's interface or to prepare data for presentation in the View.

Also from an MVVM point of view the data source and sink is always part of the Model. It does not matter whether data comes from a database or from a file picked by the user.

  • Related