ایجاد منوی Task برای Property ها

ms_vb

Member
سلام
کسی میدونه چطور میشه برای یک Component منوی Task یا همون مثلث کوچیکی که بالای بعضی Component هاست (مثل Task شی TextBox که شامل multiline می باشد) رو ایجاد کرد
 

the_king

مدیرکل انجمن
سلام
کسی میدونه چطور میشه برای یک Component منوی Task یا همون مثلث کوچیکی که بالای بعضی Component هاست (مثل Task شی TextBox که شامل multiline می باشد) رو ایجاد کرد

ابتدا یک کلاس جدید خواهید ساخت که از کلاس DesignerActionList ارث بری کنه، این کلاس قراره شامل همه
مواردی باشه که می خواهید داخل اون پنجره Tasks دیده بشه، یعنی Property ها که کاربر مقدارشون رو مشخص کنه
و روتین ها که کاربر با کلیک کردن رویشون کاری رو انجام بده.

بعد یک کلاس دیگر خواهید ساخت که از کلاس ControlDesigner ارث بری کنه، وظیفه این کلاس صرفا ارائه مجموعه
مواردی است که داخل کلاس قبلی آماده کردید.

نهایتا هم در کلاس اصلی Component تون این کلاس ای که از ControlDesigner ارث بری کرده رو به عنوان Designer
معرفی می کنید.

اگه زبان برنامه نویسی رو مشخص کنید مثال عملی می زنم.
 

ms_vb

Member
ممنون از جوابتون
زبان برنامه نویسیم Vb.Net هست
آمدم امتحان کنم برای ساخت کلاس مربوط به DesignerActionList میگه باید یک روتین New تعریف کنی
تعریف کردم میگه آرگومانت هم میخواد!
اگه لطف کنید و مثال بزنید ممنون میشم
 
آخرین ویرایش:

the_king

مدیرکل انجمن
ممنون از جوابتون
زبان برنامه نویسیم Vb.Net هست
آمدم امتحان کنم برای ساخت کلاس مربوط به DesignerActionList میگه باید یک روتین New تعریف کنی
تعریف کردم میگه آرگومانت هم میخواد!
اگه لطف کنید و مثال بزنید ممنون میشم
ابتدا در منوی Project ویژوال استدیو گزینه Add Reference را انتخاب کرده و System.Design را در لیست
پیدا کرده و اضافه کنید.

فرضا یک کلاس Component1 به پروژه تان اضافه کرده اید (منوی Project، گزینه Add Component ) که می خواهید
مواردی را به پنجره Tasks اش اضافه شود :
کد:
Public Class Component1

End Class

کتابخانه های مورد نیاز رو در ابتدای کد اضافه می کنیم :
کد:
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Windows.Forms.Design

Public Class Component1

End Class

سپس کلاسی به اسم ActionList1 تعریف می کنیم که از DesignerActionList ارث بری کند :
کد:
Friend Class ActionList1
    Inherits DesignerActionList

    Public Sub New(ByVal component As IComponent)
        MyBase.New(component)
    End Sub

End Class
مواردی که باید داخل Tasks نمایش داده شوند رو باید در این کلاس مشخص کنید، اگر قراره مقداری وارد بشه از Property و
اگر قراره فرمانی اجرا بشه از Sub استفاده می کنیم. مثلا دو Property با نام های FullName و
BackColor و یک Sub با نام DefaultValues تعریف می کنیم :
کد:
    Private mFullName As String
    Private mBackColor As Color

    Public Property FullName() As String
        Get
            Return mFullName
        End Get
        Set(ByVal value As String)
            mFullName = value
        End Set
    End Property

    Public Property BackColor() As Color
        Get
            Return mBackColor
        End Get
        Set(ByVal value As Color)
            mBackColor = value
        End Set
    End Property

    Public Sub DefaultValues()
        mFullName = "My Name"
        mBackColor = Color.Blue
[COLOR="Blue"]        Dim d As DesignerActionUIService = GetService(GetType(DesignerActionUIService))
        d.Refresh(Me.Component)[/COLOR]
    End Sub
اصولا هر Property یک متغیر داره که یا ازش مقدار Property را می خوانید یا مقدار Property را داخلش می نویسید.
اون کد آبی رنگ برای اینه که بعد از تغییر دادن مقدار Property ها، Designer ویژوال استدیو از تغییر کردن شان
مطلع شود و مقادیر جدید را نمایش دهد. اگر حذف شون کنید مقادیر عوض می شوند اما چون Designer مطلع نمیشه
مقادیر نمایشی در حین نمایش پنجره Tasks به ظاهر تغییری نمی کنند.

کلاس ما نیاز به یک GetSortedActionItems هم دارد که باید Overrides شود و مهم ترین بخش کلاس است،
هر چیزی که داخل پنجره Tasks نمایش داده می شود اینجا مشخص خواهد شد :
کد:
    Public Overrides Function GetSortedActionItems() As System.ComponentModel.Design.DesignerActionItemCollection
        Dim items As New DesignerActionItemCollection
.
.
.
        Return items
    End Function

