none
详解“MVVM”模式实例,以及对应疑问 RRS feed

  • 问题

  • 1.View

        <UserControl x:Class="MultiChartDemo.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"
    xmlns:local="clr-namespace:MultiChartDemo"

    问题一:“MultiChartDemo”命名空间的引入,是不是使该“命名空间”下所有的类都可以看得见,“MainPage”也只是其中一个子类???     在前台“XAML”中也可以引用后台“.cs”中的类,这样做是不是浪费资源???
    xmlns:vc="clr-namespace:Visifire.Charts;assembly=SLVisifire.Charts">
    <UserControl.DataContext >
            <local:MainPageViewModel />

    </UserControl.DataContext>

    问题二:“UserControl.DataContext”就是关联“View”和“ViewModel”之间的桥梁对吧???   这样“ViewModel”中的“实体集数据”就可以绑定到“View”了对吧???       但“增、删、改、查”这些事件应该怎样绑定呢,只是知道使用“Command”???绑定这些“Command”事件,是不是比“控件自带事件”消耗资源???
        <UserControl.Resources >
            <local:SeriesTemplateSelector x:Key="chartTemplateSelector">
    问题三:“SeriesTemplateSelector”是一个“.xaml.cs”后台类,为什么可以被前端“xaml”使用呢???     怎么回事???
                <local:SeriesTemplateSelector.SalesTemplate>
                    <DataTemplate >
                        <vc:DataSeries RenderAs="Line" LegendText="{Binding SalesName}" DataSource="{Binding SalesTotals}" >
                            <vc:DataSeries.DataMappings>
                                <vc:DataMapping MemberName="AxisXLabel" Path="Date"  ></vc:DataMapping>
                                <vc:DataMapping MemberName="YValue" Path="SalesTotal"  ></vc:DataMapping>
                            </vc:DataSeries.DataMappings>
                        </vc:DataSeries>
                    </DataTemplate>
                </local:SeriesTemplateSelector.SalesTemplate>

                <local:SeriesTemplateSelector.MedianTemplate>
                    <DataTemplate> 
                        <vc:DataSeries RenderAs="Column" LegendText="{Binding SalesName}" DataSource="{Binding SalesTotals}" >
                            <vc:DataSeries.DataMappings>
                                <vc:DataMapping MemberName="AxisXLabel" Path="Date"  ></vc:DataMapping>
                                <vc:DataMapping MemberName="YValue" Path="SalesTotal"  ></vc:DataMapping>
                            </vc:DataSeries.DataMappings>
                        </vc:DataSeries>
                    </DataTemplate>
                </local:SeriesTemplateSelector.MedianTemplate>

            </local:SeriesTemplateSelector>

        </UserControl.Resources>

        <Grid x:Name="LayoutRoot">

            <StackPanel Orientation="Vertical" >

                <!-- ======================================= 1st Chart ================================== -->

               <local:MultiChart    SeriesSource="{Binding SalesData}" Height="220" Width="400"  Margin="0,5,0,0">

    问题四:“public class MultiChart : Visifire.Charts.Chart”  ,“MultiChart”继承自第三方“Visifire”下“Chart”,为什么不直接使用“Visifire”下“Chart”,而是将其继承一下呢???这样做有什么好处???

                    <local:MultiChart.Titles>
                        <vc:Title Text="Dynamic Multi Lines"></vc:Title>
                    </local:MultiChart.Titles>

                    <local:MultiChart.SeriesTemplate >
                        <DataTemplate >

                            <vc:DataSeries RenderAs="Line" LegendText="{Binding SalesName}" DataSource="{Binding SalesTotals}">
                                <vc:DataSeries.DataMappings>
                                    <vc:DataMapping MemberName="AxisXLabel" Path="Date"  ></vc:DataMapping>
                                    <vc:DataMapping MemberName="YValue" Path="SalesTotal"  ></vc:DataMapping>
                                </vc:DataSeries.DataMappings>
                            </vc:DataSeries>

                        </DataTemplate>
                    </local:MultiChart.SeriesTemplate>

                </local:MultiChart>


            <!-- ======================================= 2nd Chart ================================== -->


                <local:MultiChart SeriesSource="{Binding SalesDataWithMedian}" SeriesTemplateSelector="{StaticResource chartTemplateSelector}" Height="220" Width="400" Margin="0,10,0,0">

                    <local:MultiChart.Titles>
                        <vc:Title Text="Dynamic Multi Lines with different DataTemplates"></vc:Title>
                    </local:MultiChart.Titles>

                </local:MultiChart>

            </StackPanel>
        </Grid>
    </UserControl>

    2.ViewModel(MainPageViewModel类ViewModelBase类)

             2.1MainPageViewModel类                             

    public class MainPageViewModel : ViewModelBase
        {

            #region Ctor

            public MainPageViewModel()
            {
                // start timer to update chart data for this example
                DispatcherTimer updateTimer = new DispatcherTimer();
                updateTimer.Tick += new EventHandler(updateTimer_Tick);
                updateTimer.Interval = TimeSpan.FromMilliseconds(3000);
                updateTimer.Start();
                UpdateData();

    问题五:是因为“UserControl.DataContext ”加载此“ViewModel”的时候就调用了此“构造方法”,然后执行“Updata()”对吧???    如果将“UpdateData()”方法绑定到前端按钮,应该怎样做???
            }

            #endregion

            #region Data to bind

            public List<SalesPerformance> SalesData
            {
                get { return base.GetValue(() => this.SalesData); }
                set { base.SetValue(() => this.SalesData, value); }

     问题六:“() => this.SalesData”这是什么写法,“()=>”是怎么回事???      为什么要将”ViewModel“分为”MainPageViewModel类ViewModelBase类“,这两个类???          为什么用“ViewModelBase类”来声明属性???

        }

            public List<SalesPerformance> SalesDataWithMedian
            {
                get { return base.GetValue(() => this.SalesDataWithMedian); }
                set { base.SetValue(() => this.SalesDataWithMedian, value); }
            }


            public SalesPerformance SalesDetail
            {
                get { return base.GetValue(() => this.SalesDetail); }
                set { base.SetValue(() => this.SalesDetail, value); }
            }

            #endregion

            #region Private metohds

            void updateTimer_Tick(object sender, EventArgs e)
            {
    UpdateData();
            }

            private void UpdateData()
            {
                // Fill SalesData
                List<SalesPerformance> salesData = new List<SalesPerformance>();
                SalesPerformance salesPerf = new SalesPerformance();
                salesPerf.SalesName = "Miller";
                salesPerf.SalesTotals = new List<SalesInfo>();
                salesPerf.SalesTotals.Add(new SalesInfo { Date = DateTime.Parse("11/30/2009").ToString("MMM"), SalesTotal = 20400 });
                salesPerf.SalesTotals.Add(new SalesInfo { Date = DateTime.Parse("12/31/2009").ToString("MMM"), SalesTotal = 21200 });
                salesData.Add(salesPerf);
                salesPerf = new SalesPerformance();
                salesPerf.SalesName = "Smith";
                salesPerf.SalesTotals = new List<SalesInfo>();
                salesPerf.SalesTotals.Add(new SalesInfo { Date = DateTime.Parse("11/30/2009").ToString("MMM"), SalesTotal = 21200 });
                salesPerf.SalesTotals.Add(new SalesInfo { Date = DateTime.Parse("12/30/2009").ToString("MMM"), SalesTotal = 16500 });
                salesData.Add(salesPerf);
                salesPerf = new SalesPerformance();
                salesPerf.SalesName = "James";
                salesPerf.SalesTotals = new List<SalesInfo>();
                salesPerf.SalesTotals.Add(new SalesInfo { Date = DateTime.Parse("01/31/2009").ToString("MMM"), SalesTotal = 17000 });
                salesPerf.SalesTotals.Add(new SalesInfo { Date = DateTime.Parse("02/28/2009").ToString("MMM"), SalesTotal = 16000 });
                salesData.Add(salesPerf);
            }

          2.2 “ViewModelBase类”

           问题七:除了实现“INotifyPropertyChanged”接口,“ViewModelBase类”还有其它什么作用???

            

    public abstract class ViewModelBase : INotifyPropertyChanged
        {

            private Dictionary<string, object> values;

            public ViewModelBase()
            {
                this.values = new Dictionary<string, object>();
            }

            #region INotifyPropertyChanged Members

            /// <summary>
            /// Occurs when a property value changes.
            /// </summary>
            public event PropertyChangedEventHandler PropertyChanged;

            /// <summary>
            /// Called when [property changed].
            /// </summary>
            /// <param name="propertyName">Name of the property.</param>
            protected void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }

            #endregion

            // Unfortunately, C# currently does not support property delegates, in other words, a reference to a property. 
    private string GetPropertyName(LambdaExpression lambda)
            {
                MemberExpression memberExpression;

                问题八:“GetPropertyName”着个方法的作用是什么???好像没用到啊???
                if (lambda.Body is UnaryExpression)
                {
                    var unaryExpression = lambda.Body as UnaryExpression;
                    memberExpression = unaryExpression.Operand as MemberExpression;
                }
                else
                {
                    memberExpression = lambda.Body as MemberExpression;
                }
                var constantExpression = memberExpression.Expression as ConstantExpression;
                var propertyInfo = memberExpression.Member as PropertyInfo;
                return propertyInfo.Name;
            }

            protected void SetValue<T>(Expression<Func<T>> property, T value)
            {

                LambdaExpression lambda = property as LambdaExpression;

                if (lambda == null)
                    throw new ArgumentException("Invalid view model property definition.");

                string propertyName = this.GetPropertyName(lambda);

                T existingValue = GetValueInternal<T>(propertyName);

                if (!object.Equals(existingValue, value))
                {
                    this.values[propertyName] = value;
                    this.OnPropertyChanged(propertyName);
                }
            }

            protected T GetValue<T>(Expression<Func<T>> property)
            {
                LambdaExpression lambda = property as LambdaExpression;

                if (lambda == null)
                    throw new ArgumentException("Invalid view model property definition.");

                string propertyName = this.GetPropertyName(lambda);

                return GetValueInternal<T>(propertyName);

            }

            private T GetValueInternal<T>(string propertyName)
            {
                object value;
                if (values.TryGetValue(propertyName, out value))
                    return (T)value;
                else
                    return default(T);
            }
        }                                


    Science and technology is my lover.


    2012年5月17日 5:45

