نمایش نتایج 1 تا 1 از 1

نام تاپیک: سئوال درباره Command

  1. #1

    سئوال درباره Command

    سلام دوستان .

    مطالبی که در زیر میگم ، هر چند تحقیق کردم اما 100 درصد مطمئن نیستم که درست باشه . دوستان لطفا راهنمایی کنن که این مطالب ، درست هست یا کجاها نادرست هست؟ :

    یک جریان ، قضیه ی معماری MVVM هست و قضیه ی دیگه ، بالا بردن ماژولاریتی (Modular) و همچنین رعایت اصول Solid در طراحی نرم افزار و لایه ها .

    در معماری MVVM ، فقط کافی هست که 3 لایه ی View و ViewModel و Model داشته باشیم اما ارتباط بین لایه های View و ViewModel ، چه توسط Command ها برقرار بشه ، یا نشه و بجاش توسط فراخوانیِ معمولیِ متدها انجام بشه ، معماری MVVM را نقض نمیکنه .
    در واقع در MVVM ، مهم اینه که اون 3 لایه وجود داشته باشند و هر کدوم وظایف خودشون را انجام بدن .

    به همین دلیل ، در MVVM ، وقتی حتی از Command ها هم استفاده نکنیم ، یا حتی اگه دسترسی مستقیم به اعضا و پروپرتی هایی که درون کلاس های ViewModel مون تعریف کردیم (از درون کلاس های View مون) داشته باشیم ، باعث نقض معماری MVVM نمیشه .

    ================


    اما قضیه ی دوم ، اینه که قابلیت ماژولار بودن برنامه مون را بالا ببریم و همچنین اصول Solid (مخصوصا اصل Dependency Inversion Principle) را رعایت کنیم تا قابلیت نگه داری و تست کدمون را افزایش بدیم و مخصوصا اینکه اساسا معماری MVVM ، برای همین منظور طراحی شد (یعنی برای این طراحی شد که قابلیت نگه داری و تست کدمون را افزایش بده) ، به همین جهت ، خیلی در این معماری توصیه میشه که برای ارتباط بین لایه های View و ViewModel ، از Binding و Command استفاده کنیم . چرا؟

    چون Command ها ، رابط و اینترفیسِ ICommand دارند و ارتباط باهاشون وقتی با رابط و اینترفیس انجام بشه ، اصل Dependency Inversion Principle در Solid را رعایت کرده و ماژولار بودن و قابلیت نگه داری و تست کد را به این ترتیب ، افزایش داده .
    درست میگم؟

    حالا میگم برای افزایش این بهره وری و افزایش قابلیت نگه داری کد ، مثل اغلب لایه های دیگه که با اینترفیس با هم در ارتباط هستند ، برای لایه ی ViewModel مون هم یه اینترفیس درست کنیم که اعضایی که نیاز به ارتباط برقرار کردن باهاشون داریم مثل پروپرتی ای از نوع ICommand و احیانا رویدادی که اگه نیاز شد ، پیغام ها (شامل موفقیت آمیز بودن یا ارورها) را به لایه ی View برای نمایش دادن ، منتقل کنه ، و لایه ی View ، فقط با این اینترفیس از ViewModel در ارتباط باشه (مستقیما با کلاس ها و اعضاش ارتباط نداشته باشه) (و این اینترفیس ، از این دست اعضا داشته باشه تا کلاسی که این را پیاده سازی میکنن ، هر کلاسی بتونن باشن و هر عضوی بتونن داشته باشن) . تا باعث بشه اصل DIP در Solid بیشتر رعایت بشه .

    مثل کد زیر :


    // ViewModel Layer


    public interface IStudentViewModel
    {
    event EventHandler NotifyToViewEvent;

    ICommand GetStudentCommand{get;set;}
    }




    public class StudentViewModel : IStudentViewModel
    {
    public event EventHandler NotifyToViewEvent;

    public ICommand GetStudentCommand{get;set;}

    public StudentViewModel()
    {
    this.GetStudentCommand = new DelegateCommand(this.GetStudentExecute);
    }

    private void GetStudentExecute()
    {
    this.NotifyToViewEvent?.Invoke(this, new EventArgs());
    }
    }


    // View Layer


    public class MyWindow : Window
    {
    private IStudentViewModel myStudentViewModel;

    public MyWindow()
    {
    InitializeComponent();

    this.myStudentViewModel = new StudentViewModel();
    this.myStudentViewModel.NotifyToViewEvent += this.NotifyViewModelHandler;

    this.DataContext = this.myStudentViewModel;
    }

    private void NotifyViewModelHandler(object sender, EventArgs e)
    {
    MessageBox.Show(e.ToString());
    }
    }


    و در xaml :


    <Button Content="Get Student" Command="{Binding Path = GetStudentCommand}"/>


    اما همچین ساختاری را خیلی جای کمی دیدم و نمیدونم مرسوم هست یا کلا روال غیر عادی که نیست دیگه؟ به نظر خودم درسته .
    برای بهتر کردن کد هم میشه از الگوی طراحی Factory Method یا Service Locator استفاده کرد .

    رویداد NotifyToViewEvent هم در کد بالا ، تقریبا فقط میشه گفت همین یک رویداد کافی هست تا همه ی متدهایی که Command ها را اجرا میکنن ، این رویداد را فراخوانی کنن . یعنی همین رویداد ، به ازای همه ی Command کافی هست چون فقط وظیفه ی انتقال هر نوع پیغام از هر Command ای را داره .

    =======


    بنابراین حتی با رعایت اصول Solid در MVVM هم اشکالی نداره که در کد سی شارپ ، لایه ی View و ViewModel با هم ارتباط داشته باشند :

    Simplifying the WPF TreeView by Using the ViewModel Pattern - CodeProject

    البته در لینک بالا ، چون شیِ _familyTree اش در کلاس TextSearchDemoControl ، از نوع کلاس هست (و از نوع اینترفیس یا کلاس abstract نیست) ، اصل DIP در Solid را نقض میکنه .

    ======


    بنابراین هیچ مشکلی نداره که یک Command مون را از توی یک رویداد عادی اجرا کنیم . یعنی بجای Command ، یک رویداد عادی برای کنترل مون درست کنیم و Command ای که در لایه ی ViewModel درست کردیم را از توی View ، فراخوانی کنیم .

    این ، به درد جایی میخوره که فرضا بخشی از کدمون در لایه ی View و بخشی هم در لایه ی ViewModel وجود داشته باشه . یعنی مثلا بخوایم یه Dialog ای را برای انتخاب فایل باز کنیم (که این تیکه مربوط به وظایف لایه ی View هست) و بعد از اون ، یک متدی را از Model فراخوانی کنیم که باید برای این کار ، Command مون را در ViewModel اجرا کنیم .

    بنابراین میتونیم یه هندلر Button_Click ای در View درست کنیم (و بعد از انجام کارهای مربوطه) ، در همون هندلر ، Command مربوطه در ViewModel (فرضا GetStudentCommand در کد بالا) را فراخوانی کنیم .
    هر چند احتمالا این سناریو ، کم پیش میاد و بیشتر سناریوها ، مستقیما در کد xaml ، اون Command ای را که در ViewModel مون ساخته بودیم را مستقیما فراخوانی اش میکنیم .

    ===========


    یک سناریوی دیگه هم اینه که وقتی که یک رویداد خاصی از یک المنت و کنترل مورد نظرمون ، اجرا شد ، در این صورت ، Command مون اجرا بشه که کتابخونه های زیادی برای این کار هست (از جمله کتابخونه ی پیش فرض Silverlight و MVVMLight و DevExpress و ...) اما کتابخانه ی Microsoft.Xaml.Behaviors.Wpf هم هست که خوبه و توسط nuget میشه ازش استفاده کرد :


    <Window x:Class="MVVM_Practies.MainWindow"
    xmlns:behavior ="http://schemas.microsoft.com/xaml/behaviors">

    <Button Content="Mouse Move">
    <behavior:Interaction.Triggers>
    <behavior:EventTrigger EventName="MouseMove">
    <behavior:InvokeCommandAction Command="{Binding Path=GetStudentCommand}"
    PassEventArgsToCommand="True"/>
    </behavior:EventTrigger>
    </behavior:Interaction.Triggers>
    </Button>


    </Window>



    که برای بیشترین سناریوها ، سناریو کد xaml بالا که برای رویداد خاص و کنترل خاصی استفاده میشه و همچنین مستقیما Command را در ViewModel فراخوانی میکنه .

    پاورقی اینکه RelayCommand هم کلاس سبک شده ی DelegateCommand هست (که اغلب از این نوع ها استفاده میشه).

    کلاس RoutedCommand هم مثل RoutedEvent ها ، اما این کلاسِ RoutedCommand ، اگه هر وقت اجرا بشه ، فقط استراتژی حبابی و به سمت بالا را طی میکنه تا به کنترلی که شی ای از نوع CommandBinding (که معمولا پروپرتیِ CommandBindings در المنت ها هستند) ای که شیِ Command هاشون یکی و هم خوان اش باشه (مثلا هر دو از نوع ApplicationCommands.Copy باشن ، برسه که در اون صورت ، مقداری که درون پروپرتیِ Command ای که در شیِ CommandBinding مشخص شده را اجرا میکنه .

    و RelayCommand ، بیشتر به درد زمانی میخوره که در دو کنترل مختلف (مثلا هم در MenuItem و هم در کنترل دکمه) ، بخوایم ییک کار مشابه (مثل کپی کردن و ...) را انجام بدیم .

    درست هست دیگه؟

    تشکر .
    آخرین ویرایش به وسیله SajjadKhati : پنج شنبه 18 خرداد 1402 در 16:16 عصر

تاپیک های مشابه

  1. نحوه کار با Command Argument و Command name؟
    نوشته شده توسط nabi_s در بخش ASP.NET Web Forms
    پاسخ: 3
    آخرین پست: یک شنبه 05 خرداد 1392, 12:33 عصر
  2. قرار دادن متغیر به جای نام (مثلا ( command button(command(i
    نوشته شده توسط esikhatar در بخش برنامه نویسی در 6 VB
    پاسخ: 1
    آخرین پست: چهارشنبه 06 بهمن 1389, 06:48 صبح
  3. خطای Command text was not set for the command object
    نوشته شده توسط REZADG در بخش مطالب مرتبط با بانکهای اطلاعاتی در VB6
    پاسخ: 0
    آخرین پست: چهارشنبه 01 دی 1389, 21:39 عصر
  4. Command ADODC]:no RecordSource specified.[ADO]:Command text was not set for the Command object
    نوشته شده توسط hossein71 در بخش مطالب مرتبط با بانکهای اطلاعاتی در VB6
    پاسخ: 8
    آخرین پست: چهارشنبه 16 تیر 1389, 12:12 عصر

قوانین ایجاد تاپیک در تالار

  • شما نمی توانید تاپیک جدید ایجاد کنید
  • شما نمی توانید به تاپیک ها پاسخ دهید
  • شما نمی توانید ضمیمه ارسال کنید
  • شما نمی توانید پاسخ هایتان را ویرایش کنید
  •