مثلا دو بخش مجزا (Header) ایجاد می کنیم که در یکی FullName و BackColor و در دیگری DefaultValues
نمایش داده شوند، برای هر آیتم هم یک عنوان نمایشی و توضیحات اضافه می کنیم :
کد:
    Public Overrides Function GetSortedActionItems() As System.ComponentModel.Design.DesignerActionItemCollection
        Dim items As New DesignerActionItemCollection
[COLOR="Blue"]        items.Add(New DesignerActionHeaderItem("My Properties"))
        items.Add(New DesignerActionHeaderItem("My Methods"))
        items.Add(New DesignerActionPropertyItem("FullName" _
            , "Full name", "My Properties", "Please enter your full name."))
        items.Add(New DesignerActionPropertyItem("BackColor" _
            , "Back color", "My Properties", "Please enter back color."))
        items.Add(New DesignerActionMethodItem(Me, "DefaultValues" _
            , "Default values", "My Methods", "Reset properties."))[/COLOR]
        Return items
    End Function

حالا کلاس ActionList1 آماده است، باید یک کلاس دیگر بسازیم که از ComponentDesigner (اگر برای
Component ها Tasks می سازید) یا ControlDesigner (اگر برای Control ها Tasks می سازید) ارث بری کند.
این کلاس ساختار ساده ای دارد، فقط باید اون کلاسی که قبلا ساخته ایم را به عنوان لیست Action ها برگرداند.
مثلا کلاس Designer1 را تعریف می کنیم که از لیستی که ActionList1 ارائه می کند استفاده خواهد کرد :
کد:
Friend Class Designer1
    Inherits ComponentDesigner

    Private list As DesignerActionListCollection

    Public Overrides ReadOnly Property ActionLists() As System.ComponentModel.Design.DesignerActionListCollection
        Get
            If list Is Nothing Then
                list = New DesignerActionListCollection()
                list.Add(New [B][COLOR="Blue"]ActionList1[/COLOR][/B](Me.Component))
            End If
            Return list
        End Get
    End Property
End Class

حالا دقیقا قبل از کلاس اصلی Component1 مان یک سطر کد اضافه می کنیم که کلاس Designer1 را به عنوان
Designer این Component معرفی کند :
کد:
[COLOR="Blue"]<System.ComponentModel.Designer(GetType(Designer1))> _[/COLOR]
Public Class Component1

End Class

کد را یکبار کامپایل کنید تا تغییرات روی Component1 اعمال شوند.
البته اینها اساس کار اند، اگه بخواهید این مقادیر با Component اصلی در ارتباط باشند به کد نویسی بیشتری
نیاز دارید، مثلا اگر بخواهید مقادیر بعد از خروج از برنامه Save شوند باید Serialization رو برای Property ها
فعال کنید. در مثال پیوستی اینکار انجام شده.

یک مثال کامل ضمیمه این پست می باشد. TasksSample.zip
 

پیوست ها

  • TasksSample.zip
    61.3 کیلوبایت · بازدیدها: 1

ms_vb

Member
خیلی خیلی ممنون:rose:
خدا انشاالله یک در دنیا 100 در آخرت بهت بده
فقط یه سوال بزرگوار:
در برنامه من شی اصلی از Panel ارث بری میکنه این کار باعث شد که یک شی در سینی(Try) ویژوال اضافه بشه و تنظیمات از اونجا انجام بشه تازه محدوده شی هم ناپدید شد! اگه لطف کنید و بگید که این مشکل رو چه جور حلش کنم ممنون می شم
 

the_king

مدیرکل انجمن
خیلی خیلی ممنون:rose:
خدا انشاالله یک در دنیا 100 در آخرت بهت بده
فقط یه سوال بزرگوار:
در برنامه من شی اصلی از Panel ارث بری میکنه این کار باعث شد که یک شی در سینی(Try) ویژوال اضافه بشه و تنظیمات از اونجا انجام بشه تازه محدوده شی هم ناپدید شد! اگه لطف کنید و بگید که این مشکل رو چه جور حلش کنم ممنون می شم

به ظاهر شما دارید بجای Control از Component استفاده می کنید، کلاس هایی که از Component ها ارث بری
می کنند جایشان همانجا در Tray است.

کد را که برای کلاس تان نوشته اید با این کد پیوستی مقایسه کنید. این مثال پیوستی یک کلاس است که از
Panel ارث بری کرده، یعنی از خانواده Control ها است، اسم Component1 اش ارتباطی با شیء Component ندارد.
Property ئه BackColor را از کد حذف کردم چون Control و Panel خودشان BackColor دارند.

TasksSample2.zip
 

پیوست ها

  • TasksSample2.zip
    59.6 کیلوبایت · بازدیدها: 2

ms_vb

Member
حالا یه سوال دیگه
چطور میشه اون Task های خود شی panel رو حذف کرد(Dock in parent container)
 

the_king

مدیرکل انجمن
حالا یه سوال دیگه
چطور میشه اون Task های خود شی panel رو حذف کرد(Dock in parent container)

