2009-07-01 15 views
15

जब मैं एक ObservableCollection के साथ मेनू आइटम के लिए बाध्य है, केवल "आंतरिक" MenuItem का हिस्सा क्लिक करने योग्य है: तो फिरमैं ViewModels के एक ObservableCollection को मेनूइटम में कैसे बांध सकता हूं?

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

:

alt text http://tanguay.info/web/external/mvvmMenuItems.png

मेरी देखें में मैं इस मेनू है मैं इसे डेटाटाम्प्लेट:

<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 में इतना है कि पृष्ठभूमि के साथ ऊपर DataTemplate में (जैसे कि वह दो बार बाध्य किया जा रहा है ) के अंदर एक और MenuItem वास्तव में है = " लाल " एक प्रत्येक मेनू आइटम के अंदर लाल बॉक्स और केवल इस क्षेत्र को क्लिक किया जा सकता है, पूरे मेनू आइटम क्षेत्र में नहीं (उदाहरण के लिए यदि उपयोगकर्ता उस क्षेत्र पर क्लिक करता है जहां चेकमार्क सही है या बाएं है आंतरिक सीएल के अचूक क्षेत्र, तो कुछ भी नहीं होता है, जो, यदि आपके पास कोई अलग रंग नहीं है तो बहुत भ्रमित है।)

व्यूमोडेल के एक अवलोकन करने योग्य चयन के लिए मेनूइटम को बांधने का सही तरीका क्या है ताकि प्रत्येक मेनूइटम के अंदर का पूरा क्षेत्र हो क्लिक करने योग्य?

अद्यतन:

तो मैं नीचे सलाह के आधार पर निम्न परिवर्तन किए और अब इस राशि:

alt text http://tanguay.info/web/external/mvvmMenuItemsYellow.png

मैं अपने DataTemplate अंदर केवल एक TextBlock है, लेकिन मैं अभी भी नहीं कर सकते हैं "रंग पूरे MENUITEM" लेकिन सिर्फ TextBlock:

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

और मैं कमान Menu.ItemCo में बाध्यकारी डाल ntainerStyle लेकिन वे अब आग नहीं है:

<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> 

उत्तर

35

मुझे मेनू Items के साथ एमवीवीएम का उपयोग बहुत चुनौतीपूर्ण होने के लिए मिला। मेरा शेष एप्लिकेशन व्यूमोडेल के साथ व्यू को जोड़ने के लिए डेटा टेम्पलेट का उपयोग करता है, लेकिन यह आपके द्वारा वर्णित बिल्कुल कारणों से मेनस के साथ काम नहीं करता है। यहां बताया गया है कि मैंने अंततः इसे कैसे हल किया। मेरे दृश्य इस तरह दिखता है:

<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 कहा जाता है, जो एक MenuItem के लिए ViewModel है परिभाषित किया।

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 मेनू में विभाजक को परिभाषित करने का एक तरीका है (एक और कठिन छोटी चाल)। यदि आप IsSeparator सत्य हैं तो आप शैली को मौजूदा विभाजक शैली में बदलने के लिए डेटाट्रिगर का उपयोग कैसे करते हैं, यह xaml में देख सकते हैं।

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

यह अच्छी तरह से काम करने लगता है: यहाँ कैसे MainViewModel mainmenu संपत्ति (उस दृश्य को बांधता है) को परिभाषित करता है है। मुझे लगता है कि आप मेनमेनू के लिए एक ऑब्जर्जेबल कोलेक्शन का उपयोग कर सकते हैं। मैं वास्तव में मेनू से मेनू को लिखने के लिए एमईएफ का उपयोग कर रहा हूं, लेकिन इसके बाद आइटम स्वयं स्थिर हैं (भले ही प्रत्येक मेनू आइटम के गुण नहीं हैं)। मैं एक सारमेनमेनूटेम क्लास का भी उपयोग करता हूं जो IMenuItem लागू करता है और विभिन्न हिस्सों में मेनू आइटम को तुरंत चालू करने के लिए एक सहायक वर्ग है।

अद्यतन:

अपने रंग समस्या के बारे में, this thread मदद करता है?

+1

+1 - सेपरेटर्स और सब कुछ के साथ पूर्ण उदाहरण के लिए बहुत अच्छा है। –

+0

