2015-12-03 43 views
1

最近我一直在学习C#和WPF的工作。我正在尝试在我正在开发的项目上使用MVVM,只是为了保持代码的有序性并了解它的工作原理。多次调用PropertyChanged的ViewModel属性

在MVVM中,View上的控件绑定到实现INotifyPropertyChanged的ViewModel上的属性。很多时候,当某个属性更新时,我会希望一堆其他属性作为结果进行更新。

例如,我有一个ListBox上面有一个TextBox。您可以输入文本框,并过滤列表框中的内容。但是在某些情况下,我还需要能够从代码中清除文本框。代码最终看起来是这样的:

private Collection<string> _listOfStuff; 
public Collection<string> FilteredList 
{ 
    get 
    { 
     if (String.IsNullOrWhiteSpace(SearchText)) 
     { 
      return _listOfStuff; 
     } 
     else 
     { 
      return new Collection<string>(_listOfStuff.Where(x => x.Contains(SearchText))); 
     } 
    } 
    set 
    { 
     if (value != _listOfStuff) 
     { 
      _listOfStuff = value; 
      OnPropertyChanged("FilteredList"); 
     } 
    } 
} 

private string _searchText; 
public string SearchText 
{ 
    get { return _searchText; } 
    set 
    { 
     if (value != _searchText) 
     { 
      _searchText = value; 
      OnPropertyChanged("SearchText"); // Tells the view to change the value of the TextBox 
      OnPropertyChanged("FilteredList"); // Tells the view to update the filtered list 
     } 
    } 
} 

随着这个项目变得越来越大,这开始感觉马虎。我有一个接线员,打了6个电话给OnPropertyChanged,并且很难跟踪东西。有一个更好的方法吗?

+0

通过马虎你是指很多OnPropertyChanged语句?那这正是你想要的不是? – Muds

+0

你不必调用'OnPropertyChanged(“FilteredList”);'因为它没有改变/分配。当它被改变时(即在一个异步命令中),当你执行'FilteredList = await SomeAsyncMethod()'时,它会被通知。你到底想要归档什么? – Tseng

+0

@Tseng我必须调用OnPropertyChanged(“FilteredList”);'因为它的值取决于SearchText的内容 –

回答

1

我尝试了Assisticant在大约一年前项目。它会计算出哪些属性需要提出通知以及哪些相关。在Pluralsight上有一个很好的课程,网站上的例子非常好。如果没有别的,你可以查看源代码,看看他是如何做到的。

还有一些来自Change Notification in MVVM Hierarchies的好建议。

他们提到:
使用属性 - >例如[DependsUpon(nameof(尺寸))]

约什 - 史密斯的PropertyObserver

能不能把一个方法加薪属性更改电话如果你只需要每次都提出同样的通知。

-2

如果你只是不想输入其他选项是引发OnPropertyChanged的所有属性,可以通过传递一个null或string.Empty来完成,尽管它会是一个斜坡的代码!

OnPropertyChanged(Null); 

OnPropertyChanged(String.Empty); 
0

首先你不应该在一个命令执行可能造成昂贵的操作,那么您就可以从你的SearchText删除OnPropertyChanged("FilteredList");

因此,您应该将该代码从getter移动到它自己的命令中,并将其从XAML绑定(或者作为按钮上的命令,或者使用Blends Interactivity Trigger在文本字段值发生更改时调用它)。

public ICommand SearchCommand { get; protected set; } 
// Constructor 
public MyViewModel() 
{ 
    // DelegateCommand.FromAsyncHandler is from Prism Framework, but you can use 
    // whatever your MVVM framework offers for async commands 
    SearchCommand = DelegateCommand.FromAsyncHandler(DoSearch); 
} 

public async Task DoSearch() 
{ 
    var result = await _listOfStuff.Where(x => x.Contains(SearchText)).ToListAsync(); 
    FilteredList = new Collection<string>(result); 
} 

private Collection<string> _listOfStuff; 
private Collection<string> _filteredList; 
public Collection<string> FilteredList 
{ 
    get 
    { 
     return _filteredList; 
    } 
    set 
    { 
     if (value != _filteredList) 
     { 
      _filteredList = value; 
      OnPropertyChanged("FilteredList"); 
     } 
    } 
} 

private string _searchText; 
public string SearchText 
{ 
    get 
    { 
     return _searchText; 
    } 
    set 
    { 
     if (value != _searchText) 
     { 
      _searchText = value; 
      OnPropertyChanged("SearchText"); 
     } 
    } 
} 

在一个侧面说明:您还可以使用OnPropertyChanged(nameof(FilteredList));有一个重构友好的版本,当你重命名你的财产所有OnPropertyChanged通话将被更新到。虽然需要C#6.0,但它与旧的.NET Frameworks(回到2.0)兼容,但需要Visual Studio 2015或更高版本

0

您应该只在属性本身的setter中提升OnPropertyChanged

一个清洁的实现您的视图模型可以是:

private Collection<string> _listOfStuff; 
private Collection<string> _filteredList; 

public Collection<string> FilteredList 
{ 
    get 
    {   
      return _filteredList; 
    } 
    set 
    { 
     if (value != _filteredList) 
     { 
      _filteredList = value; 
      OnPropertyChanged("FilteredList"); 
     } 
    } 
} 

private string _searchText; 
public string SearchText 
{ 
    get { return _searchText; } 
    set 
    { 
     if (value != _searchText) 
     { 
      _searchText = value; 
      OnPropertyChanged("SearchText"); 

      FilteredList = new Collection<string>(_listOfStuff.Where(x => x.Contains(SearchText))); 
     } 
    } 
} 
1

对于任何寻找此类问题的良好解决方案的人:请查看ReactiveUI

它是一个基于Reactive Extensions(Rx)的框架,其思想是明确地在属性之间建立这种类型的依赖关系,而没有RaisePropertyChanged(..)的丛林。

特别检查一下ObservableAsPropertyHelper(有时称为OAPH)。