سؤال

سؤالي العام هو كما ينص العنوان ، هل من الأفضل تحميل البيانات أثناء إنشاء ViewModel أو بعد ذلك من خلال بعض معالجة الأحداث المحملة؟

أظن أن الإجابة هي بعد البناء عبر بعض معالجة الأحداث المحملة ، لكنني أتساءل كيف يتم تنسيق ذلك بشكل نظيف بين ViewModel و View؟

إليك المزيد من التفاصيل حول وضعي والمشكلة الخاصة التي أحاول حلها:

أنا أستخدم إطار Light MVVM وكذلك الوحدة لـ DI. لدي بعض الآراء المتداخلة ، كل ملزمة إلى ViewModel المقابلة. ترتبط ViewModels بنص التحكم في كل طريقة عرض DataContext عبر فكرة ViewModellocator التي وضعتها Laurent Bugnion في ضوء MVVM. يسمح ذلك بإيجاد ViewModels عبر مورد ثابت والتحكم في عمر ViewModels عبر إطار حقن التبعية ، في هذه الحالة. كما يسمح بمزيج التعبير لرؤية كل شيء فيما يتعلق بـ ViewModels وكيفية ربطها.

لذلك على أي حال ، لديّ طريقة عرض أولياء لها تحتوي على قاعدة بيانات combobox إلى ObservableCollection في ViewModel الخاص بها. يتم ربط Combobox's SelectionItem أيضًا (في اتجاهين) إلى خاصية على ViewModel. عندما يتغير اختيار Combobox ، فإن هذا هو تشغيل التحديثات في طرق عرض أخرى وآراء فرعية. حاليًا أقوم بإنجاز هذا عبر نظام المراسلة الموجود في MVVM Light. كل هذا يعمل بشكل رائع وكما هو متوقع عندما تختار عناصر مختلفة في Combobox.

ومع ذلك ، فإن ViewModel تحصل على بياناتها أثناء وقت البناء عبر سلسلة من مكالمات تهيئة طريقة التهيئة. يبدو أن هذه مشكلة فقط إذا كنت أرغب في التحكم في ماهية المحدد الأولي لـ Combobox. باستخدام نظام المراسلة الخاص بـ MVVM Light ، قمت حاليًا بإعداده حيث تم إعداد Setter لخاصية ViewModel الخاصة بـ SelectionItem هو الذي يبث التحديث وتسجيل ViewModels المهتمين الآخر للرسالة في بنائهم. يبدو أنني أحاول حاليًا تعيين The SelectionItem عبر ViewModel في وقت البناء ، والذي لم يسمح ببناء عوامل العرض الفرعية وتسجيلها بعد.

ما هي أنظف طريقة لتنسيق تحميل البيانات والإعداد الأولي لـ SelectItem داخل ViewModel؟ أريد حقًا الالتزام بوضع القليل في رمز العرض كما هو معقول. أعتقد أنني بحاجة فقط إلى طريقة حتى يتم تحميل ViewModel متى يتم تحميل الأشياء ويمكنها بعد ذلك الاستمرار في تحميل البيانات ووضع اللمسات الأخيرة على مرحلة الإعداد.

شكرا مقدما على ردودكم.

هل كانت مفيدة؟

المحلول

للأحداث ، يجب عليك استخدام EventTocommand في مجموعة أدوات MVVM Light. باستخدام هذا ، يمكنك ربط أي حدث لأي عنصر واجهة المستخدم إلى RelayCommand. تحقق من مقالته على EventTocommand في

http://blog.galasoft.ch/archive/2009/11/05/mvvm-light-toolkit-v3-alpha-2-eventtocommand-behavior.aspx

قم بتنزيل العينة وإلقاء نظرة. إنه لشيء رائع. لن تحتاج إلى أي codebehind بعد ذلك. مثال على النحو التالي:

<Page x:Class="cubic.cats.Wpf.Views.SplashScreenView"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
      xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras"
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"
    Title="SplashScreenPage">

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <cmd:EventToCommand Command="{Binding LoadedCommand}" />
        </i:EventTrigger>        
    </i:Interaction.Triggers>

    <Grid>
        <Label Content="This is test page" />
    </Grid>
</Page>

ويمكن أن يكون وضع العرض هكذا

 public class SplashScreenViewModel : ViewModelBase
    {
        public RelayCommand LoadedCommand
        {
            get;
            private set;
        }

        /// <summary>
        /// Initializes a new instance of the SplashScreenViewModel class.
        /// </summary>
        public SplashScreenViewModel()
        {
            LoadedCommand = new RelayCommand(() =>
            {
                string a = "put a break point here to see that it gets called after the view as been loaded";
            });
        }
    }

إذا كنت ترغب في الحصول على نموذج العرض ، فيمكنك تعيين PasseventArgStocommand البسيط إلى True:

<i:Interaction.Triggers>
            <i:EventTrigger EventName="Loaded">
                <cmd:EventToCommand PassEventArgsToCommand="True" Command="{Binding LoadedCommand}" />
  </i:EventTrigger>        
</i:Interaction.Triggers>

وسيكون نموذج العرض مثل