मेरे पास एक बहुत ही समान डिज़ाइन है और सब कुछ अलग करने वाला को छोड़कर काम करता है। यदि मैं टेम्पलेट को पर बदलता हूं तो मुझे "सेपरेटर" दिखाई देता है जहां एक विभाजक होना चाहिए। लेकिन जब मैं आपके उत्तर में टेम्पलेट का उपयोग करने की कोशिश करता हूं तो कुछ भी नहीं दिखाया जाता है। मैंने <सेपरेटर बॉर्डर थिक्नेस = "100" बॉर्डरब्रश = "ब्लैक"> और फिर विभाजक दिखाई दे रहा है, लेकिन मैं डिफ़ॉल्ट शैली को चौड़ाई के साथ मेनू चौड़ाई द्वारा निर्धारित चौड़ाई के साथ चाहता हूं। क्या मुझे कहीं सेपरेटर स्टाइलकी को परिभाषित करना है? मैंने ऑनलाइन खोज की लेकिन कुछ भी नहीं मिला जो मदद मिली ...धन्यवाद! – Dina

14

DataTemplate में MenuItem न रखें। DataTemplateसामग्रीMenuItem को परिभाषित करता है। इसके बजाय, ItemContainerStyle के माध्यम से MenuItem के लिए बाहरी गुण निर्दिष्ट करें:

<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> 

इसके अलावा, HierarchicalDataTemplate रों पर एक नज़र डालें।

+0

क्या आपका मतलब मेनू में हेडर/रंग को परिभाषित करना है। ITEMContainerStyle और फिर DataTemplate के अंदर एक हाइरार्किकलडेटा टेम्पलेट डालें जो कमांड और कमांड पैरामीटर को परिभाषित करता है? –

+0

धन्यवाद, यह वही है जो मैं ढूंढ रहा था। बहुत अच्छा काम करता है। धन्यवाद! –

+0

+1 - पदानुक्रमित डेटा टेम्पलेट्स इस पूरी समस्या को लगभग तुच्छ बनाते हैं। –

2

यहां बताया गया है कि मैंने अपने मेनू कैसे किए हैं। यह ठीक नहीं हो सकता है कि आपको क्या चाहिए, लेकिन मुझे लगता है कि यह बहुत करीब है।

<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 मेन्यू बार पर दिखाई देने वाले मेनू का संग्रह है। उनमें से प्रत्येक में मेनू नाम होता है जिसे प्रदर्शित किया जाएगा और SubMenuItems नामक एक संग्रह जिसे मैं आइटम्ससोर्स के रूप में सेट करता हूं।

मैं सबमेनूइटम को स्टाइल SumMenuItemStyle शैली के माध्यम से प्रदर्शित करने के तरीके को नियंत्रित करता हूं। प्रत्येक SubMenuItem की अपनी मेनू नाम संपत्ति है, प्रकार आईसीओएमएंड की कमांड संपत्ति, और संभवतः SubMenuItems का एक और संग्रह।

परिणाम यह है कि मैं डेटाबेस में अपनी सभी मेनू जानकारी स्टोर करने में सक्षम हूं और रनटाइम पर मेनू को प्रदर्शित करने के लिए गतिशील रूप से स्विच कर सकता हूं। संपूर्ण मेन्यूटेम क्षेत्र क्लिक करने योग्य और सही तरीके से प्रदर्शित होता है।

उम्मीद है कि इससे मदद मिलती है।

2

बस अपना डेटा टेम्पलेट टेक्स्टब्लॉक (या शायद आइकन के साथ एक स्टैक पैनल और टेक्स्टब्लॉक) बनें।

+0

ठीक है कि यह बहुत अच्छा है, यह काम करता है (मैंने सोचा कि मैंने कोशिश की है), लेकिन अब मुझे किसी भी तरह से टेक्स्टब्लॉक पर कमांड को हुक करना है, इसमें कमांड विशेषता नहीं है, मैं अपने प्रतिनिधि कॉमांड का उपयोग नहीं कर सकता, आपने इसका क्या उपयोग किया संलग्न व्यवहारकर्ता या कुछ और? –

+1

ItemContainerStyle –

+0

संपादित करें, इसके अनुसार इसे ऊपर संपादित किया गया है, स्क्रीनशॉट पोस्ट किया गया है, अभी भी काम नहीं कर रहा है :-( –