जब अतुल्यकालिक कार्य एक बुरा UX बनाते हैं


9

मैं एक COM ऐड-इन लिख रहा हूं जो एक आईडीई का विस्तार कर रहा है जिसकी सख्त जरूरत है। इसमें कई विशेषताएं शामिल हैं, लेकिन इस पद की खातिर इसे 2 तक सीमित कर दें:

  • वहाँ एक है कोड एक्सप्लोरर toolwindow कि प्रदर्शित करता है एक treeview उपयोगकर्ता नेविगेट मॉड्यूल और उनके सदस्यों की सुविधा देता है।
  • एक नहीं है कोड निरीक्षण toolwindow कि प्रदर्शित करता है एक DataGridView उपयोगकर्ता नेविगेट कोड मुद्दों की सुविधा देता है और उन्हें स्वचालित रूप से ठीक है।

दोनों उपकरणों में एक "ताज़ा करें" बटन है जो एक अतुल्यकालिक कार्य शुरू करता है जो सभी खोले गए प्रोजेक्टों में सभी कोड को पार्स करता है; कोड एक्सप्लोरर पार्स परिणाम का उपयोग करता है के निर्माण के लिए treeview , और कोड निरीक्षण पार्स परिणाम का उपयोग करता कोड समस्याओं का पता लगाने और उसके परिणामों में प्रदर्शित करने के लिए DataGridView

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

तो मैंने क्या किया, मैंने अपने पार्सर क्लास को एक इवेंट प्रोवाइडर बनाया, जिसमें फीचर्स दर्ज हो सकते हैं:

    private void _parser_ParseCompleted(object sender, ParseCompletedEventArgs e)
    {
        Control.Invoke((MethodInvoker) delegate
        {
            Control.SolutionTree.Nodes.Clear();
            foreach (var result in e.ParseResults)
            {
                var node = new TreeNode(result.Project.Name);
                node.ImageKey = "Hourglass";
                node.SelectedImageKey = node.ImageKey;

                AddProjectNodes(result, node);
                Control.SolutionTree.Nodes.Add(node);
            }
            Control.EnableRefresh();
        });
    }

    private void _parser_ParseStarted(object sender, ParseStartedEventArgs e)
    {
        Control.Invoke((MethodInvoker) delegate
        {
            Control.EnableRefresh(false);
            Control.SolutionTree.Nodes.Clear();
            foreach (var name in e.ProjectNames)
            {
                var node = new TreeNode(name + " (parsing...)");
                node.ImageKey = "Hourglass";
                node.SelectedImageKey = node.ImageKey;

                Control.SolutionTree.Nodes.Add(node);
            }
        });
    }

और यह काम करता है। मुझे जो समस्या आ रही है, वह यह है ... यह काम करता है - मेरा मतलब है, जब कोड निरीक्षण ताज़ा हो जाते हैं, तो पार्सर कोड एक्सप्लोरर (और बाकी सभी) को कहता है "दोस्त, किसी की पार्सिंग, कुछ भी आप इसके बारे में करना चाहते हैं? " - और जब पार्सिंग पूरी हो जाती है, तो पार्सर अपने श्रोताओं से कहता है "दोस्तों, मेरे पास आपके लिए नए परिणाम हैं, आप इसके बारे में कुछ भी करना चाहते हैं?"।

इस समस्या के बारे में बताने के लिए आपको एक उदाहरण के माध्यम से चलता हूं:

  • उपयोगकर्ता कोड एक्सप्लोरर लाता है, जो उपयोगकर्ता को बताता है "मैं यहां काम कर रहा हूं"; उपयोगकर्ता आईडीई में काम करना जारी रखता है, कोड एक्सप्लोरर खुद को फिर से बनाता है, जीवन सुंदर है।
  • उपयोगकर्ता फिर कोड निरीक्षण लाता है, जो उपयोगकर्ता को बताता है "मैं यहां काम कर रहा हूं"; पार्सर कोड एक्सप्लोरर को कहता है "यार, किसी की पार्सिंग, कुछ भी आप इसके बारे में करना चाहते हैं?" - कोड एक्सप्लोरर उपयोगकर्ता को बताता है "मैं यहां काम कर रहा हूं"; उपयोगकर्ता अभी भी IDE में काम कर सकता है, लेकिन कोड एक्सप्लोरर को नेविगेट नहीं कर सकता क्योंकि यह ताज़ा है। और वह कोड निरीक्षण के पूरा होने की प्रतीक्षा कर रहा है।
  • उपयोगकर्ता निरीक्षण परिणामों में एक कोड मुद्दा देखता है जिसे वे संबोधित करना चाहते हैं; वे इसे नेविगेट करने के लिए डबल-क्लिक करते हैं, पुष्टि करते हैं कि कोड के साथ कोई समस्या है, और "फिक्स" बटन पर क्लिक करें। मॉड्यूल को संशोधित किया गया था और इसे फिर से पार्स करने की आवश्यकता है, इसलिए कोड निरीक्षण इसके साथ आगे बढ़ते हैं; कोड एक्सप्लोरर उपयोगकर्ता को बताता है "मैं यहां काम कर रहा हूं", ...

