سؤال

عندما ربط عناصر القائمة مع ObservableCollection فقط "الداخلية" منطقة MenuItem هو نقر:

النص البديل http://tanguay.info/web/external/mvvmMenuItems.png

في بلدي عرض لدي هذه القائمة:

<Menu>
    <MenuItem 
        Header="Options" ItemsSource="{Binding ManageMenuPageItemViewModels}"
              ItemTemplate="{StaticResource MainMenuTemplate}"/>
</Menu>

ثم ربط ذلك مع هذا DataTemplate:

<DataTemplate x:Key="MainMenuTemplate">
    <MenuItem
        Header="{Binding Title}" 
        Command="{Binding DataContext.SwitchPageCommand,
        RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Menu}}}" 
        Background="Red"
        CommandParameter="{Binding IdCode}"/>
</DataTemplate>

لأن كل ViewModel في ObservableCollection ManageMenuPageItemViewModels لديه خاصية العنوان و IdCode, رمز أعلاه يعمل بشكل جيد في أول وهلة.

ومع ذلك, المشكلة هي أن MenuItem في DataTemplate هو في الواقع داخل آخر MenuItem (كما إذا كان يتم لا بد مرتين) حتى أنه في أعلاه DataTemplate مع Background="الأحمر" هناك مربع أحمر داخل كل بند من بنود القائمة فقط هذا المجال يمكن النقر عليها ، وليس كل عنصر القائمة في المنطقة نفسها (مثلا ، إذا ينقر المستخدم على المنطقة حيث علامة أو إلى اليمين أو اليسار من داخل منطقة قابلة للنقر ، ثم لا شيء يحدث, التي, إذا لم يكن لديك لون منفصلة هي مربكة جدا.)

ما هي الطريقة الصحيحة لربط MenuItems إلى ObservableCollection من ViewModels حتى أن كل منطقة داخل كل MenuItem هو نقر?

تحديث:

لذلك أنا جعلت التغييرات التالية على أساس المشورة أدناه و الآن لديك هذا:

النص البديل http://tanguay.info/web/external/mvvmMenuItemsYellow.png

لدي فقط TextBlock داخل DataTemplate, ولكن ما زلت لا أستطيع "اللون كله MenuItem" ولكن فقط TextBlock:

<DataTemplate x:Key="MainMenuTemplate">
    <TextBlock Text="{Binding Title}"/>
</DataTemplate>

و أنا وضعت أمر ملزم في القائمة.ItemContainerStyle لكنهم لا النار الآن:

<Menu DockPanel.Dock="Top">
    <Menu.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Setter Property="Background" Value="Yellow"/>
            <Setter Property="Command" Value="{Binding DataContext.SwitchPageCommand,
        RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Menu}}}"/>
            <Setter Property="CommandParameter" Value="{Binding IdCode}"/>
        </Style>
    </Menu.ItemContainerStyle>
    <MenuItem 
        Header="MVVM" ItemsSource="{Binding MvvmMenuPageItemViewModels}"
              ItemTemplate="{StaticResource MainMenuTemplate}"/>
    <MenuItem 
        Header="Application" ItemsSource="{Binding ApplicationMenuPageItemViewModels}"
              ItemTemplate="{StaticResource MainMenuTemplate}"/>
    <MenuItem 
        Header="Manage" ItemsSource="{Binding ManageMenuPageItemViewModels}"
              ItemTemplate="{StaticResource MainMenuTemplate}"/>
</Menu>
هل كانت مفيدة؟

المحلول

وجدت باستخدام MVVM مع MenuItems أن تكون صعبة للغاية.باقي التطبيق يستخدم DataTemplates إلى زوج الرأي مع ViewModel, لكن ذلك لا يبدو أن العمل مع القوائم بسبب بالضبط الأسباب التي وصفتها.وهنا كيف أنا في نهاية المطاف حلها.من وجهة نظري يبدو مثل هذا:

<DockPanel>
<Menu DockPanel.Dock="Top" ItemsSource="{Binding Path=(local:MainViewModel.MainMenu)}">
    <Menu.ItemContainerStyle>
        <Style>
            <Setter Property="MenuItem.Header" Value="{Binding Path=(contracts:IMenuItem.Header)}"/>
            <Setter Property="MenuItem.ItemsSource" Value="{Binding Path=(contracts:IMenuItem.Items)}"/>
            <Setter Property="MenuItem.Icon" Value="{Binding Path=(contracts:IMenuItem.Icon)}"/>
            <Setter Property="MenuItem.IsCheckable" Value="{Binding Path=(contracts:IMenuItem.IsCheckable)}"/>
            <Setter Property="MenuItem.IsChecked" Value="{Binding Path=(contracts:IMenuItem.IsChecked)}"/>
            <Setter Property="MenuItem.Command" Value="{Binding}"/>
            <Setter Property="MenuItem.Visibility" Value="{Binding Path=(contracts:IMenuItem.Visible), 
                Converter={StaticResource BooleanToVisibilityConverter}}"/>
            <Setter Property="MenuItem.ToolTip" Value="{Binding Path=(contracts:IMenuItem.ToolTip)}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=(contracts:IMenuItem.IsSeparator)}" Value="true">
                    <Setter Property="MenuItem.Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type MenuItem}">
                                <Separator Style="{DynamicResource {x:Static MenuItem.SeparatorStyleKey}}"/>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Menu.ItemContainerStyle>
