最近我一直在学习C#和WPF的工作。我试图在我正在进行的项目中使用MVVM,只是为了保持代码的组织并了解它是如何工作的。
在MVVM中,View上的控件绑定到ViewModel上的属性,后者实现了INotifyPropertyChanged。通常,当某个属性更新时,我会希望其他一些属性得到更新。
例如,我有一个ListBox,上面有一个TextBox。您可以键入TextBox,它会过滤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 :(得分:1)
首先,您不应该在命令中执行可能代价高昂的操作,然后您就可以从OnPropertyChanged("FilteredList");
中删除SearchText
。
因此,您应该将该代码从getter移动到它自己的命令中并将其绑定到XAML(作为按钮上的Command或使用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或更高版本
答案 1 :(得分:1)
一年前我在一个项目上尝试过Assisticant。它确定了哪些属性需要提出通知以及哪些属性相关。 Pluralsight上有一个很好的课程,网站上的例子非常好。如果没有别的,你可以查看源代码,看看他是如何做到的。
来自Change Notification in MVVM Hierarchies的一些好建议。
他们提到:
使用属性 - &gt;例如[DependsUpon(nameof(尺寸))]
和
Josh Smith的PropertyObserver
如果您只是需要每次都提出相同的通知,可以将raise属性更改调用放在方法中。
答案 2 :(得分:1)
对于寻找这类问题的良好解决方案的任何人:查看ReactiveUI。
这是一个基于Reactive Extensions(Rx)的框架,其理念是您可以明确地在属性之间建模这种类型的依赖关系,而不需要RaisePropertyChanged(..)
的丛林。
具体检查ObservableAsPropertyHelper(有时称为OAPH)。
答案 3 :(得分:0)
你应该只在房产本身的设定者中提出OnPropertyChanged
。
ViewModel的更清晰的实现可以是:
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)));
}
}
}
答案 4 :(得分:-2)
如果你只是不想键入其他选项就是为所有属性触发OnPropertyChanged,这可以通过传递null或string.Empty来完成,虽然它会是更粗略的代码!
kubectl exec
或
OnPropertyChanged(Null);