देखें यह कहाँ जा रहा है? मुझे यह पसंद नहीं है, और मुझे यकीन है कि उपयोगकर्ता इसे पसंद नहीं करेंगे। मैं क्या खो रहा हूँ? मुझे सुविधाओं के बीच पार्स परिणाम साझा करने के बारे में कैसे जाना चाहिए, लेकिन फिर भी उपयोगकर्ता को नियंत्रण में रखना चाहिए कि फीचर को अपना काम कब करना चाहिए ?

जो कारण मैं पूछ रहा हूं, वह इसलिए है क्योंकि मुझे लगा कि यदि मैंने वास्तविक कार्य को स्थगित कर दिया, जब तक कि उपयोगकर्ता सक्रिय रूप से ताज़ा करने का निर्णय नहीं लेता है, और पार्स परिणामों को "कैश्ड" करता है क्योंकि वे आते हैं ... अच्छी तरह से तब मैं एक ट्रीव्यू ताज़ा करूँगा और संभवतः बासी पार्स परिणाम में कोड मुद्दों का पता लगाना ... जो मुझे शाब्दिक रूप से एक वर्ग में वापस लाता है, जहां प्रत्येक सुविधा अपने स्वयं के पार्स परिणामों के साथ काम करती है: क्या कोई तरीका है जो मैं सुविधाओं के बीच पार्स परिणाम साझा कर सकता हूं और एक प्यारा यूएक्स हो सकता है?

कोड , लेकिन मैं कोड की तलाश नहीं कर रहा हूं, मैं अवधारणाओं की तलाश कर रहा हूं ।


2
एक FYI करें, हमारे पास एक UserExperience.SE साइट भी है। मेरा मानना ​​है कि यह यहाँ विषय है क्योंकि यह उपयोगकर्ता इंटरफ़ेस से अधिक कोड डिज़ाइन पर चर्चा कर रहा है, लेकिन मैं आपको इस मामले में जानकारी देना चाहता हूं कि आपके परिवर्तन UI साइड की ओर अधिक बहाव करते हैं न कि समस्या के कोड / डिज़ाइन पक्ष।

जब आप पार्स कर रहे होते हैं, तो क्या यह ऑल-ऑर-नथिंग ऑपरेशन है? उदाहरण के लिए: क्या एक फाइल में परिवर्तन एक पूर्ण प्रतिक्षेप को ट्रिगर करता है, या केवल उस फ़ाइल और उन पर निर्भर करने वालों के लिए?
मॉर्गन

@ मॉर्गन दो चीजें हैं: VBAParserANTLR द्वारा उत्पन्न की गई है और मुझे एक पार्स ट्री देता है, लेकिन विशेषताएं इसका उपभोग नहीं करती हैं। RubberduckParserपार्स पेड़ लेता है, यह चलता है, और मुद्दों पर एक VBProjectParseResultस्थापित करता है, Declarationवस्तुओं है कि सभी अपने Referencesसंकल्प लिया - कि की क्या विशेषताएं इनपुट के लिए ले .. हाँ, यह बहुत ज्यादा एक सभी या कुछ भी नहीं की स्थिति है। RubberduckParserनहीं फिर से पार्स मॉड्यूल है कि हालांकि संशोधित नहीं किया गया है करने के लिए स्मार्ट पर्याप्त है। लेकिन अगर वहाँ एक अड़चन है यह पार्सिंग के साथ नहीं है, तो यह कोड निरीक्षण के साथ है।
मैथ्यू गुइंडन

4
मुझे लगता है, मैं इसे इस तरह से करूँगा: जब उपयोगकर्ता एक ताज़ा करता है, तो टूलविडो पार्स को ट्रिगर करता है और दिखाता है कि यह काम कर रहा है। अन्य टूलविंडो को अभी तक अधिसूचित नहीं किया गया है, वे पुरानी जानकारी प्रदर्शित करते रहते हैं। जब तक पार्सर खत्म नहीं हो जाता। उस समय, पार्सर नई जानकारी के साथ अपने विचार को ताज़ा करने के लिए सभी टूलवॉच को संकेत देगा। जब पार्सर काम कर रहा होता है, तो उपयोगकर्ता को किसी अन्य टूलविंडो में जाना चाहिए, वह विंडो "वर्किंग ..." स्थिति में भी प्रवेश करेगी और एक पुन: संकेत देगी। तब पार्सर एक ही समय में सभी विंडो पर अप-टू-डेट जानकारी देने के लिए शुरू होगा।
विस्फ़ोटक - मोनिका

