أكثر

إضافة مؤشر STAThread إلى ESRI Addin

إضافة مؤشر STAThread إلى ESRI Addin


أنا عالق بعض الشيء في الوقت الحالي ، لدي c # addin ، والذي يحتوي كجزء من إحدى الطرق ، على كائن SavefileDialog. يحتوي الرمز أيضًا على Timer. خطوات المستخدم هي:

  • انقر على الخريطة
  • يتم رسم الهندسة
  • تم تحديث الخريطة
  • ينتظر الموقت مرور 5 ثوانٍ (وقت كافٍ لتحديث الخريطة)
  • يظهر مربع حوار يسأل المستخدم سؤالاً
  • إذا حددوا نعم ، يظهر كائن SaveFileDialog.

يبدو أنه عندما يظهر هذا قبل ظهور SaveFileDialog مباشرة ، أتلقى الخطأ التالي

يجب تعيين مؤشر الترابط الحالي على وضع جزء مؤشر ترابط واحد (STA) قبل إجراء مكالمات OLE. تأكد من أن الوظيفة الرئيسية الخاصة بك تحتوي على سمة STAThreadAttribute محددة عليها.

أين أضع في الكود الخاص بي السمة [STAThread] حيث لا أمتلك وظيفة رئيسية. الوظيفة الإضافية عبارة عن شريط أدوات وزر واحد.


بدلاً من استخدام Timer (الذي يعمل على مؤشر ترابط منفصل) ، ماذا عن استخدام الأحداث الداخلية: IActiveViewEvents.ViewRefreshed (بدء التحديث) ثم IActiveViewEvents.AfterDraw (التحديث النهائي). إذا كنت تستمع إلى AfterDraw مع مرحلة السحبesriViewDrawPhase.esriViewForegroundأوesriViewDrawPhase.esriViewAll(قد تحتاج إلى التجربة قليلاً لمعرفة ما يناسبك) ثم يتم تشغيل الحدث بعد تحديث الخريطة ، بغض النظر عن المدة التي يستغرقها.

لديك قيمة منطقية (عامة) تقول "لقد اتصلت بهذا التحديث" أو سيظهر مربع حوار الحفظ في كل مرة يتم فيها تحديث العرض:

// global bool pIveCalledThisRefresh = false ؛ // في النموذج تحميل Form1_Load الفراغ الخاص (مرسل الكائن ، EventArgs e) {IApplication m_application = ArcMap.Application؛ IMxDocument gDoc = (IMxDocument) m_application.Document ؛ IScreenDisplay gScreenDis = gDoc.ActiveView.ScreenDisplay ؛ ((IActiveViewEvents_Event) gDoc.FocusMap) .AfterDraw + = جديد IActiveViewEvents_AfterDrawEventHandler (My_AfterDraw) ؛ } // في حدث الزر الفراغ الخاص Go_Click (مرسل الكائن ، EventArgs e) {pIveCalledThisRefresh = true؛ // قم ببعض الأشياء وقم بتحديث الخريطة pIveCalledThisRefresh = false ؛ // Refresh back to normal} // after draw event void My_AfterDraw (عرض IDisplay ، مرحلة esriViewDrawPhase) {if (! pIveCalledThisRefresh) return؛ // تخطي عمليات التحديث ما لم تكن قد تسببت في حدوثها إذا (stage == esriViewDrawPhase.esriViewForeground) // جرب هذا ، راجع المرحلة التي تريدها {if (MyDialog.ShowDialog () == System.Windows.Forms.DialogResult.OK) {// احفظك}}}

إذا كنت لا تزال ترغب في الانتظار بعد انتهاء التحديث ، احصل على الوقت ككائن DateTime ، أضف بضع ثوان ثم قارن مع DateTime.Compare () معDoEvents ()في الحلقة:

void My_AfterDraw (عرض IDisplay ، مرحلة esriViewDrawPhase) {if (! pIveCalledThisRefresh) return ؛ // تخطي التحديثات إلا إذا كنت قد تسببت في حدوثها إذا (stage == esriViewDrawPhase.esriViewForeground) // جرب هذا ، انظر إلى المرحلة التي تريدها {pSaveTime = DateTime.Now؛ pSaveTime.AddSeconds (5.0) ، // إجباري 5 ثوانٍ تفعل {// حلقة من لاشيء System.Windows.Forms.Application.DoEvents ()؛ // يتيح للعمليات الأخرى القيام بعملها} while (DateTime.Compare (pSaveTime، DateTime.Now)> 0)؛ إذا (MyDialog.ShowDialog () == System.Windows.Forms.DialogResult.OK) {// قم بحفظك}}}

يتم تنفيذ كل هذا على نفس مؤشر الترابط الذي سيخفف سلاسل عمليات عبور كائن Esri ، وهو أمر غير مسموح به لأن جميع كائنات Esri ليست آمنة لمؤشر الترابط.


إذا كنت تستخدم System.Timers.Timer أو System.Threading.Timer ، فإن الكود الذي يتم تشغيله بواسطة المؤقت يحدث في مؤشر ترابط عامل. لن يتم وضع علامة STAThread هذا على مؤشر الترابط وبالتالي لا يمكن استخدام SaveFileDialog.

يمكنك إما استخدام System.Windows.Forms.Timer ، وهو متزامن وعلى مؤشر ترابط واجهة المستخدم الرئيسي ، أو استخدام Control.Invoke لتشغيل التعليمات البرمجية الخاصة بك على مؤشر الترابط الرئيسي (أو IDispatcher.Invoke إذا كنت تستخدم WPF بدلاً من WinForms).


عند تطبيق STAThreadAttribute ، فإنه يغير حالة الجزء الخاص بمؤشر الترابط الحالي ليكون مترابطًا واحدًا. دون الدخول في مناقشة ضخمة حول COM والترابط ، تضمن هذه السمة آلية الاتصال بين مؤشر الترابط الحالي والخيوط الأخرى التي قد ترغب في التحدث إليها عبر COM. عندما تستخدم نماذج Windows ، بناءً على الميزة التي تستخدمها ، فقد تستخدم COM interop للتواصل مع مكونات نظام التشغيل. ومن الأمثلة الجيدة على ذلك الحافظة ومربعات حوار الملفات.

وبعبارة أخرى ، يتم التعامل مع الاتصال بمكونات نظام التشغيل مثل الحافظة من خلال COM ويتطلب ذلك تغيير حالة الجزء الخاص بمؤشر الترابط باستخدام مؤشر ترابط STA.


يتم استخدام السمة STAThread للإشارة إلى COM التي يجب أن يستخدمها التطبيق شقة ذات مؤشر ترابط واحد (STA). هذا يؤثر فقط على كائنات COM، وهو مطلوب فقط لأن بعض مربعات الحوار التي تستخدم COM (مثل FileOpenDialog) تحتاج إلى تحديد نموذج الترابط الصحيح.

على حد علمي ، فإن القليل جدًا (إن وجد) من تطوير الألعاب سيستفيد من COM باستثناء مربعات حوار نماذج Windows ، وبالتالي لن يكون لهذا أي تأثير ، فهو مطلوب ببساطة لهذه الحوارات.

إذا كنت تستخدم كائنات COM فأنت مايو تريد أن تنظر في نماذج خيوط COM لفهم الآثار المترتبة على هذا الإعداد تمامًا ، ولكن الإصدار المختصر هو أنه في STA سيتم تشغيل جميع طرق COM على مؤشر ترابط واحد (مؤشر ترابط واجهة المستخدم في هذه الحالة) حتى إذا تم استدعاؤه على آخر مسلك.

تحديث: يتوفر DirectX كمجموعة من كائنات COM ، لكنني لست متأكدًا من طراز مؤشر الترابط الذي تتطلبه.


  1. لديك خاصية ثابتة عامة UserName يمكن لأي شخص تعيينها في أي مكان في التعليمات البرمجية الخاصة بك. أنت لم تفصل استخدام هذه الخاصية.

إذا كان نموذج تسجيل الدخول هو الذي يجب أن يقوم بتحديثه ولن يتم تحديثه مرة أخرى ، فقم بتعيين فئة البرنامج الخاصة بك على هذا الحقل.

إذا كانت هناك فئة أخرى تقوم بتحديث هذا الحقل ، فربما لا تنتمي هذه الخاصية هنا.

لديك بعض التعليمات البرمجية المكررة ، لذلك يجب أن تكون هناك طريقة للقيام بعمل أفضل.

من وجهة نظري ، أنت تقوم بالعديد من الأشياء المختلفة في طريقتك الرئيسية ، ربما يمكنك وضع هذه العمليات في طرق منفصلة: التهيئة ، تسجيل الدخول ، البدء.

لقد وضعت مقدم العرض الرئيسي في خاصية العلامة ، والتي أعتقد أنها تنتمي إلى خاصية معينة. بهذه الطريقة يمكن للنموذج الرئيسي التحكم في من يمكنه الوصول إليه ، وإلا فإن أي كائن لديه حق الوصول إلى النموذج الرئيسي يمكنه استرداد العلامة وبالتالي المقدم. مشكلة أخرى هي أن خاصية Tag هي كائن ، لذلك سيكون عليك تحويلها في كل مرة تريد استخدامها.


1 إجابة 1

أنا لا أعارض بشدة استخدام المناطق ، لكني ضد استخدامها داخل من الأساليب. أنا أعتبرها رائحة كود محددة. يجب استخراج المناطق الموجودة داخل الأساليب في طريقتها الخاصة واستدعاؤها. على سبيل المثال

الآن ، إذا كان يلزم إجراء تغيير في كيفية إعداد أي من هذه الأشياء ، فيمكنك الانتقال مباشرةً إلى هذه الطريقة بدلاً من البحث في مئات الأسطر من التعليمات البرمجية لجزء الإعداد الذي تبحث عنه.

تمام. اسمحوا لي أن أعيد صياغة هذا. طرق الاستخراج. طرق الاستخراج في كل مكان. طريقة keyboardHook_KeyDown هي 59 سطرًا. لا بد لي من التمرير العديد مرات لمعرفة الطريقة برمتها. نحن بشر ، لا يمكننا الاحتفاظ بهذا القدر في رؤوسنا دفعة واحدة. طرق الاستخراج ليست فقط لإزالة التكرار من التعليمات البرمجية الخاصة بنا. إنه لجعل الأساليب مسؤولة منفردة وصغيرة بما يكفي لفهمها في لمحة. إذا أردنا التفاصيل ، فإننا نتعمق في الأساليب الأصغر. بخلاف ذلك ، نحصل على نظرة عامة سريعة على ما يحدث دون أن نشغل أنفسنا بالتفاصيل.

فئة الإعدادات الخاصة بك أفضل بكثير في هذا الصدد ، ولكن هناك مشكلات أخرى معها.

  • جميع العمليات ثابتة ، لذا يمكنك أيضًا جعل الفصل نفسه ثابتًا. ليس هناك من معنى في وجود حالات منه على الإطلاق ، ولا توجد دولة.
  • يمكن القول إنه من الأفضل استخدام تكوين XML على سجل Windows. يرجى الاطلاع على ما هو App.config في C # .Net وكيف يمكنني استخدامه؟ ومع ذلك ، فلا حرج في استخدام التسجيل. يمكن اعتبارها مسألة تفضيل.

إذا قررت التمسك بالسجل ، فيجب عليك تغيير المكان الذي تسجل فيه مفاتيحك.

ألق نظرة على المفاتيح الأخرى الموجودة ضمن البرنامج. لاحظ كيف أن جميعهم (معظمهم) في شكل Company NameOfSoftware . يجب عليك اتباع هذه الاتفاقية. فهو يجعل من غير المحتمل أن تواجه تعارض "مساحة الاسم" مع بعض البرامج الأخرى. نظرًا لأن هذا برنامج مفتوح المصدر ، أوصي باستخدام اسم مستخدم github الخاص بك.


واجهة ISpatialReferenceFactory3

يوفر الوصول إلى الأعضاء الذين ينشئون بيانات عمودية أو أنظمة إحداثية.

توفر المنتج

متى يجب استخدام

يوفر ISpatialReferenceFactory3 طرقًا لدعم نظام الإحداثيات الرأسية وتحويل المراجع المكانية منخفضة الدقة الحالية إلى مرجع مكاني عالي الدقة (أو العكس).

أعضاء

وصف
بناء عالية الدقة المكانية المرجع ينشئ مرجعًا مكانيًا عالي الدقة بناءً على مرجع مكاني موجود. xy / z / mDoubler هو عدد مرات مضاعفة الدقة المعنية. ستعثر القيمة صفر على أقصى مضاعفة لتلك الدقة.
بناء منخفضة الدقة المكانية المرجع أنشئ مرجعًا مكانيًا منخفض الدقة بنفس عامل المقياس مثل المدخلات عالية الدقة ، ولكن بنطاق مجال مختلف. إذا لم يتمكن نطاق المجال المحسوب من تغطية مدى البيانات المحدد ، يتم إرجاع خطأ.
CreateDatum ينشئ مسندًا محددًا مسبقًا.
إنشاء ESRIS المكاني المرجع ينشئ نظامًا مرجعيًا مكانيًا ويحدده من المخزن المؤقت ESRISpatialReference المحدد.
إنشاء ESRISpatialReference FromPRJ يقوم بإنشاء إسناد مكاني من سلسلة PRJ.
إنشاء ESRISpatialReferenceFromPRJFile ينشئ مرجعًا مكانيًا من ملف PRJ.
إنشاء ESRISpatialReferenceInfo ينشئ نظامًا مرجعيًا مكانيًا ويحدده من المخزن المؤقت ESRISpatialReference المحدد.
إنشاء ESRISpatialReferenceInfoFromPRJ ينشئ مرجعًا مكانيًا من سلسلة PRJ.
إنشاء ESRISpatialReferenceInfoFromPRJFile يقوم بإنشاء إسناد مكاني من ملف PRJ.
CreateGeographicCoordinateSystem ينشئ نظام إحداثيات جغرافي محدد مسبقًا.
خلق التحول الجغرافي ينشئ تحويلاً محددًا مسبقًا بين أنظمة الإحداثيات الجغرافية.
إنشاء معلمة ينشئ معلمة محددة مسبقًا.
CreatePredefinedAngularUnits ينشئ قائمة بوحدات زاوية محددة مسبقًا.
إنشاء المراجع المحددة مسبقًا يُنشئ قائمة بقائمة من البيانات المحددة مسبقًا.
CreatePredefinedGeographicTransformations ينشئ قائمة بالتحولات الجغرافية المحددة مسبقًا.
CreatePredefinedLinearUnits ينشئ قائمة بالوحدات الخطية المحددة مسبقًا.
CreatePredefinedPrimeMeridians ينشئ قائمة بخطوط الطول الأولية المحددة مسبقًا.
إنشاء مشاريع محددة مسبقًا ينشئ قائمة بالإسقاطات المحددة مسبقًا.
إنشاء الكائنات الدقيقة المحددة مسبقًا ينشئ قائمة بالأجسام الشبه الكروية المحددة مسبقًا.
إنشاء أنظمة محددة مسبقًا ينشئ قائمة بأنظمة إحداثيات عمودية محددة مسبقًا.
CreatePredefinedVerticalDatums ينشئ قائمة بالمراجع الرأسية المحددة مسبقًا.
قم بإنشاء PrimeMeridian ينشئ خط طول أولي محدد مسبقًا.
CreateProjectedCoordinateSystem يُنشئ نظام إحداثيات مُسقط مُعرَّف مسبقًا.
CreateProject ينشئ إسقاطًا محددًا مسبقًا.
CreateSpatialReference ينشئ مرجعًا مكانيًا محددًا مسبقًا من srID.
CreateSpheroid ينشئ شكلًا كرويًا محددًا مسبقًا.
إنشاء وحدة ينشئ وحدة قياس محددة مسبقًا.
CreateVerticalCoordinateSystem ينشئ نظام إحداثيات رأسية محدد مسبقًا من تعداد أو كود معرف.
CreateVerticalCoordinateSystemFromESRISpatialReference ينشئ نظام إحداثيات رأسي من تنسيق السلسلة الخاص به.
CreateVerticalDatum ينشئ مسندًا عموديًا محددًا مسبقًا من تعداد أو كود معرّف.
تصدير معلومات ESRISpatialReferenceInfoToPRJ يصدر مرجعًا مكانيًا إلى ملف PRJ.
تصدير ESRISpatialReferenceToPRJFile يصدر مرجعًا مكانيًا إلى ملف PRJ.
GeoTransformationDefaults تُرجع قائمة بالتحولات الجغرافية الافتراضية.
GetPredefinedGeographicTransformations تُرجع قائمة بالتحولات الجغرافية المحددة مسبقًا.

واجهات موروثة

واجهات وصف
ISpatialReferenceFactory2 يوفر الوصول إلى الأعضاء الذين يقومون بإنشاء أنواع مختلفة من مكونات الإسناد المكاني.
ISPATIALReferenceFactory يوفر الوصول إلى الأعضاء الذين يقومون بإنشاء أنواع مختلفة من مكونات الإسناد المكاني.

فئات CoClass التي تنفذ ISpatialReferenceFactory3

ملاحظات

ال ISpatialReferenceFactory3 للواجهة طريقتان مفيدتان عند العمل بمراجع مكانية منخفضة وعالية الدقة. ينشئ ConstructHighPrecisionSpatialReference مرجعًا مكانيًا عالي الدقة من مرجع مكاني منخفض الدقة. سيضمن استخدام هذه الطريقة أن قيم الإحداثيات سوف تتناسب تمامًا مع شبكة الشبكة الجديدة الأكثر كثافة. كل تقاطع للشبكة الأصلية هو تقاطع للشبكة الجديدة. ستنشئ ConstructLowPrecisionSpatialReference مرجعًا مكانيًا منخفض الدقة من مرجع مكاني عالي الدقة موجود. يمكنك أن تطلب الحفاظ على قيمة الدقة الجديدة ، عادةً على حساب نطاق المجال XY.

عند استخدام هذه الواجهة في تطبيق وحدة التحكم ، يجب وضع علامة على الروتين على أنه مترابط واحد. يمكن وضع علامة على فئة على أنها ذات مؤشر ترابط فردي عن طريق إضافة السمة [STAThread] التي تسبق إعلان الروتين مباشرة.

[موضوع STAThread]
الفراغ الثابت الرئيسي (سلسلة [] args)
<
>

عند استخدام هذه الواجهة في تطبيق وحدة التحكم ، يجب وضع علامة على الروتين على أنه مترابط واحد. يمكن وضع علامة على فئة على أنها ذات مؤشر ترابط فردي عن طريق إضافة السمة [STAThread] التي تسبق إعلان الروتين مباشرة.


ما هي أفضل طريقة لبناء مصنع باستخدام NInject؟

أنا مرتاح جدًا لحقن التبعية باستخدام NInject في MVC3. أثناء العمل في تطبيق MVC3 ، قمت بتطوير مصنع إنشاء وحدة تحكم مخصص باستخدام NInject ، لذا فإن أي وحدة تحكم يتم إنشاؤها ستحتوي على تبعيات يتم حقنها من خلال مصنع أجهزة التحكم هذا.

الآن بدأت في تطوير تطبيق windows ، وأريد استخدام Application wide Dependency Injection. أي يجب إنشاء كل كائن من خلال NInject ، وذلك لتسهيل اختبار الوحدة. يرجى إرشادي للتأكد من أن كل كائن تم إنشاؤه يجب أن يكون من خلال NInject Factory فقط.

على سبيل المثال ، إذا كنت أكتب على أي نموذج windows في حدث Button_Click:

و TestClass له أي اعتماد على ، على سبيل المثال ، ITest ، فيجب حله تلقائيًا. أعلم أنه يمكنني استخدام:

لكني أجد أنه من الممل القيام بذلك في كل مرة أرغب في إنشاء كائن. كما أنه يفرض على المطور إنشاء الكائن بطريقة معينة. هل يمكن تحسينها؟

هل يمكنني الحصول على مستودع مركزي لإنشاء كائن وبعد ذلك سيستخدم كل إنشاء كائن هذا المستودع تلقائيًا؟


يمكنك إنشاء ملف بيان وضبط التطبيق ليطلب امتيازات إدارية. سيؤدي هذا إلى تشغيل مطالبة مستخدم UAC مع الشاشة المعتمة عند تشغيل التطبيق الخاص بك دون الحاجة إلى أي رمز من جانبك.

راجع MSDN للحصول على تفاصيل دموية:

يمكن إنشاء هذا الملف باستخدام أي محرر نصوص. يجب أن يكون لملف بيان التطبيق نفس اسم الملف القابل للتنفيذ الهدف بملحق .manifest.

هناك بعض الأشياء التي أود تغييرها في التعليمات البرمجية الخاصة بك لجعلها أكثر وضوحًا أو تمتزج جيدًا مع المعايير.

أود تغيير اسم هذه الطريقة إلى RunningAsAdmin ويجب أن يكون المبدأ المتغير صغيرًا لمطابقة مخطط التسمية القياسي لمتغيرات camelCasing.

كما أود تغيير هيكل بيان if الخاص بك في الطريقة الرئيسية.

بدلاً من إبطال الطريقة المنطقية ، أود تركها تعمل ، فأنت تتحقق منها بطريقة أو بأخرى على أي حال حتى يبدو النفي خاطئًا

هل نحتاج إلى Elevate لإرجاع قيمة منطقية؟ مما يمكنني رؤيته لا يفعل أي شيء بقيمة صواب / خطأ.

دعنا فقط نجعلها طريقة باطلة ونتركها تقوم بالأشياء ونخرج منها ، لا توجد بيانات عودة.


. لصق قابل للتنفيذ - مليون "وسيطة"

الاختلافات في الأمر: لصق | أمر

الصق محتويات حافظة Windows في إدخال أمر الأمر المحدد.

لصق | أمر | مقطع

الصق محتويات حافظة Windows في إدخال الأمر المحدد ثم انسخ مخرجاته إلى حافظة Windows.

على سبيل المثال ، الصق | فرز | Clip يفرز محتويات حافظة Windows. يتطلب: مقطع

لصق> اسم الملف

لصق> example.txt

يلصق محتويات حافظة Windows في ملف اسم الملف المحدد.

لصق | فرز> اسم الملف

يفرز محتويات حافظة Windows ويحفظ الإخراج الفرز في ملف اسم الملف المحدد.


1 إجابة 1

كما أفهمها ، التطبيق جذر التكوين هو ببساطة حيث يحدث التكوين - من الناحية المثالية أقرب ما يمكن إلى نقطة الدخول. لا تقوم هذه الفئة بتغليف "جذر التكوين" ، فهي تقوم فقط بتغليف IKernel وتحرم جذر التكوين الفعلي في النهاية من كل المرونة والقوة التي يوفرها Ninject ، من خلال فرض طريق واحد صحيح للوصول إلى النواة.

الشيء هو أن مجرد وجود تلك الطبقة يثير العلم الأحمر الكبير: لأنه موجود، ونظرًا لأنه يخزن مثيل kernel على مستوى النوع (ثابت) ، فمن السهل جدًا الحصول على هذا السطر من التعليمات البرمجية في أي مكان في المشروع:

. ولديك ، في فئة ApplicationShellController - وبما أنك كشفت عن طرق ثابتة ، فلن تضطر حتى إلى مررها على أنها تبعية . لكنها أ محدد الخدمة ومع ذلك ، نظرًا لأن ApplicationShellController يحتوي على امتداد الاعتماد على نوع CompositionRoot - أي أن الجذر لم يعد موجودًا في الجذر!

يبدو أن بت LINQ أكثر تعقيدًا مما ينبغي. يُرجع ResolveAll & ltT & gt قيمة IEnumerable & ltT & gt ، لذا فإن Cast & ltT & gt زائدة عن الحاجة. ثم اختر لا إسقاط أي شيء ، وأين يمكن أن يكون المسند لـ FirstOrDefault:

إذا كان القصد هو العودة واحد مع ذلك ، والقصد من ذلك هو أنه لا يوجد سوى واحد وحدة تحكم للتعامل مع المسار المحدد ، ثم يجب عليك استخدام .SingleOrDefault بدلاً من. FirstOrDefault ، لتوضيح النية (وستطرح الطريقة استثناءً إذا كان هناك اثنان أو أكثر من وحدات التحكم لمسار معين ، بدلاً من العودة ، حسنًا ، بعض وحدات التحكم العشوائية من أي نوع تشعر أنها تمنحك إياها).

إذا فهمت بنيتك بشكل صحيح ، فلن تحتاج فعليًا إلى مثيل جديد لوحدة التحكم في كل مرة يتم فيها استدعاء هذه الطريقة.

لكن هذا ما تحصل عليه.

أعتقد أن مُنشئ ApplicationShellController يجب أن يبدو كما يلي:

يرى Ninject أن تبعية IEnumerable & ltIDocumentController & gt كفرصة للربط المتعدد: سيقوم تلقائيًا بحل مثيل لكل شيء يرتبط بـ IDocumentController ، ويمرره.

لا تحتاج إلى سمة [Inject] هنا. لا تستخدم سمات [إدخال]. تخيل أن لديك جذر التكوين الخاص بك في مجموعة مختلفة تمامًا - التجميع الوحيد في الحل الخاص بك هو ذلك يحتاج إشارة إلى Ninject ، هو التجميع مع جذر التكوين. يجب حظر الاعتماد على Ninject في أي مكان آخر ، يجب كتابة الكود الخاص بك بطريقة لا تعرفها حاوية IoC تمامًا: وجود سمة [Inject] في رمز عملك يشير إلى أن رمز عملك قادر على العمل مع IKernel في أي وقت. الوقت ، ولا ترغب في إعطاء هذا الانطباع - سواء كان ذلك فقط لأنه في الوقت المناسب ، سيتم الحفاظ على الكود بواسطة شخص اخر (نعم، أنت في المستقبل هو شخص آخر!) ، ومن الجيد دائمًا إرسال رسالة واضحة إلى ذلك معيل المستقبل، أن حاوية IoC تعيش وتموت في ركنها الصغير ولا تنتقل إلى أي مكان.

بالطبع، هناك استثناءات. على سبيل المثال ، قد ترغب في استخدام ملحق Ninject.Logging وإدخال المُنشئ ILogger إلى أي نوع يدعم التسجيل.

لذلك ، سأقوم بإزالة فئة CompositionRoot ، ونقل IKernel مباشرة إلى نقطة الدخول ، والرجوع إلى الاتفاقيات ثم افعل شيئًا مثل هذا:

يمكن لامتداد الاصطلاحات أن يفعل أكثر بكثير من ربط جميع الواجهات تلقائيًا في تعليمة واحدة - كان هذا فقط لتوضيح النقطة التي لا تحتاج إلى الاتصال بها يدويًا .Bind & ltISmurf & gt () لربط كل سنفور في القرية بشكل صريح.

على سبيل المثال ، يمكنك فرض اصطلاح تسمية في مساحة اسم معينة ، بحيث لا يرتبط أي شيء لا ينتهي بـ "Controller" بـ IDocumentController ، على سبيل المثال.

حل IApplicationShellView ، سيصل Ninject إلى نوع ApplicationShellView. وهناك مشكلة:

لا يوجد شيء لحقن! يقترن المنظر تمامًا بوحدة التحكم في الخرسانة! لكن انتظر ، لماذا يجب أن يعرف العرض عن المتحكم الرئيسي؟

تحتاج إلى عكس التبعية هنا (قلب السيطرة أليس كذلك؟) ، وبدلاً من الحصول على المنظر يسأل وحدة تحكم قم بعمل ما، احصل على العرض يخبار وحدة التحكم يجب أن تفعل شيئًا ما لأن المستخدم نقر على زر.

WinForms هو كل شيء عن الأحداث التي سأستخدمها للحدث.

لقد أدى عكس العلاقة بين وحدة التحكم والعرض إلى كسر التبعية الدائرية: الآن كل ما يحتاجه المتحكم هو التعامل مع أحداث العرض!