public class SplashScreenViewModel : ViewModelBase
{
    public RelayCommand<MouseEventArgs> LoadedCommand
    {
        get;
        private set;
    }

    /// <summary>
    /// Initializes a new instance of the SplashScreenViewModel class.
    /// </summary>
    public SplashScreenViewModel()
    {
        LoadedCommand = new RelayCommand<MouseEventArgs>(e =>
        {
            var a = e.WhateverParameters....;
        });
    }

}

نصائح أخرى

يتشابه الحل التالي مع الحل المقدم بالفعل والمقبول ، لكنه لا يستخدم أمرًا في نموذج العرض لتحميل البيانات ، ولكن "الطريقة العادية". أعتقد أن الأوامر أكثر ملاءمة لإجراءات المستخدم (يمكن أن تكون الأوامر متوفرة وغير متوفرة في وقت التشغيل) ، وهذا هو السبب في استخدام استدعاء طريقة عادية ، ولكن أيضًا عن طريق تعيين مشغل تفاعل في العرض.

أقترح هذا: إنشاء فئة نموذج عرض. إنشاء فئة نموذج العرض داخل XAML من العرض عن طريق إنشائها داخل DataContext منشأه.

تنفيذ طريقة لتحميل البيانات في نموذج العرض الخاص بك ، على سبيل المثال LoadData. قم بإعداد العرض ، بحيث يتم استدعاء هذه الطريقة عند تحميل العرض. يتم ذلك عن طريق مشغل التفاعل في عرضك المرتبط بالطريقة في نموذج العرض (الإشارات إلى "Microsoft.Expression.Interctions" و "System.Windows.Interactivity" مطلوبة):

عرض (xaml):

<Window x:Class="MyWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test" 
    xmlns:viewModel="clr-namespace:ViewModels"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"            
    >
<Window.DataContext>
    <viewModel:ExampleViewModel/>
</Window.DataContext>
<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <ei:CallMethodAction TargetObject="{Binding}" MethodName="LoadData"/>
    </i:EventTrigger>
</i:Interaction.Triggers>   

هذا سوف يسمي LoadData الطريقة في ViewModel في وقت التشغيل عند تحميل العرض. هذا هو المكان الذي تقوم فيه بتحميل بياناتك.

public class ExampleViewModel
{
    /// <summary>
    /// Constructor.
    /// </summary>
    public ExampleViewModel()
    {
        // Do NOT do complex stuff here
    }


    public void LoadData()
    {
        // Make a call to the repository class here
        // to set properties of your view model
    }

إذا كانت الطريقة في المستودع طريقة غير متزامنة ، فيمكنك عمل LoadData الطريقة ASYNC أيضا ، ولكن هذا غير مطلوب في كل حالة.

بالمناسبة ، عمومًا لن أقوم بتحميل البيانات في مُنشئ نموذج العرض. في المثال أعلاه ، يتم استدعاء مُنشئ نموذج العرض (المعلمة الأقل) عندما يعرض المصمم عرضك. يمكن أن يسبب القيام بأشياء معقدة هنا أخطاء في المصمم عند إظهار وجهة نظرك (لنفس السبب الذي لا يمكنني صنع أشياء معقدة في مُنشئ العرض).

في بعض كود السيناريوهات في مُنشئ نماذج العرض ، يمكن أن يتسبب في مشكلات في وقت التشغيل ، عندما ينفذ منشئات نماذج العرض ، قم بتعيين خصائص نموذج العرض الذي يرتبط بالعناصر في العرض ، بينما لا يتم الانتهاء من كائن العرض بالكامل.

حسنا إذا. :-)

يمكنك ربط طريقة في ViewModel باستخدام سلوك.

إليك رابط سيساعدك في ذلك.http://expressionblend.codeplex.com/

قررت فقط أن يكون XAML مرتبطًا بشكل معروف بمعالج أحداث محمّل على رمز العرض ، والذي يطلق عليه بدوره طريقة على كائن ViewModel ، عبر عنصر DataControl الجذر الخاص بالعمل.

لقد كان حلًا بسيطًا إلى حد ما ومستقيم للأمام ونظيف. أظن أنني كنت آمل في طريقة لربط الحدث المحمّل بكائن ViewModel بنفس الطريقة التعريفية التي يمكنك معها مع ICommands في XAML.

ربما أعطيت Klinger الرصيد الرسمي ، لكنه نشر تعليقًا على سؤالي ، وليس إجابة. لذلك أعطيته على الأقل واحد على تعليقه.

واجهت نفس المشكلة عند التعامل مع الرسائل بين نافذة الأصل ونافذة الطفل. ما عليك سوى تغيير الترتيب الذي يتم به إنشاء نماذج العرض الخاصة بك في فئة ViewModellocator الخاصة بك. تأكد من إنشاء جميع نماذج العرض التي تعتمد على رسالة قبل نموذج العرض الذي يرسل الرسالة.

على سبيل المثال ، في مُنشئ فئة ViewModellocator:

public ViewModelLocator()
{
    if (s_messageReceiverVm == null)
    {
        s_messageReceiverVm = new MessageReceiverVM();
    }

    if (s_messageSenderVm == null)
    {
        s_messageSenderVm = new MessageSenderVM();
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top