C# 使用MVVM实现搜索功能
我正在将一个C#WPF应用程序转换为MVVM模式,我有几个问题: 我有一个ViewModel绑定到一个模型,该模型的构造函数要求参数是从返回到搜索查询的JSON列表中选择单个对象的结果。 我想这意味着在执行搜索之前,我无法实例化此ViewModel 这在以前不是一个问题,因为我不需要将视图数据绑定到ViewModel,只需要从GUI收集文本值来实例化对象(模型),当所有数据都已就绪并且我准备好使用它时 对于MVVM,这是一个问题,因为我不想强制此搜索成为第一个用户操作——用户应该能够修改GUI中绑定到ViewModel的任何字段 处理这种情况的一些实际方法是什么?似乎我必须这样做:a)在实例化VM之前等待选择搜索结果,或b)从构造函数中删除参数,而是创建一个将在实例化VM上调用的方法,以计算/设置构造函数将设置的属性 第二个问题:我如何实现搜索功能——也就是说,在单击搜索按钮后,我如何准备结果列表?之前,我将在SearchButton_Click方法中反序列化列表,并将组合框的绑定设置为结果集合。使用MVVM时,我无法描绘返回结果列表和选择单个结果之间的状态。我是否创建一个单独的ViewModel,其中包含绑定到组合框的空目标类型列表和绑定到搜索文本框的SearchTerm属性,并从SearchButton命令ICommand填充组合框?然后如何将所选项目绑定到原始viewmodel 视图模型:C# 使用MVVM实现搜索功能,c#,.net,wpf,mvvm,C#,.net,Wpf,Mvvm,我正在将一个C#WPF应用程序转换为MVVM模式,我有几个问题: 我有一个ViewModel绑定到一个模型,该模型的构造函数要求参数是从返回到搜索查询的JSON列表中选择单个对象的结果。 我想这意味着在执行搜索之前,我无法实例化此ViewModel 这在以前不是一个问题,因为我不需要将视图数据绑定到ViewModel,只需要从GUI收集文本值来实例化对象(模型),当所有数据都已就绪并且我准备好使用它时 对于MVVM,这是一个问题,因为我不想强制此搜索成为第一个用户操作——用户应该能够修改GUI中
class ObjectViewModel
{
public CustomObject data;
public ICommand Search;
public ObjectViewModel()
{
this.data = new CustomObject();
}
}
型号:
[DataContract]
public class User
{
[DataMember(Name = "EmailAddress")]
public string EmailAddress { get; set; }
[DataMember(Name = "FirstName")]
public string FirstName { get; set; }
[DataMember(Name = "FullName")]
public string FullName { get; set; }
...
}
[DataContract]
public class CustomObject
{
public User Owner;
...
}
视图(尚未重写):
OwnerLookUp_Click从Owner文本框中获取文本并返回ObservableCollection并将其绑定到OwnerMatch。OwnerMatches_SelectionChanged将Owner文本框设置为所选项目的Fullname属性
在这个场景中,我将绑定什么到ObjectViewModel中的data.Owner?好吧,您认为将参数移出构造函数是正确的。这是有意义的,因为您的VM应该表示备份视图的数据。因此,它应该有一个下拉菜单项列表、标签字符串等。当按下search时,您可以像在MVC中一样实际执行搜索并反序列化结果 要将其放到UI上,请将ComboBox绑定到视图模型上的一个属性(即列表)。反序列化完成后,您将分配给此列表。通过分配给这个变量,您将更新UI,瞧
public class MyViewModel : INotifyPropertyChanged
{
private ObservableCollection<string> _retrievedItems;
private string _selectedItem;
public ObservableCollection<string> RetrievedItems
{
get
{
return _retrievedItems;
}
set
{
_retrievedItems = value;
OnPropertychanged("RetrievedItems");
}
}
public string SelectedItem
{
// same as other property, but with _selectedItem
}
public MyViewModel()
{
// Do whatever you normally do to initialize the view model
}
public void Search(string searchParamThatWasInConstructor)
{
// do something to get results (deserialization)
// var results = new JavascriptSerializer( ).Deserialize<List<string>>( searchParamThatWasInConstructor );
// That's just a fake example
RetrievedItems = new ObservableCollection<string>(results);
SelectedItem = RetrievedItems.Count > 0 ? RetrievedItems[0] : string.Empty;
}
}
公共类MyViewModel:INotifyPropertyChanged
{
私人可观察收集的检索项目;
私有字符串_selectedItem;
公共可见收集检索的项目
{
得到
{
返回已检索的项目;
}
设置
{
_retrievedItems=值;
OnPropertychanged(“RetrievedItems”);
}
}
公共字符串SelectedItem
{
//与其他属性相同,但带有_selectedItem
}
公共MyViewModel()
{
//执行您通常执行的任何操作来初始化视图模型
}
public void Search(字符串searchParamthatUnconstructor)
{
//执行某些操作以获得结果(反序列化)
//var results=new JavascriptSerializer();
//那只是个假的例子
RetrievedItems=新的ObservableCollection(结果);
SelectedItem=RetrievedItems.Count>0?RetrievedItems[0]:string.Empty;
}
}
并按如下方式绑定您的组合框:
<ComboBox ItemsSource="{Binding RetrievedItems}" SelectedItem="{Binding SelectedItem}" />
视图模型应表示视图的业务逻辑和状态。因此,关于第一个问题,如果视图的有效状态是不进行搜索,那么它不应该是视图模型的构造函数参数。相反,它应该是一个财产 通常在WPF中,您会通过命令将按钮绑定到视图模型上某种类型的
ICommand
(我通常使用DelegateCommand
)。该命令应执行搜索,然后适当地更新视图模型的状态。也就是说,它应该执行搜索,收集结果,并使用收集的数据设置与搜索结果相关的属性值
这里的好处是,假设您有一些绑定到这些搜索结果的UI组件,只要您的命令完成,您的UI就会自动刷新,而不需要额外的代码
更新
回应您的评论:所有内容都应该绑定到您的视图模型,并且您的视图模型使用这些绑定来完成它需要的工作和更新视图
因此,您的文本框Owner
应绑定到属性,然后您的ICommand
将如下所示:
private void ClickCommandExecute()
{
var results = searchHelper.SearchFor(this.Owner);
this.ComboSource = results;
}
同样,组合框的SelectedValue
属性将绑定到视图模型上的另一个属性。在属性的setter中,可以对选择更改作出反应:
public string SelectedResult
{
get { ... }
set
{
_selectedResult = value;
OnSelectedResultChanged(); // Go do what you need to do here
}
}
哥们,太多的文字和没有样本代码。我不会通读这一切。顺便说一句,MVVM不是问题,非MVVM是。谢谢你的回复!我不认为这完全回答了我的第二个问题。用户必须从结果中选择一个项目——我认为这意味着我需要有两个命令并将列表存储在ViewModel中。请参阅用代码更新的问题。@Yevgeniy更新了我的答案谢谢!请参阅用代码更新的问题——我绑定到(在您的示例中)MyViewModel的哪个包含所选结果的UI控件?查看我发布的更新代码;这应该可以回答这个问题。
public string SelectedResult
{
get { ... }
set
{
_selectedResult = value;
OnSelectedResultChanged(); // Go do what you need to do here
}
}