ما هي أفضل طريقة في MVVM بناء القائمة التي تعرض مختلف الصفحات ؟

StackOverflow https://stackoverflow.com/questions/1018483

  •  06-07-2019
  •  | 
  •  

سؤال

أريد بناء تطبيق بسيط مع نمط MVVM.

هذا التطبيق سوف يكون قسمين رئيسيين:

  • القائمة على رأس
  • المحتوى أدناه

الملاحة سوف تكون بسيطة:

  • كل عنصر القائمة (مثلا ، "إدارة العملاء" أو "عرض التقارير") سوف ملء منطقة المحتوى مع صفحة جديدة التي لديها بعض وظائف

لدي فعلت هذا من قبل مع التعليمات البرمجية خلف حيث البرمجية-خلف الحدث-معالج عناصر القائمة كل الصفحات تحميلها و التي يجب أن يتم عرض حملت في الطفل من StackPanel.لكن ذلك لن ينجح في MVVM منذ كنت لا تريد أن يكون يدويا ملء StackPanel لكن عرض مثلو "PageItem" كائن مع DataTemplate ، إلخ.

حتى أولئك الذين جعلوا بسيطة على زر القائمة تطبيق مثل هذا مع MVVM ما كان التطبيق الأساسي الخاص بك ؟ أنا أفكر على طول هذه الخطوط:

MainView.xaml:

<DockPanel LastChildFill="False">

    <Menu 
        ItemsSource="{Binding PageItemsMainMenu}" 
        ItemTemplate="{StaticResource MainMenuStyle}"/>

    <ContentControl 
        Content="{Binding SelectedPageItem}"/>        

</DockPanel>

حيث القائمة يتم تعبئة مع مجموعة من "PageItems" و DataTemplate يعرض عنوان كل "PageItem كائن" كما رأس كل MenuItem.

و ContentControl سوف تكون مليئة عرض/ViewModel الزوج الذي لديه وظيفة كاملة ، ولكن لست متأكد من هذا.

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

المحلول

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

الآن، إذا كنت تريد اتباع مسار MVVM الخالص، فكل ما عليك القيام به هو جعل قائمتك تطلق أمرًا، أولاً، في بعض أقسام الموارد أضف هذا النمط:

<Style x:Key="MenuItemStyle" TargetType="MenuItem">
    <Setter Property="Command" 
            Value="{Binding DataContext.SwitchViewCommand,
            RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Menu}}}"/>
    <Setter Property="CommandParameter" 
            Value="{Binding}"/>
</Style>

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

العرض الفعلي هو نفس الكود الخاص بك مع إشارة إضافية إلى هذا النمط مثل ItemContainerStyle (بحيث ينطبق على عنصر القائمة وليس محتوى DataTemplate):

<DockPanel LastChildFill="False">

    <Menu DockPanel.Dock="Top"
        ItemsSource="{Binding PageItemsMainMenu}" 
        ItemTemplate="{StaticResource MainMenuStyle}"
        ItemContainerStyle="{StaticResource MenuItemStyle}"/>
    <ContentControl 
    Content="{Binding SelectedPageItem}"/>
</DockPanel>

الآن تحتاج إلى نموذج العرض (لقد استخدمت السلاسل لأنني لا أملك رمز PageItem الخاص بك):

private string _selectedViewItem;
public List<string> PageItemsMainMenu { get; set; }
public string SelectedPageItem
{
    get { return _selectedViewItem; }
    set { _selectedViewItem = value; OnNotifyPropertyChanged("SelectedPageItem"); }
}
public ICommand SwitchViewCommand { get; set; }

واستخدم أي فئة أمر تستخدمها لجعل الأمر يستدعي هذا الرمز:

private void DoSwitchViewCommand(object parameter)
{
    SelectedPageItem = (string)parameter;
}

الآن، عندما يقوم المستخدم بالنقر فوق عنصر قائمة، سيقوم عنصر القائمة باستدعاء SwitchViewCommand مع عنصر الصفحة كمعلمة.

سيقوم الأمر باستدعاء DoSwitchViewCommand الذي سيقوم بتعيين خاصية SelectedPageItem

ستقوم الخاصية برفع NotifyPropertyChanged الذي سيقوم بتحديث واجهة المستخدم عبر ربط البيانات.

أو يمكنك كتابة معالج حدث مكون من سطرين، حسب اختيارك

نصائح أخرى

يمكنني تخيل ObservableCollection في VM, الذي يحمل كل الصفحات أن تكون للاستدعاء من القائمة.ثم ربط أحد ItemsControl و ContentControl إلى ذلك لجعل ContentControl تظهر دائما CurrentItem من تلك القائمة.وبطبيعة الحال ، فإن القائمة فقط ربط بعض عنوان العقار بينما ContentControl سوف تعتمد كل بند سد العجز في بعض العرض المناسبة وفقا لنوع.

هناك خيار آخر وهو استخدام ListBox بدلاً من القائمة، وتصميم ListBox ليبدو كقائمة، ومن ثم يمكنك الارتباط بالقيمة المحددة، مثل هذا:

<DockPanel LastChildFill="False">

    <ListBox 
        ItemsSource="{Binding PageItemsMainMenu}" 
        ItemTemplate="{StaticResource MainMenuStyle}"
        IsSynchronizedWithCurrentItem="True"/>

    <ContentControl 
        Content="{Binding PageItemsMainMenu/}"/>        

</DockPanel>

لاحظ IsSynchronizedWithCurrentItem = "True" لتعيين العنصر المحدد و{Binding PageItemsMainMenu/} مع الشرطة المائلة اللاحقة لاستخدامه.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top