我正在尝试在初始化时使用ListView的过滤器,该项目正在为ListView抛出一个空指针,即使我在构造函数和绑定中设置它。这是我的代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var viewModel = new MainViewModel();
this.ProjectListView.ItemsSource = viewModel.Projects;
这是引用它的XAML。
<ListView x:Name="ProjectListView" Margin="0,0,10,0" ItemsSource="{Binding Projects}" FontSize="16" Foreground="Black">
我不确定为什么ItemSource在构造函数中初始化时为null。是否需要应用PropertyChanged绑定?
这是我的大多数XAML
<TextBox x:Name="FolderNameBox" Grid.Column="1" Background="White" Grid.Row="1" Grid.ColumnSpan="5"
Margin="0,0,287,654.333" VerticalContentAlignment="Center"
Padding="6" FontSize="16"
IsReadOnly="True"
Text="{Binding ElementName=Hierarchy, Path=SelectedItem.Path, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}">
</TextBox>
<TextBox x:Name="SearchProjectsBox" Grid.Column="5" Background="White" Grid.Row="1" Text="Search Projects"
Margin="47.333,0,0,654.333" VerticalContentAlignment="Center" Foreground="LightGray" Padding="6" FontSize="16" HorizontalAlignment="Left" Width="268" GotFocus="TextBox_GotFocus" LostFocus="TextBox_LostFocus" TextChanged="FilterListView"/>
<TreeView x:Name="Hierarchy" Grid.Column="4" HorizontalAlignment="Left" Height="631" Margin="0,58,0,0" Grid.Row="1" VerticalAlignment="Top" Width="226"
ItemsSource="{Binding Path=Projects}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding ChildFolders}">
<StackPanel Orientation="Horizontal" >
<Image Source="{Binding Icon}" Margin="5, 5, 5, 5"></Image>
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" BorderThickness="0" FontSize="16" Margin="5" IsReadOnly="True" PreviewMouseDoubleClick="SelectAll" LostFocus="TextBoxLostFocus"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<Grid Grid.ColumnSpan="2" Grid.Column="4" HorizontalAlignment="Left" Height="631" Margin="245,58,0,0" Grid.Row="1" VerticalAlignment="Top" Width="540">
<ScrollViewer HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
<ListView x:Name="ProjectListView" Margin="0,0,10,0" ItemsSource="{Binding Projects}" FontSize="16" Foreground="Black">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="false">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
和我的基本视图模型
private ObservableCollection<Project> projects;
public ObservableCollection<Project> Projects
{
get { return projects; }
set
{
if (value != projects)
{
projects = value;
OnPropertyChanged("Projects");
}
}
}
这是背后的代码
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
MainViewModel model = new MainViewModel();
model.BuildData();
this.ProjectListView.ItemsSource = model.Projects;
}
private void FilterListView(object sender, TextChangedEventArgs e)
{
CollectionViewSource.GetDefaultView(this.ProjectListView.ItemsSource).Refresh();
}
FilterListView是TextChange方法。它打破了第一行。 ProjectListVIew正在注册为null但它甚至不应该被启动,因为它依赖于TextBox中的更改。
编辑。这是
背后的代码 public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
MainViewModel model = new MainViewModel();
model.BuildData();
this.ProjectListView.ItemsSource = model.Projects;
}
private void FilterListView(object sender, TextChangedEventArgs e)
{
CollectionViewSource.GetDefaultView(this.ProjectListView.ItemsSource).Refresh();
}
private void SelectAll(object sender, MouseButtonEventArgs e)
{
TextBox box = sender as TextBox;
box.IsReadOnly = false;
box.SelectAll();
}
private void TextBoxLostFocus(object sender, RoutedEventArgs e)
{
TextBox box = sender as TextBox;
box.IsReadOnly = true;
}
private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
TextBox tb = (TextBox)sender;
tb.Text = string.Empty;
tb.Foreground = Brushes.Black;
tb.GotFocus -= TextBox_GotFocus;
}
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
TextBox box = (TextBox)sender;
box.Text = "Search Projects";
box.Foreground = Brushes.LightGray;
box.GotFocus += TextBox_GotFocus;
}
}
}
基本视图模型
public class ViewModelBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string projectName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(projectName));
}
}
#endregion INotifyPropertyChanged
}
我正在使用的视图模型
class MainViewModel : ViewModelBase
{
private ObservableCollection<Project> projects;
public ObservableCollection<Project> Projects
{
get { return projects; }
set
{
if (value != projects)
{
projects = value;
OnPropertyChanged("Projects");
}
}
}
编辑:
我的ListView不断变化 - 如图所示,所显示的数据将基于用户在TreeView中的选择。现在,我的过滤器没有考虑屏幕上的实际内容。它仅基于绑定的Collection进行过滤。
因此,如果我的Collection是Fruit,Vegetables,Meat,Dairy和我的ListView是Apple,Carrot和Milk,如果我搜索Apple,ListView将是空白但如果我搜索Fruit,我将有一个填充行。显然不正确。
听起来我非常接近。
这是我的视图模型:
public ICollectionView SourceCollection
{
get
{
return this.projectCollection.View;
}
}
public string FilterText
{
get
{
return filterText;
}
set
{
filterText = value;
this.projectCollection.View.Refresh();
RaisePropertyChanged("SearchProjectsText");
}
}
private void projectCollection_Filter(object sender, FilterEventArgs e)
{
if (string.IsNullOrEmpty(FilterText))
{
e.Accepted = true;
return;
}
Project project = e.Item as Project;
if (project.Name.ToUpper().Contains(FilterText.ToUpper()) || project.Path.ToUpper().Contains(FilterText.ToUpper()))
{
e.Accepted = true;
}
else
{
e.Accepted = false;
}
}
public void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
其中SearchProjectText是用于过滤的实际TextBox。我的相关XAML:
<TextBox x:Name="SearchProjectsBox" Grid.Column="5" Background="White" Grid.Row="1" Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}"
Margin="47.333,0,0,654.333" VerticalContentAlignment="Center" Foreground="Black" Padding="6" FontSize="16" HorizontalAlignment="Left" Width="268"/>
<TreeView x:Name="Hierarchy" Grid.Column="4" HorizontalAlignment="Left" Height="631" Margin="0,58,0,0" Grid.Row="1" VerticalAlignment="Top" Width="226"
ItemsSource="{Binding Path=Projects}">
<ListView x:Name="ProjectListView" Margin="0,0,10,0" ItemsSource="{Binding SourceCollection}" FontSize="16" Foreground="Black">
答案 0 :(得分:1)
您永远不会设置datacontext。不要绑定和分配;你不需要两者兼而有之。只需设置父级的DataContext,并在XAML中绑定相应的父属性(您已经做过了 - 您的XAML看起来很好):
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
在将新的集合实例分配给其INotifyPropertyChanged.PropertyChanged
属性时,请确保您的viewmodel正确引发Projects
。
并确保您执行为项目提供一个集合,并且其中包含一些内容。
您是否正在使用ObservableCollection<T>
我希望,而不是List<T>
来收藏?
我不知道为什么(已经很晚了,我累了,抱歉!),但是FilterListView
在InitializeComponent()
之前被调用了。当你描述症状时,我应该想到这一点。这为我解决了这个问题:
private void FilterListView(object sender, TextChangedEventArgs e)
{
if (this.ProjectListView != null)
{
CollectionViewSource.GetDefaultView(this.ProjectListView.ItemsSource).Refresh();
}
}
答案 1 :(得分:0)
设置DataContext,它将创建一个与其绑定的ViewModel的新实例。
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}