文件解析器属于 MVVM 设计模式的什么地方?

Where do File Parsers belong in MVVM Design Pattern?

我试图在 Visual Studio 中找到一个良好一致的文件夹结构来捕捉所有的可能性。到目前为止,这是我为我的项目想出的。

我的应用程序如下所示:

xaml 非常简单:

<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>

隐藏代码:

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 : "";
        }
    }
}

在后面的代码中保留 ShowDialog 的灵感来自 BionicCode https://whosebug.com/users/3141792/bioniccode 他在哪里回答了有关 OpenFileDialogs 的问题 Open File Dialog MVVM Actual Answer (which should have been the answer to the question) is at

InventorAndXACompare class总结起来就是

        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()

比较文件需要两个文件。然后它将这些文件解析为两个字典,在两个方向上进行比较,如果存在差异,它将这些行添加到 MainWindowViewModel 内的数据表中,然后通过

将这些行绑定到视图
        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");
            }
        }

我想知道是否有更好的结构方式,以及 InventorAndXACompare 是否最好放在 Models 文件夹中?

在 MVVM 架构中,您通常会在模型组件中找到解析器。视图模型通常不处理数据。通常它可能会转换数据以满足模型接口的约束或准备数据以在视图中呈现。

另外,从 MVVM 的角度来看,数据源和接收器始终是模型的一部分。数据是来自数据库还是来自用户选择的文件并不重要。