13

मैं एक यूआई के साथ एक विनफॉर्म एप्लिकेशन बना रहा हूं जिसमें केवल NotifyIcon और इसकी गतिशील रूप से आबादी ContextMenuStrip शामिल है। एप्लिकेशन को एक साथ रखने के लिए MainForm है, लेकिन यह कभी दिखाई नहीं दे रहा है।आईओसी: इवेंट हैंडलर पर निर्भरता को तारों

मैंने इसे यथासंभव ठोस बनाने के लिए सेट किया है (ऑब्जेक्ट ग्राफ़ को संभालने के लिए ऑटोफैक का उपयोग करके) और मेरी सफलता से काफी प्रसन्न हूं, ज्यादातर ओ भाग के साथ भी अच्छी तरह से साथ मिल रहा है। विस्तार के साथ मैं वर्तमान में इसे कार्यान्वित कर रहा हूं ऐसा लगता है कि मैंने अपने डिजाइन में एक दोष खोजा है और थोड़ा सा पुनर्निर्माण करने की आवश्यकता है; मुझे लगता है कि जिस तरह से मुझे जाना है, मुझे पता है कि निर्भरता को सही तरीके से परिभाषित करने के तरीके के बारे में थोड़ा अस्पष्ट है।

ऊपर वर्णित अनुसार, मेनू शुरू करने के बाद गतिशील रूप से आबादी वाला है। इस प्रयोजन के लिए, मैं एक IToolStripPopulator इंटरफेस परिभाषित:

public interface IToolStripPopulator 
{ 
    System.Windows.Forms.ToolStrip PopulateToolStrip(System.Windows.Forms.ToolStrip toolstrip, EventHandler itemclick); 
} 

इस का एक कार्यान्वयन MainForm में इंजेक्ट किया जाता है, और Load() विधि ContextMenuStrip और हैंडलर के रूप में परिभाषित किया गया साथ PopulateToolStrip() कहता है। पॉप्युलेटर की निर्भरता केवल मेनू आइटम के लिए उपयोग करने के लिए डेटा प्राप्त करने से संबंधित होती है।

इस अमूर्तता ने कुछ विकासवादी कदमों के माध्यम से अच्छी तरह से काम किया है, लेकिन जब मुझे एक से अधिक ईवेंट हैंडलर की आवश्यकता होती है, तो अब पर्याप्त नहीं है, उदा। क्योंकि मैं मेनू आइटम के कई अलग-अलग समूह बना रहा हूं - अभी भी एक IToolStripPopulator इंटरफ़ेस के पीछे छिपा हुआ है क्योंकि फ़ॉर्म को इसके बारे में चिंतित नहीं होना चाहिए।

जैसा कि मैंने कहा, मुझे लगता है कि मुझे पता है कि सामान्य संरचना की तरह होना चाहिए - मैं कुछ अधिक विशिष्ट करने के लिए IToolStripPopulator इंटरफ़ेस * नाम दिया और एक नया जिसका PopulateToolStrip() विधि एक EventHandler पैरामीटर नहीं ले करता है, जो बजाय में इंजेक्ट किया जाता बनाई ऑब्जेक्ट (कार्यान्वयन आदि द्वारा आवश्यक हैंडलर की संख्या के बारे में अधिक लचीलापन की इजाजत देता है)। इस तरह मेरा "सबसे प्रमुख" IToolStripPopulator किसी भी विशिष्ट संख्या के लिए बहुत आसानी से एडाप्टर हो सकता है।

अब जो मैं अस्पष्ट हूं, वह है जिस तरह से मुझे EventHandler निर्भरताओं को हल करना चाहिए। मुझे लगता है कि हैंडलर को सभी को MainForm में परिभाषित किया जाना चाहिए, क्योंकि मेनू की घटनाओं पर उचित प्रतिक्रिया देने के लिए अन्य सभी निर्भरताओं की आवश्यकता है, और यह मेनू का "मालिक" भी है। इसका मतलब यह होगा कि IToolStripPopulator ऑब्जेक्ट्स के लिए मेरी निर्भरता अंततः मेनफॉर्म में इंजेक्शन वाली MainForm ऑब्जेक्ट पर Lazy<T> का उपयोग करके निर्भरताओं को लेने की आवश्यकता होगी।

public interface IClickHandlerSource 
{ 
    EventHandler GetClickHandler(); 
} 

यह मेरा MainForm द्वारा लागू किया गया था, और मेरे विशिष्ट IToolStripPopulator कार्यान्वयन Lazy<IClickHandlerSource> पर निर्भरता ले लिया:

मेरी पहली सोचा एक IClickHandlerSource इंटरफेस को परिभाषित किया गया था। हालांकि यह काम करता है, यह लचीला है। मुझे या तो संभावित रूप से बढ़ती संख्या में हैंडलर (MainForm कक्षा के साथ ओसीपी का उल्लंघन करने) के लिए अलग-अलग इंटरफेस परिभाषित करना होगा या लगातार IClickHandlerSource (मुख्य रूप से आईएसपी का उल्लंघन करना) का विस्तार करना होगा। सीधे ईवेंट हैंडलर पर निर्भरता लेना उपभोक्ताओं की तरफ से एक अच्छा विचार दिखता है, लेकिन व्यक्तिगत रूप से आलसी उदाहरण (या जैसा) के गुणों के माध्यम से रचनाकारों को तारों से जोड़ना बहुत गन्दा लगता है - यदि संभव हो तो।

