从 Windows 窗体到 WPF 是一个挑战,这是我的第一个 WPF 项目,所以如果我遗漏了一些明显的东西,请原谅我......
我正在逐行向 ListView 添加项目,然后想稍后迭代这些项目并读取项目和子项目值。我尝试了几种方法,但都只返回最后一行。
我没有使用 ItemsSource 属性,因为我想在添加行时查看它们,因为在添加每行之前可能需要一些时间来处理每行的数据。如果我使用 ItemsSource = data,我必须等到获取所有数据,然后一次性添加所有数据,并且还没有找到使用该方法的另一种方法。
我在这里看了很多建议,这个看起来不错,但它使用 ItemsSource 一次性添加所有数据。 https://stackoverflow.com/questions/42635953/c-sharp-wpf-iterate-through-listview-items
我有这个代码
<ListView x:Name="listViewResults" Margin="2,117,4,36" Grid.ColumnSpan="6" FontFamily="Consolas" >
<ListView.View>
<GridView>
<GridViewColumn Header="#" Width="40" DisplayMemberBinding ="{Binding Path=hop}"/>
<GridViewColumn Header="Host/IP" Width="350" DisplayMemberBinding ="{Binding Path=hostIP}"/>
<GridViewColumn Header="RTT1" Width="100" DisplayMemberBinding ="{Binding Path=R1}"/>
<GridViewColumn Header="RTT2" Width="100" DisplayMemberBinding ="{Binding Path=R2}"/>
<GridViewColumn Header="RTT3" Width="100" DisplayMemberBinding ="{Binding Path=R3}"/>
<GridViewColumn Header="Average" Width="100" DisplayMemberBinding ="{Binding Path=average}"/>
</GridView>
</ListView.View>
</ListView>
public class RowData
{
public string? hop { get; set; }
public string? hostIP { get; set; }
public string? R1 { get; set; }
public string? R2 { get; set; }
public string? R3 { get; set; }
public string? average { get; set; }
public string? tag { get; set; }
}
这就是我添加的方式,逐行添加...
RowData row = new RowData();
ListView lv = listViewResults;
lv.Items.Clear();
foreach (var entry in MyMethod(ipToTrace))
{
row.hop = hopID;
row.hostIP = hostOrIPAddress;
row.R1 = roundTripTime[0];
//etc...
lv.Items.Add(row);
}
我已经尝试了所有这些方法来迭代 ListView 并且都返回唯一的最后一行
// 1
foreach (RowData item in listViewResults.Items)
{
MessageBox.Show("Hop: " + item.hop + " IP: " + item.hostIP);
}
// 2
for (int i = 0; i < listViewResults.Items.Count; i++)
{
RowData item = listViewResults.Items[i] as RowData;
MessageBox.Show("Hop: " + item.hop + " IP: " + item.hostIP);
}
// 3
List<RowData> items = (List<RowData>)listViewResults.Items.Cast<RowData>().ToList();
foreach (RowData row in items)
{
MessageBox.Show(row.hostIP + " - " + row.ToString());
}
当我查询 count 属性时,它总是具有正确的行数,但我真的很困惑为什么我只得到最后一条记录返回。
您对
ItemsControl.ItemsSoucre
属性及其使用方式的所有假设都是错误的。您永远不应该通过将项目添加到 ItemsSource
或 Items
属性来直接修改集合。相反,定义一个您正在处理的集合并将其分配给 ItemsSource
(最好使用数据绑定)。
您所要做的就是创建一个
ObservableCollection<T>
并将其分配给 ItemsSource
属性。现在,当向该集合添加/删除项目时,ListView
将自动更新以显示更改。您使用相同的集合来迭代行。
请注意,常见的 C# 命名约定 要求所有公共成员都使用 PascalCase 而不是驼峰式命名。只有字段被命名为驼峰命名法,并且字段永远不会是公共的,除非它们是常量或事件。如果您决定不使用通用约定,那么您至少应该保持一致,并且不要混合命名规则(因为您的一些属性是 PascalCase 和一些 CamelCase)。
partial class MainWindow : Window
{
// ObservableCollection implements INotifyCollectionChanged which enables
// every ItemsControl (like the ListView) to track changes of the ItemsSource.
// Create a field or property.
public ObservableCollection<RowData> Rows { get; }
public MainWindow()
{
InitializeComponent();
this.Rows = new ObservableCollection<RowData>();
// Assign the collection to the ItemsSource property or use data binding
listViewResults.ItemsSource = this.Rows;
this.Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
foreach (var entry in MyMethod(ipToTrace))
{
RowData row = new RowData()
{
Hop = hopID,
hostIP = hostOrIPAddress,
R1 = roundTripTime[0],
//etc...
}
this.Rows.Add(row);
}
}
private void ProcessRows()
{
// If you want to iterate over the rows, just use the source collection
foreach (RowData row in this.Rows)
{
MessageBox.Show("Hop: " + row.hop + " IP: " + row.hostIP);
}
}
}