主窗口正在侦听插入/拔出USB设备。如果是usb-key / disk,它会从该设备收集文件列表,并在第二个窗口中显示该列表。
调试时我可以看到NewUsbFiles observablecollection得到了117个项目。我看到属性UsbFile(在调用showdialog之前)有117个项目,但是列表框是空的。
有什么想法吗?
填充/创建第二个窗口的方法:
NewUsbFiles = new ObservableCollection<UsbFile>();
UpdateNewUsbFiles(driveName);
Application.Current.Dispatcher.Invoke(delegate
{
var usbFileSelector = new UsbFileSelector()
{
Owner = this,
UsbFiles = NewUsbFiles
};
usbFileSelector.ShowDialog();
});
UsbFile-class:
public class UsbFile
{
public string UsbFileName { get; set; }
public string OnTableFileName { get; set; }
public bool Ignored { get; set; } = false;
public UsbFile(string fileName)
{
var fileInfo = new FileInfo(fileName);
UsbFileName = fileInfo.FullName;
OnTableFileName = $"{fileInfo.CreationTime:yyMMddHHmmsss}_{fileInfo.Name}";
}
}
第二个窗口的XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:MainWindow="clr-namespace:PartyPictures.WPF.MainWindow" x:Name="wUsbFileSelector"
x:Class="PartyPictures.WPF.UsbFileSelector"
mc:Ignorable="d"
Title="USB" HorizontalAlignment="Center" VerticalAlignment="Center" WindowStyle="ToolWindow" ScrollViewer.VerticalScrollBarVisibility="Auto" SizeToContent="WidthAndHeight">
<StackPanel x:Name="spUsbFileList">
<ListBox x:Name="ImageListbox"
DataContext="{Binding ElementName=wUsbFileSelector}"
ItemsSource="{Binding UsbFiles}"
Background="AliceBlue" ScrollViewer.HorizontalScrollBarVisibility="Disabled" MinWidth="200" MinHeight="200">
</ListBox>
</StackPanel>
</Window>
第二个窗口的代码隐藏:
public partial class UsbFileSelector : Window
{
public ObservableCollection<UsbFile> UsbFiles { get; set; } = new ObservableCollection<UsbFile>();
public UsbFileSelector()
{
InitializeComponent();
}
}
答案 0 :(得分:1)
在窗口中,您可以看到InitializeComponent方法。它创建了XAML中定义的所有内容并应用了所有绑定。在使用您的空收集器(您使用默认属性值创建)绑定绑定后,绑定将不知道该属性的任何更改,这是正确的答案。
但实现INotifyPropertyChanged更多是关于viewmodel实例,而不是视觉。
如果你想绑定,我真的建议你为Windows和控件使用Dependency Property。有一些原因:
以下是更改后窗口的外观
public partial class UsbFileSelector : Window
{
public static readonly DependencyProperty UsbFilesProperty =
DependencyProperty.Register("UsbFiles", typeof(ObservableCollection<UsbFile>), typeof(UsbFileSelector));
public ObservableCollection<UsbFile> UsbFiles
{
get { return (ObservableCollection<UsbFile>) GetValue(UsbFilesProperty); }
set { SetValue(UsbFilesProperty, value); }
}
public UsbFileSelector()
{
InitializeComponent();
}
}
另外,我强烈建议您在为WPF开发时使用一些WPF检查器工具,例如,snoop。您可以在应用程序运行时浏览控件和属性,并从代码或stackoverflow中快速查找问题=)
答案 1 :(得分:0)
在
var usbFileSelector = new UsbFileSelector()
{
Owner = this,
UsbFiles = NewUsbFiles
};
您正在为UsbFiles
属性分配新值,而不会触发该属性的属性更改通知。
您可以实现INotifyPropertyChanged并触发PropertyChanged事件或使UsbFiles成为依赖项属性。
或者您将NewUsbFiles
作为构造函数参数传递,并在调用InitializeComponent
public UsbFileSelector(ObservableCollection<UsbFile> usbFiles)
{
UsbFiles = usbFiles;
InitializeComponent();
}
并将其称为:
var usbFileSelector = new UsbFileSelector(NewUsbFiles)
{
Owner = this
};
请注意,如果您始终传递新集合,则实际上不需要使用ObservableCollection。您永远不会在集合中添加或删除元素,因此不需要更改通知。
答案 2 :(得分:0)
有人发布了(并删除了评论)我应该添加的内容 DataContext = this;
要
public UsbFileSelector()
{
InitializeComponent();
DataContext = this;
}
其他人提到(评论也被删除),由于
,这不是必需的DataContext="{Binding ElementName=wUsbFileSelector}"
在XAML中。
但事实证明,从XAML中删除DataContext行并在代码中将其设置为此是sollution。不知道为什么会这样做。
编辑只是为了表明这不是一个好的解决方案,只是偶然起作用,请尝试以下方法:
// this works
var usbFileSelector = new UsbFileSelector();
usbFileSelector.Owner = this;
usbFileSelector.UsbFiles = NewUsbFiles;
usbFileSelector.ShowDialog();
// this does not
var usbFileSelector = new UsbFileSelector();
usbFileSelector.Owner = this;
await Task.Delay(10);
usbFileSelector.UsbFiles = NewUsbFiles;
usbFileSelector.ShowDialog();
答案 3 :(得分:0)
已经给出的所有答案都是正确的,问题的核心是
UsbFiles = NewUsbFiles
导致绑定“中断” - UsbFiles 不再指向绑定到列表框的集合。
解决这个问题的另一种可能方法是简单地单独绑定绑定集合,然后重新填充内容。
var usbFileSelector = new UsbFileSelector()
{
Owner = this,
UsbFiles.Clear();
foreach (var uf in NewUsbFiles) {
UsbFiles.Add(uf);
}
};