मेरे सबसे अच्छा शर्त वर्तमान में इस प्रतीत हो रहा है:

public interface IEventHandlerSource 
{ 
    EventHandler Get(EventHandlerType type); 
} 

इंटरफ़ेस अभी भी MainForm द्वारा कार्यान्वित और एक आलसी सिंगलटन के रूप में इंजेक्ट किया जा जाएगा, और EventHandlerType विभिन्न प्रकार की आवश्यकता के साथ एक कस्टम enum होगा। यह अभी भी बहुत ओसीपी अनुपालन नहीं होगा, लेकिन उचित रूप से लचीला है। EventHandlerType स्पष्ट रूप से प्रत्येक नए प्रकार के ईवेंट हैंडलर के लिए एक बदलाव होगा, जैसा कि MainForm में संकल्प तर्क होगा, नए ईवेंट हैंडलर के अलावा और (संभवतः) IToolStripPopulator के नए लिखित अतिरिक्त कार्यान्वयन के अलावा।

या .... IEventHandlerSource का एक अलग कार्यान्वयन कि (केवल वस्तु के रूप में) Lazy<MainForm> पर निर्भरता लेता है और निराकरण MainForm में परिभाषित विशिष्ट संचालकों को EventHandlerType विकल्प?

मैं वास्तव में MainForm से ईवेंट हैंडलर को एक व्यवहार्य तरीके से प्राप्त करने का एक तरीका सोचने की कोशिश कर रहा हूं, लेकिन अभी यह बिल्कुल प्रतीत नहीं होता है।

यहां मेरा सबसे अच्छा विकल्प क्या है, जो कम से कम ईवेंट हैंडलर के सबसे कमजोर युग्मन और सबसे सुरुचिपूर्ण रिज़ॉल्यूशन प्रदान करता है?

[* हाँ, मैं शायद नाम वास्तव में ओसीपी का अनुपालन करने के लिए छोड़ दिया जाना चाहिए था अकेला, लेकिन यह बेहतर है कि जिस तरह से देखा।]

+2

मैं अपने प्रश्न को कई बार पढ़ा लागू है, लेकिन मैं कुछ जानकारी याद कर रहा हूँ। क्या आप अधिक कोड दिखा सकते हैं? उदाहरण के लिए, 'आईवेन्टहैंडलरसोर्स' के उपभोक्ता कैसा दिखते हैं, और 'आईवेन्टहैंडलरसोर्स' के कार्यान्वयन की तरह कैसा दिखता है, और यह सब कैसे पंजीकृत है? – Steven

उत्तर

0

आप अपने प्रपत्र के भीतर बच्चे घटकों होस्ट कर रहे हैं, और वे मुख्य रूप से पॉप्युलेट कर सकते हैं आवेदन "खोल"।

आपके पास बेस क्लास ShellComponent हो सकता है, जो System.Windows.Forms.ContainerControl से प्राप्त होता है। यह आपको एक डिजाइन सतह भी देगा। IToolStripPopulator पर भरोसा करने के बजाय, आपके पास इस तरह की आईटूल हो सकती है।

public inteface ITool<T> 
{ 
    int ToolIndex { get; } 
    string Category { get; } 
    Action OnClick(T eventArgs); 
} 

ShellComponent में आप हर बार एक दृश्य भरी हुई है MainForm से public List<ITool> OnAddTools(ToolStrip toolStrip) कह सकते हैं,। इस तरह घटक टूलस्ट्रिप को पॉप्युलेट करने के लिए जिम्मेदार होगा।

'शैलकंपोनेंट' तब उन हैंडलरों के लिए आईओसी कंटेनर से पूछेगा जो ITool<T> लागू करते हैं। इस प्रकार आपका ITool<T> ईवेंट को अलग करने का तरीका प्रदान करता है (MainForm, या ContainerControl में) और इसे किसी भी कक्षा में दबाएं। यह आपको तर्कों के लिए जो भी आप पारित करना चाहते हैं उसे परिभाषित करने की अनुमति देता है (जैसा कि MouseClickEventArgs ect के विपरीत है)।

2

सबसे अच्छा विकल्प क्या है, जो कमजोर युग्मन प्रदान करता है और विभिन्न ईवेंट हैंडलर के सुरुचिपूर्ण रिज़ॉल्यूशन प्रदान करता है?