راهی برای اینکار نمی شناسم، حتی با Shadows کردن Dock هم همچنان نشان داده میشه.
به Designer اش هم که کلا با کد دسترسی نخواهید داشت.
 

ms_vb

Member
ممنون از جوابتون
ببخشید
یه سوال دیگه برام پیش اومده چه طور میشه بعضی از گزینه ها رو بسته به انتخابهای قبلی حذف کرد یا نمایش داد مانند Task های Combobox
 

the_king

مدیرکل انجمن
ممنون از جوابتون
ببخشید
یه سوال دیگه برام پیش اومده چه طور میشه بعضی از گزینه ها رو بسته به انتخابهای قبلی حذف کرد یا نمایش داد مانند Task های Combobox

لیست گزینه ها در تابع ()GetSortedActionItems داخل کلاسی ایجاد میشه که از DesignerActionList ارث بری کرده اید،
شما هر زمانی که اراده کنید می توانید با استفاده از DesignerActionUIService این لیست رو Refresh کنید،
که در نتیجه مجددا این تابع ()GetSortedActionItems اجرا میشه.
نمونه کد Refresh کردن در کد هایی که نوشته بودم هست :
کد:
        Dim d As DesignerActionUIService = GetService(GetType(DesignerActionUIService))
        d.Refresh(Me.Component)

حالا شما باید دو بخش از کد رو ویرایش کنید، یکی جایی است که این لیست گزینه ها ایجاد می شه، یعنی
تابع ()DesignerActionUIService، مثلا کاری می کنیم که فقط زمانی FullName نمایش داده بشه که
کاربر در BackColor رنگ Transparent رو انتخاب نکرده :
کد:
[COLOR="Gray"]    Public Overrides Function GetSortedActionItems() As System.ComponentModel.Design.DesignerActionItemCollection[/COLOR]
.
.
.
        Dim prop As PropertyDescriptor = TypeDescriptor.GetProperties(GetType(Component1))("BackColor")
        If prop.GetValue(Me.Component).Equals(Color.Transparent) = False Then
            items.Add(New DesignerActionPropertyItem("FullName" _
                    , "Full name", "My Properties", "Please enter your full name."))
        End If
.
.
.
[COLOR="Gray"]    End Function[/COLOR]
یعنی اگر کاربر رنگ Transparent رو انتخاب کرده بود دیگه در لیست Action ها FullName اضافه نمیشه.

این بخش اول ویرایش بود، اما الان کد ناقصه، چون اگر کاربر در حین کار با پنجره Tasks مقدار BackColor رو عوض کرد
این لیست بصورت خود بخود دلیلی برای Refresh شدن نداره و همچنان در وضعیت قبلی می مونه.
به همین جهت ویرایش دوم رو در Property مربوط به BackColor انجام می دهیم تا عمل Refresh انجام بشه :
کد:
[COLOR="Gray"]    Public Property BackColor() As Color
        Get
            Dim prop As PropertyDescriptor = TypeDescriptor.GetProperties(GetType(Component1))("BackColor")
            Return prop.GetValue(Me.Component)
        End Get
        Set(ByVal value As Color)
            Dim prop As PropertyDescriptor = TypeDescriptor.GetProperties(GetType(Component1))("BackColor")
            prop.SetValue(Me.Component, value)[/COLOR]
            Dim d As DesignerActionUIService = GetService(GetType(DesignerActionUIService))
            d.Refresh(Me.Component)
[COLOR="Gray"]        End Set
    End Property
[/COLOR]
 

ms_vb

Member
دست شما درد نکنه بازم مثل همیشه جوابتان خیلی بدردم خورد
یه سوال دیگه هم دارم:green:
اونم اینه که توی خود Property شی هم میشه همچین کاری کرد که نمایش بعضی از Property ها وابسته به دیگر Property ها باشه؟
 

the_king

مدیرکل انجمن
دست شما درد نکنه بازم مثل همیشه جوابتان خیلی بدردم خورد
یه سوال دیگه هم دارم:green:
اونم اینه که توی خود Property شی هم میشه همچین کاری کرد که نمایش بعضی از Property ها وابسته به دیگر Property ها باشه؟

اگه منظورتون در کد داخل Property باشه که نه، کد داخل Property در نمایش خودش یا بقیه Property نقش مستقیمی
نداره. اما در مثالی که زدم نمایش Property ئه FullName وابسته به نمایش Property ئه BackColor است، می توانید
بجای شرط if مربوطه از هر شرط دیگری استفاده کنید.
 

ms_vb

Member
نه من منظورم یه چیزی مثل (ApplicationSettings) هست که اگر شما در گزینه PropertyBinding یک ApplicationSetting اضافه کنید در این قسمت اضافه خواهد شد
البته چون موضوعش فرق میکنه با اجازه شما در یک مبحث جدید میپرسمش
ممنون
 
آخرین ویرایش:

ms_vb

Member
یعنی فقط من از این جواب آقای the_king استفاده کردم!
خداییش تشکرهایی که از این آقا شده خیلی کمه
 

جدیدترین ارسال ها

بالا