2
@cmaster मैं उस टिप्पणी को एक उत्तर के रूप में भी उकेरूंगा।
रबडक Rubber

जवाबों:


7

जिस तरह से मैं शायद यह दृष्टिकोण करूंगा वह सही परिणाम प्रदान करने पर कम ध्यान केंद्रित करना होगा, और इसके बजाय एक सर्वोत्तम प्रयास दृष्टिकोण पर ध्यान केंद्रित करना होगा। इसके परिणामस्वरूप कम से कम निम्नलिखित परिवर्तन होंगे:

  • उस तर्क को रूपांतरित करें जो वर्तमान में आरंभ करने के बजाय अनुरोध करने के लिए फिर से शुरू होता है।

    पुनः पार्स अनुरोध करने का तर्क कुछ इस तरह से लग सकता है:

    IF parseIsRunning IS false
      startParsingThread()
    ELSE
      SET shouldParse TO true
    END
    

    यह पार्सर को लपेटने वाले तर्क के साथ जोड़ा जाएगा, जो कुछ इस तरह दिख सकता है:

    SET parseIsRunning TO true
    DO 
      SET shouldParse TO false
      doParsing()
    WHILE shouldParse IS true
    SET parseIsRunning TO false
    

    महत्वपूर्ण बात यह है कि पार्सर सबसे हाल के रि-पार्स अनुरोध तक सम्मानित किया गया है, लेकिन किसी भी समय एक से अधिक पार्सर नहीं चल रहा है।

  • ParseStartedकॉलबैक निकालें । पुनः पार्स अनुरोध करना अब एक आग है और ऑपरेशन भूल जाओ।

    वैकल्पिक रूप से, इसे GUI के कुछ भाग से ताज़ा ताज़ा संकेतक दिखाने के अलावा और कुछ नहीं करने के लिए कनवर्ट करें, जो उपयोगकर्ता सहभागिता को अवरुद्ध नहीं करता है।

  • बासी परिणामों के लिए न्यूनतम हैंडलिंग प्रदान करने का प्रयास करें।

    कोड एक्सप्लोरर के मामले में, यह उतनी ही सरल हो सकती है, जब उपयोगकर्ता एक सटीक नाम नहीं पाया जाता है, तो विधि के लिए ऊपर या नीचे एक उचित संख्या में लाइनों को देख रहा है।

    मुझे यकीन नहीं है कि कोड इंस्पेक्टर के लिए क्या उपयुक्त होगा।

मुझे कार्यान्वयन विवरणों पर यकीन नहीं है, लेकिन कुल मिलाकर, यह बहुत कुछ इसी तरह से है कि नेटबीन्स संपादक इस व्यवहार को कैसे संभालता है। यह इंगित करना बहुत जल्दी है कि यह वर्तमान में ताज़ा है, लेकिन कार्यक्षमता तक पहुंच को अवरुद्ध नहीं करता है।

बासी परिणाम अक्सर पर्याप्त होते हैं - खासकर जब कोई परिणाम नहीं की तुलना में।


1
उत्कृष्ट अंक, लेकिन मेरे पास एक सवाल है: मैं ParseStarted[ताज़ा] बटन ( Control.EnableRefresh(false)) को अक्षम करने के लिए उपयोग कर रहा हूं । यदि मैं उस कॉलबैक को हटाता हूं, और उपयोगकर्ता को इसे क्लिक करने देता हूं ... तो मैं खुद को ऐसी स्थिति में डालूंगा जहां मेरे पास दो समवर्ती कार्य हैं जो पार्सिंग कर रहे हैं ... मैं अन्य सभी कार्यात्मकताओं पर ताज़ा करने के बिना इसे कैसे टाल सकता हूं, जबकि कोई पार्सिंग है?
मथिउ गुइंडन

@ MatMug मैंने समस्या के उस पहलू को शामिल करने के लिए अपना जवाब अपडेट किया।
मॉर्गन

मैं इस दृष्टिकोण से सहमत हूं, सिवाय इसके कि मैं अभी भी एक ParseStartedघटना रखूंगा, यदि आप यूआई (या अन्य घटक) को कभी-कभी उपयोगकर्ता को चेतावनी देने की अनुमति देना चाहते हैं तो एक पुनरावृत्ति हो रही है। बेशक, आप दस्तावेज़ों को कॉल करने का प्रयास कर सकते हैं, उपयोगकर्ता को वर्तमान पार्स परिणामों के बासी () होने का उपयोग करने से रोकने की कोशिश नहीं करनी चाहिए ।
मार्क हर्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.