初始化时ListView项源为空

时间:2017-10-06 01:55:49

标签: c# wpf listview

我正在尝试在初始化时使用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">

2 个答案:

答案 0 :(得分:1)

您永远不会设置datacontext。不要绑定和分配;你不需要两者兼而有之。只需设置父级的DataContext,并在XAML中绑定相应的父属性(您已经做过了 - 您的XAML看起来很好):

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

在将新的集合实例分配给其INotifyPropertyChanged.PropertyChanged属性时,请确保您的viewmodel正确引发Projects

并确保您执行为项目提供一个集合,并且其中包含一些内容。

您是否正在使用ObservableCollection<T>我希望,而不是List<T>来收藏?

更新

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

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();
 }