2009-06-17 21 views
5

दिलचस्प संदर्भ मेनू आइटम से गोलीबारी आदेशों से संबंधित समस्या ...WPF कमान में ContextMenu की उत्पत्ति पासिंग

मैं अपने नियंत्रण, InsertRowCmd में एक पंक्ति सम्मिलित करने के लिए एक कमांड सक्रिय करना चाहते हैं। इस कमांड को पता होना चाहिए कि पंक्ति कहां डालें।

मैं Mouse.GetPosition() इस्तेमाल कर सकते हैं, लेकिन है कि मुझे माउस वर्तमान की स्थिति है, जो मेनू आइटम से अधिक होगा मिलेगा। मैं इसके बजाय संदर्भ मेनू की उत्पत्ति प्राप्त करना चाहता हूं।

किसी भी एक कैसे आदेश को पैरामीटर के रूप संदर्भ मेनू के मूल पारित करने के लिए पर कोई सुझाव हैं?

नमूना कोड:

प्रयोग क्लिक हैंडलर बजाय ताकि मैं कोड में मूल पा सकते हैं:

<UserControl x:Name="MyControl"> 
<!--...--> 
     <ContextMenu x:Name="menu"> 
      <MenuItem Header="Insert Row" Command="{x:Static customCommands:MyCommands.InsertRowCmd}" CommandParameter="?"/> 
     </ContextMenu> 
</UserControl> 

मेरे वर्तमान विचारों इस प्रकार हैं। समस्या यह है कि मुझे सक्षम/अक्षम करने को संभालना होगा।

-Handle क्लिक करें घटना और संदर्भ मेनू के मूल को बचाने के। इस सहेजी गई जानकारी को कमांड में पास करें। मैंने सत्यापित किया है कि कमांड निष्पादित होने से पहले घटनाओं को आग पर क्लिक करें।

कोई भी विचार?

संपादित करें:

मैं जोश स्मिथ के CommandSinkBinding रूट करने के लिए आदेश मेरी ViewModel वर्ग में से निपटने का उपयोग कर रहा हूँ। तो कोड निष्पादन को संभालने वाला कोड दृश्य के बारे में कुछ भी नहीं जानता है।

उत्तर

5

आपको TranslatePoint का उपयोग ContextMenu के शीर्ष-बाएं (0, 0) को ग्रिड में समन्वय में करने के लिए करना होगा। आप ContextMenu करने के लिए CommandParameter जुड़ कर ऐसा करते हैं और एक कनवर्टर इस्तेमाल कर सकते हैं:

CommandParameter="{Binding IsOpen, ElementName=_menu, Converter={StaticResource PointConverter}}" 

एक और दृष्टिकोण एक संलग्न व्यवहार है कि स्वचालित रूप से प्रकार Point जब भी ContextMenu खोला जाता है की एक संलग्न केवल पढ़ने के लिए संपत्ति को अद्यतन करता होगा। प्रयोग कुछ इस तरह दिखेगा:

<ContextMenu x:Name="_menu" local:TrackBehavior.TrackOpenLocation="True"> 
    <MenuItem Command="..." CommandParameter="{Binding Path=(local:TrackBehavior.OpenLocation), ElementName=_menu}"/> 
</ContextMenu> 

तो TrackOpenLocation जुड़ी संपत्ति ContextMenu के लिए संलग्न और एक दूसरे जुड़ी संपत्ति (OpenLocation) जब भी ContextMenu खोला जाता है अद्यतन करने का काम करता है। तब MenuItem सिर्फ OpenLocation करने के लिए बाध्य स्थान है, जिस पर ContextMenu पिछले खोला था प्राप्त करने के लिए कर सकते हैं।

+0

मुझे लगता है कि शुरुआत में "कमांड पैरामीटर" का अर्थ "कनवर्टर पैरामीटर" नहीं है? –

+0

क्या आप संलग्न व्यवहार विचार को विस्तारित करना चाहते हैं? –

+0

हां, धन्यवाद - निश्चित और विस्तृत। –

1

केंट के जवाब के अलावा, एक "मानक तरीका" के बारे में सोचते हैं। उदा जब एक ListBox एक ContextMenu है, आप मेनू की स्थिति की जरूरत नहीं है, क्योंकि चयनित आइटम से पहले मेनू पॉप निर्धारित है। इसलिए, यदि आपके नियंत्रण में कुछ ऐसा होगा जो राइट क्लिक पर "चयनित" हो जाता है ...

