2013-08-12 8 views
16

में प्रस्तुत करना मैं प्राइमेटिव्स में नियंत्रण को विभाजित करने के लिए सामान्य WPF प्रतिपादन को हाइजैक करना चाहता हूं, लेआउट प्रबंधन करें, बाइंडिंग इत्यादि लागू करें।कस्टम ड्रॉइंग कॉन्टेक्स्ट

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

मेरे योजना पर वास्तविक प्रतिपादन के लिए पुरातन हस्तांतरण पीछा कर रहा है:

  1. एक कस्टम DrawingContext को लागू करें। DrawingContext एक अमूर्त वर्ग है, जो DrawEllipse, DrawText, DrawImage आदि जैसी विधियों का एक समूह परिभाषित करता है - मुझे इस कार्यक्षमता के लिए अपना स्वयं का कार्यान्वयन करने की आवश्यकता होगी।
  2. एक WPF UserControl बनाएं और उसे दिए गए DrawingContext पर प्रस्तुत करने के लिए मजबूर करें।

हालांकि मैं निम्न समस्याओं का सामना किया है:

  1. DrawingContext सार आंतरिक तरीकों void PushGuidelineY1(double coordinate) और void PushGuidelineY2(double leadingCoordinate, double offsetToDrivenCoordinate) है, जो मैं आसानी से ओवरराइड नहीं कर सकते हैं। (शायद इस पर काबू पाने के लिए कुछ चाल है?)
  2. पूरेDrawingContext पर दृश्य प्रस्तुत करने की कोई विधि नहीं है? क्यूं कर?

मैं की तरह

void RenderRecursively(UIElement e, DrawingContext ctx) 
{ 
    e.OnRender(ctx); 
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(e); i++) 
     RenderRecursively((UIElement)VisualTreeHelper.GetChild(e, i), ctx); 
} 

कुछ कर सकते हैं - लेकिन मुझे आश्चर्य है कि एक UIElement रेंडर करने के लिए एक सीधा रास्ता है तो। (बेशक, यह समस्या एक मामूली है, लेकिन इसके लिए कोई आधारभूत संरचना नहीं देखकर मुझे आश्चर्य होता है कि यह सही तरीका है।)

तो, क्या DrawingContext विरासत के लिए लक्षित नहीं है? क्या कस्टम DrawingContext सही दिशा में एक कदम की आपूर्ति करने का पूरा विचार है, या मुझे रणनीति पर पुनर्विचार करने की आवश्यकता है? WPF में समर्थित कस्टम संदर्भ पर चित्रण कर रहा है, या मुझे एक अलग अवरोध बिंदु की आवश्यकता है?

+6

ड्रॉइंग कॉन्टेक्स्ट पर टिप्पणियों से: 'आप कभी भी DrawingContext को तुरंत चालू नहीं करते हैं; हालांकि, आप कुछ तरीकों से ड्राइंग संदर्भ प्राप्त कर सकते हैं, जैसे DrawingGroup.Open और DrawingVisual.RenderOpen.' मेरे लिए इसका मतलब यह है कि वास्तव में * कस्टम * ड्रॉइंग कॉन्टेक्स्ट को आपूर्ति * करने का कोई तरीका नहीं है। – Clemens

+0

@ क्लेमेन: हाँ, मैंने यह टिप्पणी देखी, लेकिन मुझे यह समझ गया कि "आपको इसे स्वयं नहीं बनाना चाहिए, हम इसे आपके लिए आंतरिक रूप से करते हैं; और ड्राइंग विज़ुअल में ड्राइंग के लिए बस ड्रॉइंगविज़ुअल को इसे ठीक से प्रारंभ करने दें"। वैसे भी, दिलचस्प है अगर ड्राइंग के लिए वैध अवरोध बिंदु हैं। – Vlad

+2

DrawingVisual में आकर्षित करने का एकमात्र तरीका DrawingVisual.RenderOpen द्वारा प्रदान किए गए DrawingContext में आकर्षित करना है। विज़ुअल के साथ अपने कस्टम ड्रॉइंग कॉन्टेक्स्ट को जोड़ने का कोई तरीका नहीं है। विचार व्यर्थ है। – Clemens

उत्तर

3

आपको इस समस्या को विपरीत दिशा से संपर्क करने की आवश्यकता हो सकती है। अपना खुद का DrawingContext प्रदान करने के उद्देश्य से, आप इसके बजाय आपको Drawing प्रदान करने के लिए WPF से पूछ सकते हैं। तो यह आपके द्वारा लक्षित 'पुश' दृष्टिकोण की तुलना में 'पुल' दृष्टिकोण 'से अधिक है, लेकिन इसे उसी स्थान पर जाना संभव हो सकता है: यदि आपके पास Drawing है जो भाग की उपस्थिति का पूर्ण प्रतिनिधित्व है दृश्य पेड़ की, यह एक डेटा संरचना है जिसे आप चल सकते हैं और कॉल से खोजे गए सभी चीजों को एक कस्टम DrawingContext पर खोज सकते हैं।

