Filtered ObservableCollection不会在WPF UI上更新ListView

时间:2013-02-14 20:44:10

标签: c# wpf listview mvvm observablecollection

我正在尝试在我的WPF UI上过滤数据绑定到ListView的ObservableCollection。但是,当集合刷新时,ListView变为空白并且不显示任何内容。我也在尝试自学MVVM模式。问题可能是我没有刷新控件,但是如何让它在MVVM模式中刷新?我习惯于做Winforms和代码隐藏,当用户点击Search按钮时会发生过滤逻辑 - 它会调用ApplicationModel.Search方法。

型号代码:

public class AppObject
{
    public string Name { get; set; }
    public string Description { get; set; }
    public string Owner { get; set; }
    public string Email { get; set; }

    public AppObject(string name, string desc, string owner, string email)
    {
        this.Name = name;
        this.Description = desc;
        this.Owner = owner;
        this.Email = email;
    }
}

public class ApplicationsModel : ObservableCollection<AppObject>
{
    private static object threadLocker;
    private static ApplicationsModel current;

    static ApplicationsModel()
    {
        threadLocker = new object();
    }

    public static ApplicationsModel Current
    {
        get
        {
            lock (threadLocker)
            {
                if (current == null)
                {
                    current = new ApplicationsModel();
                }
            }
            return current;
        }
    }

    private ApplicationsModel()
    {
        this.Refresh();
    }

    private ApplicationsModel(IEnumerable<AppObject> collection)
        : base(collection)
    {
    }

    private void Refresh()
    {
                    try
                    {
                            // Query database to get the initial data - this code works fine
                    }
        catch (Exception e)
        {
            string error = String.Format("Could not refresh repository list: {0}", e.Message);
            MessageBox.Show(error, "Error Refreshing", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }

    public void Search(string key)
    {
        IEnumerable<AppObject> newList = current.Items.Where<AppObject>(t => t.Name.Equals(key));
        foreach (AppObject app in newList)
        {
            Console.WriteLine(app.Name);
            Console.WriteLine(app.Description);
        }
        current.Clear();
        current = null;
        current = new ApplicationsModel(newList);
    }

    public void ClearSearch()
    {
        Console.WriteLine("ClearSearch method called");
    }
}

ViewModel代码:

public class ApplicationViewModel
{
    public ObservableCollection<AppObject> AppCollection { get; set; }
    static string searchString;
    static string emailString;
    public AppObject SelectedApp { get; set; }
    public string AppToSearch
    {
        get
        {
            return searchString;
        }
        set
        {
            searchString = value;
        }
    }
    public string AppToRequest
    {
        get
        {
            return SelectedApp.Email;
        }
        set
        {
            SelectedApp.Email = value;
        }
    }
    private SearchButtonCommand searchButtonCmd;
    private ClearButtonCommand clearButtonCmd;
    private EmailButtonCommand emailButtonCmd;

    public ApplicationViewModel()
    {
        this.AppCollection = ApplicationsModel.Current;
    }

    public ICommand SearchButtonPressed
    {
        get
        {
            if (this.searchButtonCmd == null)
            {
                this.searchButtonCmd = new SearchButtonCommand();
            }
            return this.searchButtonCmd;
        }
    }

    public ICommand ClearButtonPressed
    {
        get
        {
            if (this.clearButtonCmd == null)
            {
                this.clearButtonCmd = new ClearButtonCommand();
            }
            return this.clearButtonCmd;
        }
    }

    public ICommand EmailButtonPressed
    {
        get
        {
            if (this.emailButtonCmd == null)
            {
                this.emailButtonCmd = new EmailButtonCommand();
            }
            return this.emailButtonCmd;
        }
    }

    private class SearchButtonCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            string searchkey = ApplicationViewModel.searchString;
            ApplicationsModel.Current.Search(searchkey);
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }
    }

    private class ClearButtonCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            ApplicationsModel.Current.ClearSearch();
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }
    }

    private class EmailButtonCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            string targetEmail = ApplicationViewModel.emailString;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }
    }
}

UI XAML:

<Window.DataContext>
    <vm:ApplicationViewModel />
</Window.DataContext>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Image Grid.Row="0" Height="84" HorizontalAlignment="Left" Margin="0,5,5,5" Name="imgNexusLogo" Stretch="Fill" VerticalAlignment="Top" Width="600" Source="C:\source\Nexus\NexusShop\Images\nexus1bannerlong.png" />
    <Grid Grid.Row="1" HorizontalAlignment="Center" Margin="0,5,5,5" VerticalAlignment="Center">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <Label Grid.Row="0" Grid.Column="0" Content="Search for Application">
            <Label.Foreground>
                <SolidColorBrush Color="LightCyan" />
            </Label.Foreground>
        </Label>
        <TextBox Grid.Row="0" Grid.Column="1" Margin="3" Width="500" Text="{Binding AppToSearch}" />
        <Button Grid.Row="0" Grid.Column="2" HorizontalAlignment="Right" Width="100" Height="20" Margin="3" Background="LightCyan" Content="Search" vm:ButtonBehaviour.SearchCommand="{Binding SearchButtonPressed}" />
        <Button Grid.Row="0" Grid.Column="3" HorizontalAlignment="Right" Width="100" Height="20" Margin="3" Background="LightCyan" Content="Clear Search" vm:ButtonBehaviour.ClearCommand="{Binding ClearButtonPressed}"/>
    </Grid>
    <ListView Grid.Row="2" BorderBrush="Black" HorizontalAlignment="Stretch" ItemsSource="{Binding Path=AppCollection}" SelectedItem="{Binding SelectedNexusApp}">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Application Name" Width="100" DisplayMemberBinding="{Binding Name}"/>
                <GridViewColumn Header="Application Description" Width="800" DisplayMemberBinding="{Binding Description}"/>
                <GridViewColumn Header="Application Owner" Width="100" DisplayMemberBinding="{Binding Owner}"/>
            </GridView>
        </ListView.View>
    </ListView>
    <Button Grid.Row="3" HorizontalAlignment="Center" Width="200" Height="30" Margin="3" Background="LightCyan" Content="Request Application" vm:ButtonBehaviour.EmailCommand="{Binding EmailButtonPressed}" />
</Grid>

同样,单击搜索按钮时会发生过滤的功能,并且它会在ApplicationModel.Search上运行该方法(string stringtofilteron)。我将MVVM课程基于本教程:http://www.codeproject.com/Articles/81484/A-Practical-Quick-start-Tutorial-on-MVVM-in-WPF

感谢您的帮助!

固定代码:         公共类ApplicationViewModel:INotifyPropertyChanged

    #region INotifyPropertyChanged implementation
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion

ApplicationsModel.Current.Search(this.searchString);
NotifyPropertyChanged();

我在模型中更改了Refresh方法,在那里进行过滤。

1 个答案:

答案 0 :(得分:2)

您的ViewModel需要实施INotifyPropertyChanged,并在AppCollection更改时通知。

参考: http://msdn.microsoft.com/en-us/library/ms229614.aspx