• MVC和MVVM杂谈


    代码不仅仅是一种技术,更是一种艺术,在艺术的领域中有了自己的设计模式,有了自己的框架……,任何东西都不是与生俱来的,而是随着人们的认识慢慢发现和总结,大脑的思维就在于此,可以发现规律和总结规律。

    MVC和MVVM这两种模式对于NET下的开发者应该不会陌生,关于这两个我在以前的博客中介绍过,今天心血来潮,自己一个个的模拟下,纸上得来终觉浅,绝知此事要躬行,就我这破脑子,看过的东西,很快就被忘记,愚人自有愚人的办法。

    刚开始的时候,我们写程序,对于NET的开发人员来说,都是在一个事件下面完成一个一个任务的,比如下面的操作:

     private void Button_Click(object sender, RoutedEventArgs e)
            {
    
    string pName = Convert.ToDouble(textBox1.Text);
                   
    Double B
    = Convert.ToDouble(textBox2.Text);

    // 省略
    //在这里对A和B进行操作,如果对Name,B换一种操作,那么必须进入视图这里操作


    }

    这样有一个好处就是代码很容易阅读,逻辑也很清楚,但是对于大的项目来说,这个缺点就很明显,业务和视图耦合的太紧密,我们知道写程序有一个目的就是解耦,所以上面这个必须改动,那么这个时候我们需要将业务处理逻辑和视图分开来写,在视图中声明一个事件或者委托变量,然后在需要的进行处理的类中进行绑定,如下:

      public event ClickEventHandler SendClick;
              
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                if (SendClick != null)
                {
                    MyArgs pArgs = new MyArgs();
                    pArgs.Name= textBox1.Text;
                    pArgs.B = Convert.ToDouble(textBox2.Text);
                    //A和B的操作在另外的类中,这样的好处,对于A,B可以有不同的操作,SendClick预先不知道自己如何对Name,B操作,如果要换一种操作,直接在绑定的类中进行修改,而不是在视图中修改,相比上面的,这里的优势不言而喻。
    SendClick(
    this, pArgs); } }

    如果是视图是程序的外观或者外衣,那么数据就是这个程序的血液,没有血液的程序还能有什么用么?视图的目的就是为了显示数据,而如何显示数据,这个就好比人的神经中枢,控制着人的一切,通着类似,程序中应该有一个控制器,所以我们将程序中所使用的数据完完全全的放在一个类中,称之为数据模型,好比下面这个一样:

    class Persons
        {
            List<Person> persList = new List<Person>();
    
            public Persons()
            {
                persList.Add(new Person("刘宇", 25));
                persList.Add(new Person("刘宇1", 25));
                persList.Add(new Person("刘宇2", 25));
            }
            public List<Person>  GetPersons()
            {
                return persList;
            }
        }

    数据和视图都有了,控制器将这两者联系起来:

      public controller()
           {
               if (m_MVC == null)
               {
                   m_MVC = new MVC(); //这是我们的视图
                   m_MVC.SendClick += new ClickEventHandler(m_MVC_SendClick);
               }
               datamodel = new Persons().GetPersons();//这是我们的数据
           }
    
            void m_MVC_SendClick(object sender, MyArgs e)
            {
    
    string sName=e.Name;

    //这里对数据进行操作,这里我做了一个查找

              List<Person> pPersonsTest;
                if (!string.IsNullOrEmpty(sName))
                {
                    pPersonsTest = new List<Person>();

    
    

                    foreach (var p in pPersons)
                    {
                        if (p.Name == sName)
                            pPersonsTest.Add(p);

                       //有了结果,可以在视图上显示,省略。

                       
                    }

    
    

                }

    
            }

    上面这个就算是一个MVC结构的小程序,数据和视图分开了,控制器用来对请求进行处理。

    在MVVM中,这个可以进一步通过ICommand和绑定简化。

    在视图中,我们也不需要对事件进行处理,也就是没有了Button_Click这样的方法,取之而来的是:


    <Button Command="{Binding pCmd}" CommandParameter="{Binding ElementName=txtName, Path=Text}" Height="64" Grid.ColumnSpan="2" Grid.Row="1" Content="查找"></Button>

     public partial class View : UserControl
        {
           ViewModel  PVM= new ViewModel();
            public View()
            {
                InitializeComponent();
                this.DataContext = PVM;
            }

               }

    这里出现了ViewModel,这个ViewModel实现了INotifyPropertyChanged接口,要不然怎么实现变更通知,这里有一个疑惑我没搞清楚,就是这个PropertyChanged事件是在什么时候赋值的,这个可能是系统实现的。

    class ViewModel : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;//
    
            private string _str;
    
           // private View _View;
    
            public string Str
            {
                get { return _str; }
                set
                {
                    _str = value;
                    if (PropertyChanged != null)
                    {
                        this.PropertyChanged(this, new PropertyChangedEventArgs(Str));
                    }//封装在一个函数里面
                }
            }
            
            //View pView 在MVC中传入视图可以用来更新数据,但是在MVVM中通过绑定。
            public ViewModel()
            {
                
                pPersons = new Persons().GetPersons();
    
                pCmd = new MyCommand(search) { ISbool = true };
    
                
    
            }
    
            public ICommand pCmd { get; set; }
            public List<Person> pPersons;
            void search(string sName)
            {
                List<Person> pPersonsTest;
                if (!string.IsNullOrEmpty(sName))
                {
                    pPersonsTest = new List<Person>();
    
                    foreach (var p in pPersons)
                    {
                        if (p.Name == sName)
                            pPersonsTest.Add(p);
    
                        
                    }
    
                }
            }
        }

    在ViewModel中有一个pCmd这个参数,这个是被绑定到按钮上的,当按钮接受到这个命令后,就会执行查询操作,代码如下:

     class MyCommand:ICommand
        {
           public delegate void handler(string sName) ;
           handler _handler;
            public bool ISbool{get;set;}
    
            public MyCommand(handler pHandler)
            {
                this._handler = pHandler;
                
            }
    
            public event EventHandler CanExecuteChanged;
            public bool CanExecute(object parameter)
            {
               
                return true;
                
             
            }
    
    
            public void Execute(object parameter)
            {
                if (!String.IsNullOrEmpty(parameter.ToString()))
                {
                    if (CanExecuteChanged!=null)
                    {
                        _handler(parameter.ToString());
                    }
                }
            }
        }

    对于这个CanExecuteChanged这个事件是什么时候有值的,我也不清楚,这个先放到这里暂且不管,在命令里其实也是通过回调函数来执行ViewModel中的方法,委托在这里着实起了很大的作用。在写程序的时候,主界面我们经常是布局,然后将试图作为用户控件,最后添加到主窗体中,在MVVM中,只需要在主窗体中声明试图,然后放到指定的位置即可:

     xmlns:local="clr-namespace:WpfMVVM"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <StackPanel>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition></ColumnDefinition>
                        <ColumnDefinition></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <local:View Grid.Column="1" Grid.Row="0"></local:View>
    
                               </Grid>
               
              
            </StackPanel>
            
        </Grid>

    总算将这个写完了,但是对于这两个事件变量的值,我只是能跟踪到其有值,但是却不知道在哪里给赋值的?还望大家告知答案。

    技术这个玩意,要深刻的体会,要深入的应用,这样才可能有出奇制胜的可能,在工作中也就有了事半功倍这个说法,其实上面讨论的很大程度上都是依靠委托,委托允许声明和实现的分离(其实接口也是可以的)。

  • 相关阅读:
    java中CyclicBarrier的使用
    java并发中CountDownLatch的使用
    java中Locks的使用
    java 中的fork join框架
    java中ThreadPool的介绍和使用
    java中的daemon thread
    java中interrupt,interrupted和isInterrupted的区别
    java中的Atomic类
    怎么在java中关闭一个thread
    java中join的使用
  • 原文地址:https://www.cnblogs.com/zuiyirenjian/p/3127760.html
Copyright © 2020-2023  润新知