मेरा मानना ​​है कि यह वही बुनियादी दृष्टिकोण है कि एक्सपीएस दस्तावेज़ निर्यात सेबेस्टियन उल्लेख आंतरिक रूप से उपयोग करता है। लेकिन इसका उपयोग सीधे एक्सपीएस एपीआई

के माध्यम से इसका उपयोग करने से अधिक प्रत्यक्ष दृष्टिकोण है, दिल में कुछ सरल है: VisualTreeHelper.GetDrawing। यह DrawingGroup देता है। (Drawing एक अमूर्त बेस क्लास है।) यह प्रलेखन पृष्ठ आपको दिखाता है कि आप जिस पेड़ को वापस लेते हैं उसके माध्यम से कैसे चलना है। दुर्भाग्यवश, यह पूरी नौकरी नहीं करता है: यह केवल उस नोड के लिए दृश्य प्रदान करता है जो आप इसे कॉल करने के लिए करते हैं, और यदि उस नोड में बच्चे हैं, तो उन्हें शामिल नहीं किया जाएगा।

तो दुर्भाग्य से, आपको कुछ ऐसा लिखना होगा जो दृश्य पेड़ को दोहराता है, जैसा कि आप पहले ही योजना बना रहे थे। और आपको सही परिणामों को प्राप्त करने के लिए दृश्य से जुड़े किसी भी अस्पष्ट मास्क, गैर-मुखौटा-आधारित अस्पष्टता, क्लिप क्षेत्र, प्रभाव और परिवर्तनों को संभालने की भी आवश्यकता होगी; आपको अपने प्रस्तावित दृष्टिकोण को सही तरीके से काम करने के लिए भी ऐसा करना होगा, इसलिए वास्तव में कुछ भी वास्तव में नहीं बदलता है। (सेबस्टियन के रूप में एक्सपीएस एपीआई का उपयोग करने का एक संभावित लाभ यह है कि यह आपके लिए यह सब कुछ करता है। हालांकि, एक्सपीएस दस्तावेज़ से आपके इच्छित फॉर्म में जानकारी निकालने की आपकी समस्या है, और इससे आपको खोने वाली जानकारी समाप्त हो सकती है अपनी खुद की DrawingContext हो सकता है आप एक वर्ग है कि से FrameworkElement या UIElement या यहाँ तक कि Visual कि अपनी OnRender विधि में अपनी गतिविधियों करता निकला बना सकते हैं इसके बजाय लिखने की कोशिश कर की रक्षा करने के लिए चाहते हो सकता है।)

+0

मेरे परीक्षणों में यह काम नहीं किया। मुझे लगता है कि आपको सुझाए गए दृष्टिकोण का उपयोग करने की आवश्यकता है क्योंकि 'GetDrawing'' नियंत्रण 'के लिए' शून्य 'उत्पन्न करेगा क्योंकि' ऑनरेंडर 'के दौरान खींचे गए दृश्यों को उस सहायक विधि द्वारा समझा नहीं जाता है -' सीमा 'की गणना करने का प्रयास करें और आपको 'शून्य' मिलेगा। – Sebastian

+0

यदि मैं 'सीमा 'पर' GetDrawing' 'कहता हूं जिसमें गैर-शून्य' सीमा ब्रश 'और एक गैर-शून्य' सीमाचित्र 'है, तो मुझे एक गैर-शून्य' ड्रॉइंग ग्रुप 'वापस मिल जाता है जिसमें एक ही' ज्यामिति ड्रॉइंग 'होता है 'सीमा 'के रूप में आकार,' आयताकार जीमेट्री 'को' ज्यामिति 'के रूप में, और' पेन 'जो' मोटाई 'और' सीमा ब्रश 'सेटिंग्स से मेल खाता है। क्या आपने किसी भी मौके पर या तो एक परीक्षण किया था) एक सीमा जिसने वास्तव में कुछ भी नहीं पेंट किया था या बी) एक सीमा जिसने अभी तक अपने दृश्यों को महसूस नहीं किया था? –

+0

आप यहां सही हो सकते हैं - सीमा पहले कभी कल्पना नहीं की गई थी। शायद यह मुद्दा है, हालांकि मैंने अभी तक जांच नहीं की है। झूठे आरोप के लिए खेद है! – Sebastian

2

