65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (16投票s)

2010 年 9 月 5 日

Ms-PL

3分钟阅读

viewsIcon

59322

downloadIcon

359

该应用程序允许用户使用 Silverlight 通过动画显示查询集合。

一个简单的 Silverlight 配置器

实时示例

该应用程序允许用户通过下拉列表和滑块查询集合(通过 Web 服务)。结果会以动画显示。

您可能会问,为什么不直接使用 Microsoft Pivot?主要原因是

  • 这个应用程序使用了 视图模型/MVVM,因此用户界面可以 由设计师完全设计
  • 代码量不多,您可以快速将其改编用于您自己的用途。
  • 这个应用程序不侧重于图像。Microsoft Pivot 设计用于显示高质量图像。但是,您可以将其改编为显示图像。
  • 这是一个较小的应用程序,加载速度更快。
  • 该应用程序旨在直接从数据库获取数据。

如果以上情况不适用于您,您可能希望使用 Microsoft Pivot

应用程序

image

基本上,您选择性别、体重和年龄,符合所选条件的人就会以动画框的形式显示,并且它们会重新排序。

在 Adam Kinney 的帮助下

在我访问微软园区时发生了一件有趣的事。我遇到了 Adam Kinney(前微软传道者)。我告诉他我正在开发一个 Silverlight 配置器的想法,并询问他关于如何最好地显示数据的建议。他建议使用 Silverlight Wrap Panel 和 FluidMoveBehavior。他开始向我描述,我开始做笔记,然后他觉得我可怜,并且因为他有笔记本电脑,所以他编写了一些代码并将其通过电子邮件发送给我。

那些飞来飞去、淡入淡出的框来自他的示例。这一切都是通过无代码实现的,并且可以使用 **Microsoft Expression Blend** 轻松修改所有内容。

构建应用程序 – Web 应用程序

image

首先,我们创建一个 **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 应用程序

image

调用 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
    }

image

**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** 中完成,完全不需要编写代码。

image

**Expression Blend** 中的 **View** 看起来像这样: 

image

此图显示了什么绑定到什么

image

请注意,**Range Sliders** 来自 Josh Twist 发布的一篇文章。

延伸阅读

**Adam Kinney** 建议,如果您想了解他是如何实现动画列表的,请将以下 URL 转发给您

© . All rights reserved.