【问题标题】:ListView Item Source is null on initializationListView 项目源在初始化时为空
【发布时间】:2017-10-06 21:11:40
【问题描述】:

我试图在初始化时和初始化时对 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 为空。我需要应用 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 中的选择。现在,我的过滤器没有考虑屏幕上的实际内容。它仅基于绑定的集合进行过滤。

因此,如果我的集合是水果、蔬菜、肉类、乳制品,而我的 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 是用于过滤的实际文本框。我的相关 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">

【问题讨论】:

  • 您正在更新MainViewModel,但viewModel.Projects 可能仍然是null

标签: c# wpf listview


【解决方案1】:

您从不设置数据上下文。不要同时绑定和分配;你不需要两者。只需设置父级的 DataContext,并在 XAML 中绑定适当的父级属性(您已经这样做了——您的 XAML 看起来不错):

    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainViewModel();
    }

并确保当您将新集合实例分配给其 Projects 属性时,您的视图模型正确引发 INotifyPropertyChanged.PropertyChanged

并确保您确实为 Projects 提供一个集合,并且其中有一些东西。

我希望你使用ObservableCollection&lt;T&gt;,而不是List&lt;T&gt;,来收集?

更新

我不知道为什么(已经很晚了,我很累,抱歉!),但是 FilterListViewInitializeComponent() 之前被调用。当你描述症状时我应该想到这一点。这为我解决了这个问题:

private void FilterListView(object sender, TextChangedEventArgs e)
{
    if (this.ProjectListView != null)
    {
        CollectionViewSource.GetDefaultView(this.ProjectListView.ItemsSource).Refresh();
    }
}

【讨论】:

  • 是的,Projects 是一个 Observable。我想要做的主要目标是在 TextBox 上使用过滤机制。问题是,列表视图在加载时是空的,只有当用户在 TreeView 上进行选择时才会填充,所以它非常复杂。
  • 不应该那么复杂。您还需要向我们展示带有 CollectionViewSource 的部分。是在 XAML 中还是在视图模型中?
  • 我添加了一些我的 XAML 和虚拟机
  • 我添加了更多代码,XAML 已在上面发布。我希望这不是一件微不足道的事情。我希望它是更复杂的事情,所以我不觉得那么愚蠢
  • 我想通了。谢谢你的帮助。你把我放在正确的位置。
【解决方案2】:

设置将创建其绑定的 ViewModel 的新实例的 DataContext。

public MainWindow()
{
   InitializeComponent();
   DataContext = new MainViewModel();
 }

【讨论】:

  • 我的 TextChanged 方法仍然是一个空异常,它是 CollectionViewSource.GetDefaultView(ListViewItemsSource).Refresh();
猜你喜欢
  • 1970-01-01
  • 2018-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-09
  • 2022-10-24
  • 1970-01-01
  • 2018-12-13
相关资源
最近更新 更多