</Menu>
</DockPanel>

إذا لاحظت ، تعريف واجهة تسمى IMenuItem ، وهو ViewModel عن MenuItem.هنا هو رمز ذلك:

public interface IMenuItem : ICommand
{
    string Header { get; }
    IEnumerable<IMenuItem> Items { get; }
    object Icon { get; }
    bool IsCheckable { get; }
    bool IsChecked { get; set; }
    bool Visible { get; }
    bool IsSeparator { get; }
    string ToolTip { get; }
}

لاحظ أن IMenuItem يعرف IEnumerable البنود ، وهو كيف تحصل على القوائم الفرعية.كما IsSeparator هو وسيلة لتحديد الفواصل في القائمة (آخر صعب قليل الحيلة).يمكنك أن ترى في xaml كيف يستخدم DataTrigger إلى تغيير نمط القائمة فاصل نمط إذا IsSeparator صحيح.هنا كيف MainViewModel يحدد الأساسية الملكية (هذا رأي يربط):

public IEnumerable<IMenuItem> MainMenu { get; set; }

ويبدو أن تعمل بشكل جيد.أفترض أنك يمكن أن تستخدم ObservableCollection عن القائمة الأساسية.أنا في الواقع باستخدام MEF أن يؤلف قائمة أجزاء ، ولكن بعد أن البنود هي نفسها ثابتة (على الرغم من أن خصائص كل عنصر القائمة لا).أنا أيضا استخدام AbstractMenuItem الفئة التي تطبق IMenuItem و هو مساعد من الدرجة إنشاء عناصر القائمة في مختلف أجزاء.

تحديث:

بخصوص مشكلة اللون, لا هذا الموضوع مساعدة ؟

نصائح أخرى

لا تضع MenuItem في DataTemplate.على DataTemplate يحدد المحتوى من MenuItem.بدلا من ذلك تحديد دخيلة خصائص MenuItem عبر ItemContainerStyle:

<Menu>
    <Menu.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Setter Property="Header" Value="{Binding Title}"/>
            ...
        </Style>
    </Menu.ItemContainerStyle>
    <MenuItem 
        Header="Options" ItemsSource="{Binding ManageMenuPageItemViewModels}"
              ItemTemplate="{StaticResource MainMenuTemplate}"/>
</Menu>

كما نلقي نظرة على HierarchicalDataTemplates.

هنا هو كيف فعلت بلدي القوائم.قد لا يكون بالضبط ما تحتاجه ، ولكن أعتقد أنها قريبة جدا.

  <Style x:Key="SubmenuItemStyle" TargetType="MenuItem">
    <Setter Property="Header" Value="{Binding MenuName}"></Setter>
    <Setter Property="Command" Value="{Binding Path=MenuCommand}"/>
    <Setter Property="ItemsSource" Value="{Binding SubmenuItems}"></Setter>
  </Style>

  <DataTemplate DataType="{x:Type systemVM:TopMenuViewModel}" >
    <Menu>
      <MenuItem Header="{Binding MenuName}"         
                    ItemsSource="{Binding SubmenuItems}" 
                    ItemContainerStyle="{DynamicResource SubmenuItemStyle}" />
    </Menu>
  </DataTemplate>

    <Menu DockPanel.Dock="Top" ItemsSource="{Binding Menus}" />

TopMenuViewModel هو مجموعة من القوائم التي تظهر على شريط القوائم.كل منهما تحتوي على MenuName أنه سيتم عرض مجموعة تسمى SubMenuItems أن يكون ItemsSource.

انا السيطرة على الطريق SubMenuItems يتم عرضها عن طريق أسلوب SumMenuItemStyle.كل SubMenuItem الخاصة MenuName الملكية الأوامر الملكية من نوع ICommand ، وربما مجموعة أخرى من SubMenuItems.

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

ويساعد هذا الأمل.

فقط جعل DataTemplate أن يكون TextBlock (أو ربما كومة الفريق مع رمز TextBlock).

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