2013-02-14 56 views
1

我想過濾一個ObservableCollection數據綁定到我的WPF UI上的ListView。但是,當集合刷新時,ListView變爲空白並且不顯示任何內容。我也在試圖自我介紹MVVM模式。這個問題可能是我沒有刷新控件,但我怎樣才能讓它在MVVM模式下刷新?我習慣做Winforms和代碼隱藏,當用戶點擊Search按鈕時會發生過濾器邏輯 - 它調用ApplicationModel.Search方法。已過濾的ObservableCollection不會更新WPF UI上的ListView

型號代碼:

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

視圖模型的代碼:

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

而且我在我的模型改變了刷新方法做過濾那裏。

+0

傑弗裏·汗是正確的 - 你缺少的inotify。幾個問題。 1)你爲什麼使用threadlocker?所有這些工作都是在UI線程上完成的,不應該被其他線程所觸及。 2)爲什麼每次刷新時都創建一個新的視圖模型?你爲什麼不只是刷新View Model的Observable Collection?在處理可能在視圖模型上連接的事件時,這更容易實現,並且更友好。如果您沒有手動刪除事件處理程序 - 視圖模型永遠不會處理,您的應用程序將消耗內存。 – tsells 2013-02-15 00:57:51

+0

是的,那是一個clusterf ** k並且會導致內存泄漏。這是非常晚,我很累,所以我寫了這樣的東西。我只是根據您的建議更改了刷新方法,以便參數進行過濾,然後工作正常,並且每次都不會創建新的集合,我們也不必擔心處置問題。 – Herman404 2013-02-15 19:09:48

回答

2

您的ViewModel需要執行INotifyPropertyChanged,並在AppCollection已更改時通知。

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

+1

這樣做!對於以此爲目的的任何人來說,我已經編輯了我的帖子,以反映我爲了使其發揮作用所做的更改 – Herman404 2013-02-15 19:04:37

相關問題