简单 Silverlight 配置器/透视 (视图模型/MVVM)






4.88/5 (16投票s)
该应用程序允许用户使用 Silverlight 通过动画显示查询集合。
一个简单的 Silverlight 配置器
实时示例
该应用程序允许用户通过下拉列表和滑块查询集合(通过 Web 服务)。结果会以动画显示。
您可能会问,为什么不直接使用 Microsoft Pivot?主要原因是
- 这个应用程序使用了 视图模型/MVVM,因此用户界面可以 由设计师完全设计。
- 代码量不多,您可以快速将其改编用于您自己的用途。
- 这个应用程序不侧重于图像。Microsoft Pivot 设计用于显示高质量图像。但是,您可以将其改编为显示图像。
- 这是一个较小的应用程序,加载速度更快。
- 该应用程序旨在直接从数据库获取数据。
如果以上情况不适用于您,您可能希望使用 Microsoft Pivot。
应用程序
基本上,您选择性别、体重和年龄,符合所选条件的人就会以动画框的形式显示,并且它们会重新排序。
在 Adam Kinney 的帮助下
在我访问微软园区时发生了一件有趣的事。我遇到了 Adam Kinney(前微软传道者)。我告诉他我正在开发一个 Silverlight 配置器的想法,并询问他关于如何最好地显示数据的建议。他建议使用 Silverlight Wrap Panel 和 FluidMoveBehavior。他开始向我描述,我开始做笔记,然后他觉得我可怜,并且因为他有笔记本电脑,所以他编写了一些代码并将其通过电子邮件发送给我。
那些飞来飞去、淡入淡出的框来自他的示例。这一切都是通过无代码实现的,并且可以使用 **Microsoft Expression Blend** 轻松修改所有内容。
构建应用程序 – Web 应用程序
首先,我们创建一个 **People** 集合
public static class People { public static List<Person> GetPeople() { List<Person> colPeople = new List<Person>(); colPeople.Add(new Person { Name = "Tom", Description = "Cook", Age = 44, Weight = 224, Gender = "M" }); colPeople.Add(new Person { Name = "Mary", Description = "Taxi Driver", Age = 22, Weight = 114, Gender = "F" }); colPeople.Add(new Person { Name = "Jane", Description = "Nurse", Age = 28, Weight = 109, Gender = "F" }); colPeople.Add(new Person { Name = "Lex", Description = "Doctor", Age = 51, Weight = 194, Gender = "M" }); colPeople.Add(new Person { Name = "Paul", Description = "Saleman", Age = 23, Weight = 208, Gender = "M" }); colPeople.Add(new Person { Name = "Frank", Description = "Butler", Age = 32, Weight = 184, Gender = "M" }); colPeople.Add(new Person { Name = "Joe", Description = "Programmer", Age = 30, Weight = 290, Gender = "M" }); colPeople.Add(new Person { Name = "John", Description = "Clerk", Age = 25, Weight = 202, Gender = "M" }); colPeople.Add(new Person { Name = "Mark", Description = "Student", Age = 14, Weight = 102, Gender = "M" }); colPeople.Add(new Person { Name = "Paula", Description = "Student", Age = 12, Weight = 98, Gender = "F" }); colPeople.Add(new Person { Name = "Beth", Description = "Student", Age = 18, Weight = 119, Gender = "F" }); colPeople.Add(new Person { Name = "Jack", Description = "Butcher", Age = 31, Weight = 114, Gender = "M" }); colPeople.Add(new Person { Name = "Bob", Description = "Student", Age = 13, Weight = 114, Gender = "M" }); colPeople.Add(new Person { Name = "Robert", Description = "Student", Age = 12, Weight = 99, Gender = "M" }); colPeople.Add(new Person { Name = "Tony", Description = "Student", Age = 10, Weight = 105, Gender = "M" }); colPeople.Add(new Person { Name = "Ray", Description = "Lawyer", Age = 35, Weight = 212, Gender = "M" }); return colPeople; } }
接下来,我们创建一个 Web 服务来查询此集合
public class WebService : System.Web.Services.WebService { [WebMethod] public List<Person> SearchPeople(string Gender, int AgeHigh, int AgeLow, int WeightHigh, int WeightLow) { List<Person> colPeople = new List<Person>(); var result = from objPeople in People.GetPeople().AsQueryable() where objPeople.Age <= AgeHigh where objPeople.Age >= AgeLow where objPeople.Weight <= WeightHigh where objPeople.Weight >= WeightLow select objPeople; if (Gender != "All") { colPeople = (from finalresult in result where finalresult.Gender == Gender select finalresult).ToList(); } else { colPeople = result.ToList(); } return colPeople; } }
请注意,这里您可以让您的 Web 服务简单地连接到您的数据库。
就是这样!希望您到目前为止觉得这一切都很容易,并且可以看到如何轻松地修改它来获取您自己的数据。
构建应用程序 – Silverlight 应用程序
调用 Web 服务的 **Model** 非常简单
public class Model { #region SearchPeople public static void SearchPeople(string Gender, int AgeHigh, int AgeLow, int WeightHigh, int WeightLow, EventHandler<SearchPeopleCompletedEventArgs> eh) { // Set up web service call WebServiceSoapClient WS = new WebServiceSoapClient(); // Set the EndpointAddress WS.Endpoint.Address = new EndpointAddress(GetBaseAddress()); WS.SearchPeopleCompleted += eh; WS.SearchPeopleAsync(Gender, AgeHigh, AgeLow, WeightHigh, WeightLow); } #endregion // Utility #region GetBaseAddress private static Uri GetBaseAddress() { // Get the web address of the .xap that launched this application string strBaseWebAddress = App.Current.Host.Source.AbsoluteUri; // Find the position of the ClientBin directory int PositionOfClientBin = App.Current.Host.Source.AbsoluteUri.ToLower().IndexOf(@"/clientbin"); // Strip off everything after the ClientBin directory strBaseWebAddress = Strings.Left(strBaseWebAddress, PositionOfClientBin); // Create a URI Uri UriWebService = new Uri(String.Format(@"{0}/WebService.asmx", strBaseWebAddress)); // Return the base address return UriWebService; } #endregion }
**View Model** 包含应用程序的所有逻辑。希望这能展示 **View Model / MVVM** 风格编程的强大功能,以及如何比使用代码隐藏进行编码时使用 *更少* 的代码。
首先,我们创建一个属性来保存主集合。这个集合是 Adam Kinney 的代码唯一关注的对象。应用程序中所有其他代码都只是在更改这个集合
#region ColPeople private ObservableCollection<Person> _ColPeople = new ObservableCollection<Person>(); public ObservableCollection<Person> ColPeople { get { return _ColPeople; } private set { if (ColPeople == value) { return; } _ColPeople = value; this.NotifyPropertyChanged("ColPeople"); } } #endregion
接下来,我们有属性来保存其他参数。这些参数是 **滑块** 和 **组合框** 绑定的对象
#region AgeLow private int _AgeLow = 10; public int AgeLow { get { return _AgeLow; } set { if (AgeLow == value) { return; } _AgeLow = value; this.NotifyPropertyChanged("AgeLow"); } } #endregion #region AgeHigh private int _AgeHigh = 100; public int AgeHigh { get { return _AgeHigh; } set { if (AgeHigh == value) { return; } _AgeHigh = value; this.NotifyPropertyChanged("AgeHigh"); } } #endregion #region WeightLow private int _WeightLow = 90; public int WeightLow { get { return _WeightLow; } set { if (WeightLow == value) { return; } _WeightLow = value; this.NotifyPropertyChanged("WeightLow"); } } #endregion #region WeightHigh private int _WeightHigh = 300; public int WeightHigh { get { return _WeightHigh; } set { if (WeightHigh == value) { return; } _WeightHigh = value; this.NotifyPropertyChanged("WeightHigh"); } } #endregion #region Gender private string _Gender = "All"; public string Gender { get { return _Gender; } set { if (Gender == value) { return; } _Gender = value; this.NotifyPropertyChanged("Gender"); } } #endregion
现在,对于 *复杂* 的部分(实际上并不复杂,这就是我的观点)。这是调用 **Model** 的方法。请注意,它不接受参数,它只是将当前设置的各种属性的值传递给 **Model**
#region GetPeopleFromModel private void GetPeopleFromModel() { // Call the Model to get People Model.SearchPeople(Gender, AgeHigh, AgeLow, WeightHigh, WeightLow, (Param, EventArgs) => { if (EventArgs.Error == null) { // Remove people who are not part of the recent query var DeletedPeople = (from people in ColPeople where !EventArgs.Result.Select(x => x.Name).Contains(people.Name) select people).ToList(); // loop thru each item foreach (var Person in DeletedPeople) { // Add to the colTasks collection ColPeople.Remove(Person); } // Add people that are not part of ColPeople var NewPeople = from people in EventArgs.Result where !ColPeople.Select(x => x.Name).Contains(people.Name) select people; // loop thru each item foreach (var Person in NewPeople) { // Add to the colTasks collection ColPeople.Add(Person); } } }); } #endregion
这个类实现了 **INotifyPropertyChanged**,因此我们使用此方法在属性更改时调用 **GetPeopleFromModel()** 方法
#region MainPageModel_PropertyChanged void MainPageModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { if ( e.PropertyName == "AgeLow" || e.PropertyName == "AgeHigh" || e.PropertyName == "WeightLow" || e.PropertyName == "WeightHigh" || e.PropertyName == "Gender") { GetPeopleFromModel(); } } #endregion
就是这样!
如果您不习惯 **视图模型风格** 编程,您可能会想:“像年龄和体重这样的属性是如何设置的?” 答案是,我们将在 **View** 中将控件绑定到这些属性。所有这些都在 **Microsoft Expression Blend** 中完成,完全不需要编写代码。
**Expression Blend** 中的 **View** 看起来像这样:
此图显示了什么绑定到什么
请注意,**Range Sliders** 来自 Josh Twist 发布的一篇文章。
延伸阅读
**Adam Kinney** 建议,如果您想了解他是如何实现动画列表的,请将以下 URL 转发给您