我正在创建一个练习应用程序来练习使用文本文件作为数据库。
现在我想要单击按钮以在文本框中显示该列表。
这是代码。
namespace StaffRosterLewis.ViewModel
{
class LoadData
{
public static void LoadRosterData()
{
string mypath = @"J:\zUtilities - Program Files\";
mypath += "StaffRoster - RosterOld.txt";
List<Model.Person> people = new List<Model.Person>();
List<string> lines = File.ReadAllLines(mypath, Encoding.ASCII).ToList();
foreach (var line in lines)
{
string[] entries = line.Split('|');
Model.Person newPerson = new Model.Person
{
LastName = entries[1],
FirstName = entries[2],
Extension = entries[3],
Department = entries[4],
Team = entries[5],
Group = entries[6],
Title = entries[7],
Shift = entries[8],
EmergencyResponder = entries[9],
AEDCPRCert = entries[10],
Languages = entries[11],
Notary = entries[12],
Note = entries[13],
DutyLocation = entries[14]
};
//newPerson.Unknown15 = entries[15];
people.Add(newPerson);
}
people.ToString();
}
}
}
我认为问题出在按钮点击发生的地方。我只是想显示上面的 people 的内容,但是无论我如何尝试引用它,我都会丢失变量“people”。上面的代码是公共的,我将其设置为静态,因此 people 变量应该可以在项目中的任何位置访问。 (我以为)
private void Button_Show_Click(object sender, RoutedEventArgs e)
{
Button_Show.Content = $"{LoadData.LoadRosterData.people.ToString()}";
}
您的代码有很多问题。
您正在尝试在这里访问静态属性之类的方法。
其次,你的返回类型是 void,它应该是 string 类型。
第三,您应该重写 ToString 方法,以所需格式将列表项返回为字符串。
您应该使用
Path.Combine
来获取路径。
如果您计划将
people
设置为静态变量,那么您必须接受它不是线程安全的,并确保在必要时重置它,否则您可能会在列表中遇到意外的项目。
如果一行中的
|
少于 15 个,你的代码将会抛出异常
你不需要做
LoadRosterData
static
。但是,正如其他评论者所提到的,该方法必须返回结果(在您当前使用的上下文中)。
因为从文件中读取可能会消耗资源,所以当您将结果存储在例如文件中时,可以提高性能。公共财产
Peoples
。LoadRosterData
设为实例成员。
要从集合中创建字符串,您可以使用
StringBuilder
。下面的示例使用 StringWriter
,它允许异步创建字符串。 StringWriter
内部也使用 StringBuilder
。
您可以通过覆盖 Person 类型的
ToString
来进一步改进代码。
为了提高文件读取性能,您应该使用
StreamReader
的异步 API,而不是同步 File
类。使用 StreamReader.ReadLineAsync
还可以节省额外的循环。
为了使文件处理和数据模型创建特别方便,您应该考虑使用序列化。
推荐的文本格式是 JSON。请参阅 Microsoft Docs:如何在 .NET 中序列化和反序列化(编组和解组)JSON 以了解具体操作方法。反序列化 JSON 文件(最好是异步)将自动生成
Person
项目的集合,没有任何麻烦(这将消除丑陋且脆弱的基于索引的访问(以初始化实例属性),并创建任何分隔符,例如管道“|”多余)。
您正在访问从索引“1”开始的数组。但在计算机科学中,索引总是从“0”开始。不确定您是否故意从索引“1”开始。
以下代码修复了一些问题并实现了一些性能改进。它还展示了如何将集合转换为
string
,其中每个 Person
项目都显示在其自己的行中:
PersonDataReader.cs
class PersonDataReader
{
// Consider to use an ImmutableList to prevent modification.
// In the current context, this property could (and probably should) defined private.
public List<Person> Persons { get; }
// If Person is private, 'HasData' has to be defined private too
public bool HasData => this.Persons.Any();
// Constructor
public PersonDataReader() => this.Persons = new List<Person>();
public async Task<string> CreateRosterSummaryAsync()
{
// Use StringWriter to enable asynchronous string creation.
// StringWriter also uses a StringBuilder internally to improve performance.
using (var textWriter = new StringWriter())
{
if (!this.HasData)
{
await LoadRosterDataAsync();
}
// Alternatively use LINQ,
// for example Enuemrable.Select together with Enumerable.Aggregate
// to concatenate the Person.ToString values
foreach (Person person in this.Persons)
{
string personString = person.ToString();
// Write a Person per line
await textWriter.WriteLineAsync(personString);
}
return textWriter.ToString();
}
}
private async Task LoadRosterDataAsync()
{
this.Persons.Clear();
// Use Path.Combine to ensure a valid formatted path (improve robustness)
string sourcePath = Path.Combine(@"J:\zUtilities - Program Files", "StaffRoster - RosterOld.txt");
// Test if the file actually exists to avoid the expensive exception.
// If the file not found exception is desired, remove the File.Exists condition.
if (File.Exists(sourcePath))
{
return;
}
using (var fileReader = new StreamReaeder(sourcePath, Encoding.ASCII))
{
while (!fileReader.EndOfFile)
{
var line = await reader.ReadLineAsync();
string[] personValues = line.Split('|', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
// If you would use serialization, constructing the type explicitly
// can be avoided. A recommended text format to allow easy de-/serialization is the JSON format.
var newPerson = new Model.Person
{
// Check if starting from index '1' is really correct
LastName = personValues[1],
FirstName = personValues[2],
Extension = personValues[3],
Department = personValues[4],
Team = personValues[5],
Group = personValues[6],
Title = personValues[7],
Shift = personValues[8],
EmergencyResponder = personValues[9],
AEDCPRCert = personValues[10],
Languages = personValues[11],
Notary = personValues[12],
Note = personValues[13],
DutyLocation = personValues[14]
};
this.Persons.Add(newPerson);
}
}
}
}
Person.cs
class Person
{
/* Properties of Person */
// Example text representation of a 'People' object
// using string interpolation
public override string ToString()
=> $"Lastname: {this.LastName}; Firstname: {this.FirstName}; Duty location: {this.DutyLocation}";
}
MainWindow.xaml.cs
partial class MainWindow : Window
{
private PersonDataReader PersonDataReader { get; }
public MainWindow()
{
InitializeComponent();
this.PersonDataReader = new PersonDataReader();
}
private async void Button_Show_Click(object sender, RoutedEventArgs e)
{
string personPerLineText = await this.PersonDataReader.CreateRosterSummaryAsync();
// Why did you chose a Button here? It should be
// this.DisplayTextBox.Text = personPerLineText;
this.Button_Show.Content = personPerLineText;
// Consider to display the complete List<Person> in a ListBox.
}
}
A
ListBox
可能是显示 Person
列表的更好选择。它的实现更加直观,并且无需担心字符串表示和创建。
你的方法LoadRosterData有一个返回值void,没有任何意义。如果您想返回一个字符串值并使用它,您可以这样做:
//returns a string
public static string MyStringMethod()
{
string str = "My string";
//Specify the return value with the return keyword
return str;
}
或者如果您想返回列表:
public static List<string> MyListMethod()
{
List<string> list = new List<string>();
list.Add("one");
list.Add("two");
list.Add("three");
return list;
}
你不能对列表执行ToString(),但你可以引用一个人的索引。 以及用途:
button.Content = $"{MyStringMethod()}"
或者如果你想通过名字获取人,你可以使用 IndexOf() 方法:
List<string> list = new List<string>();
list.Add("one");
list.Add("two");
list.Add("three");
string number = "one";
button.Content = $"{list[list.IndexOf(number)]}";