سؤال

أقوم بتطوير تطبيق WinForms في C#. لدي خبرة محدودة في برمجة واجهة المستخدم الرسومية ، واضطررت إلى تعلم الكثير أثناء الطيران. ومع ذلك ، إليك ما أقوم ببناءه.

انظر واجهة المستخدم الرسومية العامة انظر إلى الرابط التالي:

واجهة المستخدم الرسومية http://img227.imageshack.us/img227/1084/program0.jpg

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

لقد كنت أدرس الكثير حول أنماط تصميم واجهة المستخدم الرسومية ، والنمط الذي أرغب في تنفيذه هو العرض السلبي (انظر http://martinfowler.com/eaadev/passivescreen.html). أنا أبحث عن بعض المساعدة حول كيفية جمع كل هذا معًا.

خلفية:

1) بناءً على ما ينقر عليه المستخدم في "TreeView" ، ستعرض "القائمة" في الزاوية اليسرى السفلية قائمة بالكائنات التي يمكنها ملء منطقة "المحرر". قد تكون هذه الكائنات عبارة عن مربع نص أو dataGridView. يقوم المستخدم بتبديل القائمة لاختيار ما يريد رؤيته في "المحرر"

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

3) المشكلة في الطريقة التي كنت أفعلها بالأشياء هي أنه من المستحيل اختباره ، وبالتالي الانتقال إلى نمط تصميم العرض السلبي MVP-esque

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

أسئلة:

1) هل أحتاج إلى تنفيذ واجهة/عرض واحدة كبيرة لكل "نظرة" للبرنامج ، ثم تنفيذ عمليات العرض الفرعية/العرض الفرعي لكل من Treeview ، المحرر ، المسجل ، إلخ؟ أم أن هناك "هيكل" أفضل للقيام بذلك؟

2) عندما يتعلق الأمر بـ "تسليم" الأحداث من العرض إلى مقدم العرض/وحدة التحكم (مهما كانت المصطلحات التي ترغب في استخدامها في نمط تصميم العرض السلبي) ، ما هي الطريقة التي يجب أن أفعلها؟ في بعض الأحيان لدي خصائص بسيطة تحتاج إلى تحديث ، وأحيانًا أحتاج إلى سلسلة كاملة من الخطوات التي تتكشف.

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

شكرا مقدما!

دانيال

هل كانت مفيدة؟

المحلول

فيما يلي مثال بسيط يوضح مفهوم المشاهدات السلبية باستخدام نمط تصميم MVP. لأننا نستخدم وجهات النظر السلبية ، فإن العرض ليس لديه معرفة بالمقدم. سيقوم مقدم العرض ببساطة بالاشتراك في الأحداث التي نشرتها The View and Act وفقًا لذلك.

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

فيما يلي عقد يصف طريقة عرض بسيطة سيتم استخدامها لعرض معلومات العميل

public interface ICustomerManagementView
{
    void InitializeCustomers(ICustomer[] customers);
    void DisplayCustomer(ICustomer customer);
    event EventHandler<EventArgs<ICustomer>> SelectedCustomerChanged;
}

يكشف طريقة واحدة initializeCustomers سيتم استخدامها لتهيئة عرضنا باستخدام كائنات من نموذجنا.

لدينا أيضا حدث SelectionCustomerChanged سيتم استخدام ذلك من قبل مقدم العرض لدينا لتلقي إشعار بأن إجراء ما حدث في الرأي.

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

public class CustomerManagementPresenter
{
    private ICustomer _selectedCustomer;
    private readonly ICustomerManagementView _managementView;
    private readonly ICustomerRepository _customerRepository;

    public CustomerManagementPresenter(ICustomerManagementView managementView, ICustomerRepository customerRepository)
    {
        _managementView = managementView;
        _managementView.SelectedCustomerChanged += this.SelectedCustomerChanged;

        _customerRepository = customerRepository;

        _managementView.InitializeCustomers(_customerRepository.FetchCustomers());
    }

    private void SelectedCustomerChanged(object sender, EventArgs<ICustomer> args)
    {
        // Perform some logic here to update the view
        if(_selectedCustomer != args.Value)
        {
            _selectedCustomer = args.Value;
            _managementView.DisplayCustomer(_selectedCustomer);
        }
    }
}

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

في المُنشئ ، لدينا سطرين مهمين من التعليمات البرمجية ، أولاً ، اشتركنا في الحدث المحدد في عرضنا ، هنا يمكننا تنفيذ الإجراءات المرتبطة بها. ثانياً ، اتصلنا بـ LiStilaizeCustomers مع بيانات من المستودع.

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

public partial class CustomerManagementView : Form, ICustomerManagementView
{
    public CustomerManagementView()
    {
        this.InitializeComponents();
    }

    public void InitializeCustomers(ICustomer[] customers)
    {
        // Populate the tree view with customer details
    }

    public void DisplayCustomer(ICustomer customer)
    {
        // Display the customer...
    }

    // Event handler that responds to node selection
    private void CustomerTreeViewAfterSelect(object sender, TreeViewEventArgs e)
    {
        var customer = e.Node.Tag as ICustomer;
        if(customer != null)
        {
            this.OnSelectedCustomerChanged(new EventArgs<ICustomer>(customer));
        }
    }

    // Protected method so that we can raise our event
    protected virtual void OnSelectedCustomerChanged(EventArgs<ICustomer> args)
    {
        var eventHandler = this.SelectedCustomerChanged;
        if(eventHandler != null)
        {
            eventHandler.Invoke(this, args);
        }
    }

    // Our view will raise an event each time the selected customer changes
    public event EventHandler<EventArgs<ICustomer>> SelectedCustomerChanged;
}

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

تحرير: args الحدث المخصص المخصص

public class EventArgs<T> : EventArgs
{
    private readonly T _value;

    public EventArgs(T value)
    {
        _value = value;
    }

    public T Value
    {
        get { return _value; }
    }
}

نصائح أخرى

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

لذلك في حالتك ، قد يكون لديك iformmanager الذي ستنفذه نافذتك الرئيسية ، ثم ifileManager ، iloggerwindow إلخ ، إلخ.

على الرغم من أنه قد يكون من المبالغة بعض الشيء في الاستخدام ، إلا أنني أقترح أن تكون قد ألقيت نظرة على مصنع برامج العميل الذكي (من فريق Microsoft Patterns والممارسات) - لم يعد يتم تطويره بنشاط ، ولكنه يحتوي على تنفيذ جيد لـ MVP و MVP و هل هذا النوع من المشاركة في تكوين الأشياء بشكل جيد ، لذلك قد يمنحك بعض الأفكار الجيدة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top