【发布时间】:2019-12-09 21:56:00
【问题描述】:
我正在编写一个WPF 应用程序来显示在大型系统中生成的日志文件,这将是其中的一部分。日志文件是.CSV 文件,并且将具有预定义的列数。但是,这些文件中隐藏着“子类型”。让我详细说明。
为简洁起见,假设我的文件有 4 列,即:
LineNum、Data1、Data2、Data3
但这里有一个问题。我们的Type1 日志文件将包含与LineNum, Data1, and Data2 相关的数据,而我们的Type2 日志文件将包含与LineNum, Data1, and Data3 相关的数据。请记住,这只是一个示例,我实际上有超过 4 列,并且大约有 20 种不同的组合。以下是每种类型日志的两个示例。
类型1
1,Data1A,Data2A,,
2,Data1B,Data2B,,,
3,Data1C,Data2C,,,
类型2
1,Data1A,,Data3A,
2,Data1B,,Data3B,
3,Data1C,,Data3C,
正如我之前所说,我的实际文件有大量列(70 多列),但每种类型的数据仅与少数列有关。我完全无法控制它,因为它是已经存在的旧较大系统的一部分。现在我想让我的应用程序读取这些文件,但只显示其中包含数据的列。
幸运的是,在更大的系统中,有一组“系统”文件指示哪种类型的文件在哪些列中有数据。因此,Type1 的 sys 文件将如下所示:
1、1、1、0
1 表示除第 3 列 (Data3) 之外的所有列都有数据。而Type2 的sys 文件将如下所示:
1、1、0、1
表示除Data2 之外的所有内容都可用。
现在,用户通过文件选择对话框选择要显示的文件类型。当他们这样做时,我希望应用程序弄清楚它是哪种类型,并相应地仅显示适用的列。这是一个示例应用程序,用于说明该应用程序。
我使用的两个 Model 类:
public class LogDataSet
{
public List<LogData> LogData { get; set; }
public List<bool> DisplayColumns { get; set; }
}
public class LogData
{
public int LineNum { get; set; }
public string Data1 { get; set; }
public string Data2 { get; set; }
public string Data3 { get; set; }
}
DisplayColumsn 列表本质上告诉您应该显示哪些列。通过查看下面的代码应该很容易理解其余部分。我有两个示例 Button 事件来模拟用户选择不同的日志类型。在阅读的时候,我也阅读了正确的sys文件类型,并显示数据。
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private LogDataSet _logDataSet;
public LogDataSet LogDataSet
{
get { return _logDataSet; }
set { _logDataSet = value; OnPropertyChanged("LogDataSet"); }
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private void BtnType1_Click(object sender, RoutedEventArgs e)
{
var type1logs = new List<LogData>
{
new LogData() { LineNum = 1, Data1 = "Data1A", Data2 = "Data2A" },
new LogData() { LineNum = 2, Data1 = "Data1B", Data2 = "Data2B" },
new LogData() { LineNum = 3, Data1 = "Data1C", Data2 = "Data2C" }
};
LogDataSet = new LogDataSet() { LogData = type1logs };
LogDataSet.DisplayColumns = ReadSysFiles("Type1.sys");
}
private void BtnType2_Click(object sender, RoutedEventArgs e)
{
var type2logs = new List<LogData>
{
new LogData() { LineNum = 1, Data1 = "Data1A", Data3 = "Data3A" },
new LogData() { LineNum = 2, Data1 = "Data1B", Data3 = "Data3B" },
new LogData() { LineNum = 3, Data1 = "Data1C", Data3 = "Data3C" }
};
LogDataSet = new LogDataSet() { LogData = type2logs };
LogDataSet.DisplayColumns = ReadSysFiles("Type2.sys");
}
public static List<bool> ReadSysFiles(string path)
{
var data = File.ReadAllLines(path).ToList()[0];
var parts = data.Split(',');
var display = new List<bool>();
foreach (var item in parts)
{
display.Add(item == "1" ? true : false);
}
return display;
}
}
还有我的简单XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<DataGrid Grid.Row="0" Grid.ColumnSpan="2"
Name="DgLogs" Margin="8" AutoGenerateColumns="False" IsReadOnly="True"
ItemsSource="{Binding LogDataSet.LogData}">
<DataGrid.Columns>
<DataGridTextColumn Header="Line #" Binding="{Binding LineNum}"/>
<DataGridTextColumn Header="Data1" Binding="{Binding Data1}"/>
<DataGridTextColumn Header="Data2" Binding="{Binding Data2}"/>
<DataGridTextColumn Header="Data3" Binding="{Binding Data3}"/>
</DataGrid.Columns>
</DataGrid>
<Button x:Name="BtnType1" Content="Type 1"
Width="100" Height="28" Margin="4, 4, 4, 8" Grid.Column="0" Grid.Row="1"
Click="BtnType1_Click"/>
<Button x:Name="BtnType2" Content="Type 2"
Width="100" Height="28" Margin="4, 4, 4, 8" Grid.Column="1" Grid.Row="1"
Click="BtnType2_Click"/>
</Grid>
这显然会显示所有 4 列,列中的空单元格不包含每种文件类型的数据。但是,根据我的bool 列表DisplayColumns,我将如何隐藏这些列?我看到很多 SO 帖子显示如何基于另一个控件等执行此类操作,但没有显示如何绑定到列表的索引。
编辑
我也愿意接受其他创造性的解决方案,而且我不必阅读sys 文件并使用DisplayColumns 列表。这是我采取的方法,但只要完成工作,我就可以走另一条路。
【问题讨论】:
标签: c# wpf data-binding datagrid show-hide