答案

  • 你好,

    首先非常建议您下次可以保持每个帖子一个问题,并且给一个明确的题目,这样可以大大帮助助于后人更容易的搜索到自己感兴趣的问题。

    1. 如果你想一个命名空间只针对一个类的话,可以考虑将这个类放到一个独立的文件夹中,然后设定命名空间为

    xmlns:local="clr-namespace:MultiChartDemo.FolderName"

    2.“控件自带事件”你指比如DataForm中的增删改查功能么?如果项目适合直接使用DataForm,使用内置的功能要比自己再定义节省资源。但是如果内置功能不适合你的项目也只能自己定义了。如果自定义就要是绑定command 或者eventtrigger。

    3.可以把SeriesTemplateSelector理解为一个silverlight usercontrol,被添加到另外一个xaml中。

    4.这个问题涉及第三方控件的设计问题,建议到其官方论坛询问。

    5.是的。绑定update方法到前段和第二个问题中绑定command或者eventhandler是一样的。将update定义为一个实现ICommand接口的类别,然后绑定。

    http://www.cnblogs.com/webabcd/archive/2010/09/13/1824683.html

    6&7,()=>这个是c# lambda表达式,比如 base.GetValue(() => this.SalesData); 代表base.GetValue传入的参数为delegate类型。具体的可以参看baseclass中GetValue是怎么定义的。

    http://msdn.microsoft.com/en-us/library/bb397687.aspx

    一般来说ViewModelBase中都是一个实现INotifyPropertyChanged接口的一个类,实现这个接口可以让后台数据变化值自动更新到UI。因为每个ViewModel都需要这个接口,方便起见就创建一个积累,让其他ViewModel继承。

    8.如果搜索一下GetPropertyName关键字不难发现这个方法在GetValue SetValue中被用到了。因为GetValue SetValue以委托作为传入参数,隐去了参数的类型,所以这里需要解析一下lambda表达式,获取当前传入参数的类型。

    • 已标记为答案 Shi Ding 2012年5月24日 9:52
    2012年5月18日 9:39