+0

हमम ... इसमें कुछ संभावना है। –

+0

मैं आपके दोनों सुझावों का उपयोग कर समाप्त हुआ। ऐसे समय होते हैं जब क्लिक बच्चे के नियंत्रण पर नहीं होता है, इसलिए मुझे संलग्न व्यवहार के साथ प्वाइंट अनुवाद पर केंट के सुझाव की आवश्यकता होती है। जब कोई आइटम चुना गया था, तो मैंने इसके बजाय उस आइटम का उपयोग किया था। धन्यवाद! –

4

केंट के जवाब से इसे जारी रखते हुए, मैं उसके संलग्न संपत्ति सुझाव का इस्तेमाल किया और इस के साथ समाप्त हो गया (जोश स्मिथ के example for attached behaviors उपयोग करते हुए):

public static class TrackBehavior 
{ 
public static readonly DependencyProperty TrackOpenLocationProperty = DependencyProperty.RegisterAttached("TrackOpenLocation", typeof(bool), typeof(TrackBehavior), new UIPropertyMetadata(false, OnTrackOpenLocationChanged)); 

public static bool GetTrackOpenLocation(ContextMenu item) 
{ 
    return (bool)item.GetValue(TrackOpenLocationProperty); 
} 

public static void SetTrackOpenLocation(ContextMenu item, bool value) 
{ 
    item.SetValue(TrackOpenLocationProperty, value); 
} 

public static readonly DependencyProperty OpenLocationProperty = DependencyProperty.RegisterAttached("OpenLocation", typeof(Point), typeof(TrackBehavior), new UIPropertyMetadata(new Point())); 

public static Point GetOpenLocation(ContextMenu item) 
{ 
    return (Point)item.GetValue(OpenLocationProperty); 
} 

public static void SetOpenLocation(ContextMenu item, Point value) 
{ 
    item.SetValue(OpenLocationProperty, value); 
} 

static void OnTrackOpenLocationChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
{ 
    var menu = dependencyObject as ContextMenu; 
    if (menu == null) 
    { 
    return; 
    } 

    if (!(e.NewValue is bool)) 
    { 
    return; 
    } 

    if ((bool)e.NewValue) 
    { 
    menu.Opened += menu_Opened; 

    } 
    else 
    { 
    menu.Opened -= menu_Opened; 
    } 
} 

static void menu_Opened(object sender, RoutedEventArgs e) 
{ 
    if (!ReferenceEquals(sender, e.OriginalSource)) 
    { 
    return; 
    } 

    var menu = e.OriginalSource as ContextMenu; 
    if (menu != null) 
    { 
    SetOpenLocation(menu, Mouse.GetPosition(menu.PlacementTarget)); 
    } 
} 
} 

और फिर Xaml में उपयोग करने के लिए, तुम बस जरूरत है:

NameScope.SetNameScope(menu, NameScope.GetNameScope(this)); 

चोर को:

<ContextMenu x:Name="menu" Common:TrackBehavior.TrackOpenLocation="True"> 
<MenuItem Command="{Binding SomeCommand}" CommandParameter="{Binding Path=(Common:TrackBehavior.OpenLocation), ElementName=menu}" Header="Menu Text"/> 
</ContextMenu> 

हालांकि, मैं भी जोड़ने के लिए की जरूरत मेरे विचार का संरक्षक, अन्यथा CommandParameter के लिए बाध्यकारी ElementName=menu नहीं देख सका।

+0

मुझे लगता है कि मुझे नाम के दायरे के साथ एक ही समस्या थी। पोस्ट के लिए धन्यवाद। –

+1

नामकस्कोप हैक की आवश्यकता को दूर करने वाला एक वैकल्पिक समाधान सापेक्ष स्रोत बाध्यकारी का उपयोग करना है: कमांड पैरामीटर = "{बाध्यकारी पथ = (सामान्य: ट्रैकबैवियर। ओपनलोकेशन), सापेक्ष स्रोत = {सापेक्ष स्रोत पूर्ववर्ती प्रकार = ContextMenu}}"। यह मेरे लिए अच्छा काम किया। –

संबंधित मुद्दे