如何在WPF中将集合绑定到ListView?

7
我有一个程序用于搜索符合特定条件的目录文件。由于这个搜索过程需要很长时间,因此我必须以异步方式调用它。当搜索算法找到一个文件时,它会触发一个事件。我的 MainWindow 实例监听此事件,并需要更新 GUI。如何将这些“添加”的文件绑定到 ListView?我认为可以使用 ObservableCollection 实例,但我无法弄清如何绑定。
我已经剥离了所有无关的控件和代码。以下是两个相关文件。
MainWindow.xaml:
<Window x:Class="Example.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="CR Search" Height="395" Width="525">
    <Grid>
        <ListView x:Name="Results">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Filename"/>
                    <GridViewColumn Header="Directory"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

MainWindow.xaml.cs:

using System.IO;
using System.Threading.Tasks;

public partial class MainWindow
{
    private SearchLogic _backgroundSearch;

    private async void Search(object sender, RoutedEventArgs e)
    {
        // TODO: clear Results

        _backgroundSearch = new SearchLogic("", new DirectoryInfo("C:\"));
        _backgroundSearch.FileAdded += FileAdded;

        await Task.Run(new Action(_backgroundSearch.Search));
    }

    private void FileAdded(object sender, FileAddedEventArgs eventArgs)
    {
        // TODO: add eventArgs.File to Results
        // eventArgs.File is an instance of FileInfo
    }
}
1个回答

12

这是一个简单的例子

您的XAML

<Window x:Class="WpfApplication10.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Width="525"
        Height="350"
        Loaded="Window_Loaded">
    <Grid>
        <ListBox ItemsSource="{Binding FileNames}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Vertical">
                        <Label>Name</Label>
                        <TextBlock Text="{Binding Name}"/>
                        <Label>Modified</Label>
                        <TextBlock Text="{Binding LastModified}"/>                        
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

你的代码后台

public partial class MainWindow : Window
{
    public class FileInfo
    {
        public string Name { get; set; }
        public DateTime LastModified { get; set; }
        public FileInfo(string name)
        {
            Name = name;
            LastModified = DateTime.Now;
        }
    }

    ObservableCollection<FileInfo> mFileNames = new ObservableCollection<FileInfo>();

    public ObservableCollection<FileInfo> FileNames
    {
        get
        {
            return mFileNames;
        }
    }

    public MainWindow()
    {
        DataContext = this;
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        ThreadPool.QueueUserWorkItem((x) =>
            {
                while (true)
                {
                    Dispatcher.BeginInvoke((Action)(() =>
                    {
                        mFileNames.Add(new FileInfo("X"));
                    }));
                    Thread.Sleep(500);
                }
            });
    }
}

如果你运行这个程序,你会注意到列表框每半秒就会更新一次新的项目。基本上需要注意的关键是ObservableCollection只能从UI线程更新,因此如果你重构上面的代码,你需要通过当前UI线程的Dispatcher来更新它。


我已经解决了线程问题。那么在ObservableCollection中使用对象怎么样?比如一个FileInfo对象的集合。我该如何将文件名和其目录绑定到ListView中的列上? - Tyler Crompton
我刚刚更新了我的回答。如果你的 FileInfo 是可变的,并且在将其添加到列表后更改其属性,则必须在其上实现 INotifyPropertyChanged,以便 UI 更新。 - parapura rajkumar
我正在使用 System.IO.FileInfo。话虽如此,你为什么要使用 ListBox 而不是 ListView 呢? - Tyler Crompton
并不是真的...基本上你可以在XAML中绑定任何公共属性。FileInfo应该可以正常工作。 - parapura rajkumar
我必须添加一个DataContext。 - Tyler Crompton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接