全部回复

  • 你好,

    首先非常建议您下次可以保持每个帖子一个问题,并且给一个明确的题目,这样可以大大帮助助于后人更容易的搜索到自己感兴趣的问题。

    1. 如果你想一个命名空间只针对一个类的话,可以考虑将这个类放到一个独立的文件夹中,然后设定命名空间为

    xmlns:local="clr-namespace:MultiChartDemo.FolderName"

    2.“控件自带事件”你指比如DataForm中的增删改查功能么?如果项目适合直接使用DataForm,使用内置的功能要比自己再定义节省资源。但是如果内置功能不适合你的项目也只能自己定义了。如果自定义就要是绑定command 或者eventtrigger。

    3.可以把SeriesTemplateSelector理解为一个silverlight usercontrol,被添加到另外一个xaml中。

    4.这个问题涉及第三方控件的设计问题,建议到其官方论坛询问。

    5.是的。绑定update方法到前段和第二个问题中绑定command或者eventhandler是一样的。将update定义为一个实现ICommand接口的类别,然后绑定。

    http://www.cnblogs.com/webabcd/archive/2010/09/13/1824683.html

    6&7,()=>这个是c# lambda表达式,比如 base.GetValue(() => this.SalesData); 代表base.GetValue传入的参数为delegate类型。具体的可以参看baseclass中GetValue是怎么定义的。

    http://msdn.microsoft.com/en-us/library/bb397687.aspx

    一般来说ViewModelBase中都是一个实现INotifyPropertyChanged接口的一个类,实现这个接口可以让后台数据变化值自动更新到UI。因为每个ViewModel都需要这个接口,方便起见就创建一个积累,让其他ViewModel继承。

    8.如果搜索一下GetPropertyName关键字不难发现这个方法在GetValue SetValue中被用到了。因为GetValue SetValue以委托作为传入参数,隐去了参数的类型,所以这里需要解析一下lambda表达式,获取当前传入参数的类型。

    • 已标记为答案 Shi Ding 2012年5月24日 9:52
    2012年5月18日 9:39
  • 你好,

    首先非常建议您下次可以保持每个帖子一个问题,并且给一个明确的题目,这样可以大大帮助助于后人更容易的搜索到自己感兴趣的问题。

    1. 如果你想一个命名空间只针对一个类的话,可以考虑将这个类放到一个独立的文件夹中,然后设定命名空间为

    xmlns:local="clr-namespace:MultiChartDemo.FolderName"

    2.“控件自带事件”你指比如DataForm中的增删改查功能么?如果项目适合直接使用DataForm,使用内置的功能要比自己再定义节省资源。但是如果内置功能不适合你的项目也只能自己定义了。如果自定义就要是绑定command 或者eventtrigger。

    3.可以把SeriesTemplateSelector理解为一个silverlight usercontrol,被添加到另外一个xaml中。

    4.这个问题涉及第三方控件的设计问题,建议到其官方论坛询问。

    5.是的。绑定update方法到前段和第二个问题中绑定command或者eventhandler是一样的。将update定义为一个实现ICommand接口的类别,然后绑定。

    http://www.cnblogs.com/webabcd/archive/2010/09/13/1824683.html

    6&7,()=>这个是c# lambda表达式,比如 base.GetValue(() => this.SalesData); 代表base.GetValue传入的参数为delegate类型。具体的可以参看baseclass中GetValue是怎么定义的。

    http://msdn.microsoft.com/en-us/library/bb397687.aspx

    一般来说ViewModelBase中都是一个实现INotifyPropertyChanged接口的一个类,实现这个接口可以让后台数据变化值自动更新到UI。因为每个ViewModel都需要这个接口,方便起见就创建一个积累,让其他ViewModel继承。

    8.如果搜索一下GetPropertyName关键字不难发现这个方法在GetValue SetValue中被用到了。因为GetValue SetValue以委托作为传入参数,隐去了参数的类型,所以这里需要解析一下lambda表达式,获取当前传入参数的类型。

    谢谢,虽然不是不很解,但是知道自己要补充的知识了,这些不是问就能问的出来滴。

    Science and technology is my lover.

    2012年5月21日 2:09