सामान्य समाधान मौजूद नहीं है और यह वैश्विक अनुप्रयोग वास्तुकला पर निर्भर करता है।प्रिज्म में http://martinfowler.com/eaaDev/EventAggregator.html

  • कार्यान्वयन - -

    :

    आप एक loosest युग्मन चाहते हैं, EventAggregator पैटर्न आप इस तरह के मामले में मदद कर सकते हैं (अपने IEventHandlerSource समान है कि करने के लिए)

    लेकिन, वैश्विक घटनाओं का उपयोग महान सावधानी के साथ किया जाना चाहिए - वे धुंध आर्किटेक्चर कर सकते हैं, क्योंकि ईवेंट की सदस्यता लेना कहीं भी संभव होगा।

    डीआई और आईओसी में महत्वपूर्ण बात: कम निर्भरता को उच्च निर्भरता के बारे में नहीं जानना चाहिए। मुझे लगता है, और जैसा कि लियोन ने पहले कहा था, ITool<T> जैसे कुछ इंटरफेस बनाने और MainForm में टूल्स की स्टोर सूची बेहतर बनाने के लिए बेहतर होगा। कुछ क्रियाओं के बाद MainForm इस टूल में कुछ विधियों का आह्वान करेगा।

  • 1

    सबसे पहले, मुझे लगता है कि आपको दावा नहीं करना चाहिए कि आपके मुख्य प्रारूप में सभी ईवेंट हैंडलर होना चाहिए। आप स्पष्ट रूप से इस तथ्य में भाग गए कि विभिन्न जरूरतों के साथ अलग-अलग हैंडलर हैं (और शायद अलग निर्भरताएं), तो उन्हें सभी को एक ही कक्षा में क्यों रखा जाना चाहिए? आप शायद अन्य भाषाओं में घटनाओं को संभालने के तरीके से कुछ प्रेरणा ले सकते हैं। डब्ल्यूपीएफ कमांड का उपयोग करता है, जावा में श्रोताओं हैं। दोनों वस्तुएं हैं, सिर्फ एक प्रतिनिधि नहीं, जिससे उन्हें आईओसी परिदृश्य में निपटना आसान हो जाता है। ऐसा कुछ अनुकरण करना काफी आसान है। आप अपने टूलबार आइटम्स पर टैग का दुरुपयोग कर सकते हैं, जैसे: Binding to commands in WinForms या टूलबार आइटम को सही कमांड के साथ जोड़ने के लिए PopulateToolbar के अंदर लैम्ब्डा एक्सप्रेशन का उपयोग करें (Is there anything wrong with using lambda for winforms event? देखें)। यह माना जा रहा है कि चूंकि PopulateToolbar जानता है कि कौन से आइटमों को बनाने की आवश्यकता है, यह भी पता है कि प्रत्येक आइटम से कौन सी एक्शन/कमांड संबंधित है।

    क्रिया का प्रतिनिधित्व करने वाली वस्तु मुख्य रूप से मुख्य रूप या अन्य कार्यों के स्वतंत्र रूप से इंजेक्शन की जा सकती है। टूलबार आइटम को अपने स्वयं के कार्यों के साथ बाद में जोड़ा जा सकता है या बाद में आपके मुख्य रूप या किसी भी अन्य क्रिया को प्रभावित किए बिना हटाया जा सकता है, प्रत्येक कार्रवाई स्वतंत्र रूप से परीक्षण और प्रतिक्रिया की जा सकती है।

    नीचे की रेखा, EventHandlers के बारे में सोचना बंद करें, क्रियाओं/कमांड के बारे में सोचने के लिए अपने अधिकार में एक इकाई के रूप में सोचना शुरू करें और उपयुक्त पैटर्न के साथ आना आसान हो जाएगा। सुनिश्चित करें कि आप Command Pattern समझते हैं, क्योंकि यह बहुत कुछ है जो आपको यहां चाहिए।

    1

    क्या आपने किसी ईवेंट एग्रीगेटर का उपयोग करने का प्रयास किया है? देखें: Caliburn framework, event Aggregator एक ईवेंट एग्रीगेटर टूलस्ट्रिप को आपके मुख्य रूप से डीक्यूल करेगा।

    public interface IToolStripPopulator 
    { 
        ToolStrip PopulateToolStrip(ToolStrip toolstrip); 
    } 
    

    लपेटें इस तरह की सुविधा के लिए एग्रीगेटर:

    public static class Event 
    { 
        private static readonly IEventAggregator aggregator = new EventAggregator(); 
        public static IEventAggregator Aggregator 
        { 
         get 
         { 
          return aggregator; 
         } 
        } 
    } 
    

    आप उदाहरण के लिए, एक या अधिक ईवेंट वर्गों को परिभाषित:

    public class EventToolStripClick { 
        public object Sender {get;set;} 
        public EventArgs Args {get;set;} 
    } 
    

    नियंत्रक कि toolstrip बनाता में, प्रकाशित क्लिक हैंडलर में कस्टम इवेंट लिखें:

    public void ControllerToolStripClick(object sender, EventArgs args) 
    { 
        Event.Aggregator.Publish(new EventToolStripClick(){Sender=sender,Args=args)}); 
    } 
    

    MainForm में इंटरफ़ेस IHandle

    public class MainForm : Form, IHandle<EventToolStripClick> 
    { 
        ... 
        public void Handle(EventToolStripClick evt) 
        { 
         //your implementation here 
        } 
    }