मैंने WinRT के लिए FlowDocumentViewer बनाने के लिए समान काम करने की कोशिश की। लेकिन डब्ल्यूपीएफ की तुलना में विनरेट बहुत कम परिपक्व होने के कारण, यह मूल परत (थ्रेड रेंडर के माध्यम से) को बहुत अधिक प्रतिनिधि देता है, मैं कहीं भी नहीं मिल सका। लेकिन मैंने यही सीखा है और मुझे उम्मीद है कि मैं इसे अच्छी तरह समझा रहा हूं।

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

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

यदि आपको डब्ल्यूपीएफ प्रतिपादन को प्रतिस्थापित करना है तो आपकी सबसे अच्छी शर्त उपयोगकर्ता नियंत्रण बनाने के लिए है, कॉल को व्यवस्थित करें और मापें ओवरराइड करें और DrawingVisual.RenderOpen() का उपयोग करके प्रत्येक तत्व को DrawingVisual में प्रस्तुत करें और उन्हें अपने कोड से व्यवस्थित करें। डेटा बाइंडिंग नोटिफिकेशन प्रबंधित करना एक और चीज होगी जो आपको स्वयं करना होगा।

बहुत ही रोचक परियोजना की तरह लगता है। सौभाग्य!

+0

असल में, बहुत सारे आंतरिक 'ड्रॉइंग कॉन्टेक्स्ट' हैं, जो हिट परीक्षण जैसी साधारण चीजों के लिए उपयोग किए जाते हैं। मेरा अंतिम लक्ष्य WPF को कुछ दस्तावेज़ प्रकार में प्रस्तुत करना है, इसलिए एक कस्टम UserControl मदद नहीं करेगा। आपकी सलाह के लिए वैसे भी धन्यवाद! – Vlad

4

मुझे लगता है कि आपका दृष्टिकोण काम नहीं करेगा, क्योंकि (जैसा कि अन्य ने उल्लेख किया है) आप अपना DrawingContext कार्यान्वयन प्रदान नहीं कर सकते हैं।

मैं इसके बजाय निम्न का सुझाव देता हूं: WPF प्रतिपादन को "फ़्लैट" करने के लिए, WPF को अपने दृश्यों को एक्सपीएस दस्तावेज़ में निर्यात करें। उस प्रक्रिया के दौरान, सभी प्रतिपादन मूल रूप से सरल प्रतिपादन प्राइमेटिव के रूप में गिने जाते हैं और जिनके साथ आप छोड़े गए हैं Canvas एस, मूल आकार, ग्लिफ और अन्य ड्राइंग प्राइमेटिव हैं।

फिर दस्तावेज़ के पृष्ठों में दृश्यों पर पुनरावृत्त करें। जहां तक ​​मुझे पता है कि परिणामी दृश्य में प्राइमेटिव शामिल होंगे, केवल OnRender पर कॉल करने की आवश्यकता नहीं है। इसके बजाए यह आपको दृश्य उदाहरणों का बाहरी रूप से आत्मनिर्भर करने में सक्षम बनाता है (instanceof-कैस्केड और गुणों को पढ़ने/व्याख्या करने का उपयोग करके)। यह अभी भी काफी काम है, क्योंकि आपको डब्ल्यूपीएफ की तरह गुणों की व्याख्या करने की आवश्यकता है, लेकिन जहां तक ​​मैं देख सकता हूं, यह कम से कम कई प्रमुख उपयोग-मामलों के लिए काम करना चाहिए।

+0

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

+0

आपके उत्तर के लिए बहुत बहुत धन्यवाद। यद्यपि मैंने आपके द्वारा प्रस्तावित तरीके से जाने का विकल्प नहीं चुना है, लेकिन यह स्पष्ट रूप से एक बहुत अच्छा विचार है और अधिक अपवर्तनीय हकदार है। – Vlad

1

। आपको अभी भी Draw[Something] के दिए गए कार्यान्वयन का उपयोग करना होगा, लेकिन आप संचालन के तर्क और आदेश के नियंत्रण में होंगे।आप अभी भी माध्यमिक स्रोत से प्राइमेटिव और निर्देशों का विश्लेषण कर सकते हैं और आपका एक UIElement/FrameworkElement रनटाइम पर निर्देश लिख सकता है।

+0

यह काम करेगा, लेकिन केवल कस्टम विजुअल के लिए। मेरी समस्या क्या है पकड़ने के लिए है टेक्स्टब्लॉक का ऑनरेंडर कर रहा है। – Vlad

+0

यह एक दिलचस्प समस्या है। अगर आपको उत्तर मिल जाए तो अपने अनुभव साझा करने पर विचार करें। :-) –

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