Atributy jmenného prostoru System.ComponentModel

1. díl - Atributy jmenného prostoru System.ComponentModel

Jan Novák       23.12.2008       VB.NET, Komponenty, WinForms, .NET       12831 zobrazení

V tomto článku si ukážeme jak efektivně využívat atributy z jmenného prostoru System.ComponentModel při vytváření vlastních komponent.

Pro demonstraci si vytvoříme komponentu s názvem Person. V praxi bychom pro ni těžko hledali využití, ale v teoretické rovině je to ideální ukázka. A jak bude vlastně vypadat?

' Jmenný prostor obsahující atributy pro práci s komponentami
Imports System.ComponentModel

Public Class Person
    Inherits Component
    
End Class

Tento kód umístíme do nového souboru v našem projektu. Pojmenujme ho výstižně Person.vb. Po kompilaci projektu nám v ToolBoxu přibyde nová kategorie a v ní nová komponenta.

Screenshot ToolBoxu zaměřený na nově vytvořenou komponentu

Pokud Vám vrtá hlavou, proč nepoužijeme ovládací prvek (Control), odpověď je snadná. Control má kromě funkcionality také velkou vizuální úlohu a používá se k interakci s uživatelem. Component je určena ke snadnějšímu sdílení objektů v aplikaci a v podstatě pouze reprezentuje třídu.

Struktura

Třídě Person nyní přidáme některé vlastnosti, na kterých budeme později prezentovat používání atributů z Systém.ComponentModel. Určitě bude třeba vědět, jak se naše osoba jmenuje, kdy se narodila a jak jí můžeme kontaktovat.

Public Class Person
    Inherits Component
    
    Private _name As String
    Private _birth As Date
    Private _mail As String
    
    Public Property Name() As String
        Get
            Return _name
        End Get
        Set(ByVal value As String)
            If Not String.IsNullOrEmpty(value) Then
                _name = value
            Else
                Throw New ArgumentNullException("value")
            End If
        End Set
    End Property
    Public Property Birth() As Date
        Get
            Return _birth
        End Get
        Set(ByVal value As Date)
            _birth = value
        End Set
    End Property
    Public Property Mail() As String
        Get
            Return _mail
        End Get
        Set(ByVal value As String)
            _mail = value
        End Set
    End Property
    Public ReadOnly Property Age() As Integer
        Get
            If Me.Birth <> Nothing Then Return Date.Now.Year - Me.Birth.Year Else Return 0
        End Get
    End Property
    
End Class

Atributy

Jmenný prostor Systém.ComponentModel obsahuje (jak je již z názvu patrné) spoustu užitečných tříd pro práci s komponentami, potažmo vizuální editaci jejich vlastností. Než se pustíme do pokročilejší editace vlastností naší osoby, dáme nějakou kulturu jejím vlastnostem. Jistě jste si všimli, že v okně Properties, konkrétně v jeho části s nápovědou, je poněkud vymeteno, oproti komponentám, které nám nabízí Visual Studio. Také vlastnosti, které jsme definovali se všechny zařadili do skupiny Misc, přesto, že je o to nikdo nežádal. S tím nám pomohou atributy:

Browsable

Atribut Browsable určuje, zda se má vlastnost zobrazit v okně Properties. Zejména u vlastností, které jsou pouze pro čtení (ReadOnly) je to celkem zbytečné. Skryjme tedy vlastnost Age pro práci v Designeru.

<Browsable(False)> _
Public ReadOnly Property Age() As Integer
    Get
        If Me.Birth <> Nothing Then Return Date.Now.Year - Me.Birth.Year Else Return 0
    End Get
End Property

Tento zápis zajistí, že vývojář tuto vlastnost v okně Properties neuvidí. Přístup z kódu zůstane samozřejmě nedotčený.

Aributy se zapisují do ostrých závorek. Mezera a podtržítko za atributem jsou proto, že se atributy mají psát před vlastnost:

<Browsable(False)> Public ReadOnly Property Age() As Integer

To by ovšem bylo značně nepřehledné, a proto můžeme za atributem tímto způsobem rozdělit zápis stejně, jako kdybychom například zadávali parametry metodě, která jich požaduje hodně, a kód by přesahoval hranice obrazovky. Pak je možno parametry psát například každý na jeden řádek, a patřičně je oddělovat právě tímto separátorem.

Category

Nyní máme všechny vlastnosti v kategorii Misc. Tam se umisťují všechny vlastnosti, které nemají kategorii určenou. My si vlasnosti naší osoby rozdělíme do kategorií Personálie a Kontakt. Jakým způsobem myslím není třeba vysvělovat. Jediný problém by mohl nastat u Age, kde již jeden atribut máme. Není sice třeba tuto vlastnost nikam řadit, protože je skrytá, ale pro pořádek jí zařadíme do kategorie personálií. A jak tedy zapíšeme více atributů za sebou? Jednoduše.

<Browsable(False), Category("Personal")> _

DefaultEvent, DefaultProperty, DefaultValue

Než si vysvětlíme tyto tři atributy, trochu upravíme naší osobu. Přidáme jí konstruktor, dvě události a jednu novou vlastnost. Bude se hodit vědět, jestli osoba žije, nebo je již po smrti. Přidáme vlastnost Alive. Bude jen pro čtení a zařadíme ji do kategorie personálií. Také ji skryjeme atributem Browsable. Poté vytvoříme dvě nové události – Born a Died. Ty se obejdou bez parametrů.

Public Event Born()
Public Event Dead()

Nyní má komponenta způsob, jak nám dát vědět, když se osoba narodí a když zemře. Za narození budeme považovat její vytvoření. Vyvoláme tedy událost Born v konstruktoru.

Public Sub New()
    _alive = True
    RaiseEvent Born()
End Sub

Událost Dead bude vyvolána zabití osoby metodou Kill:

Public Sub Kill()
    _alive = False
    RaiseEvent Died()
End Sub

Teď už ke slíbeným atributům DefaultXxx. DefaultEvent a DefaultProperty mají podobné použití. Jak jste si jistě všimli, okno Properties neumožňuje editovat pouze vlastnosti, ale též události. Pokud máme na formuláři dvě tlačítka a u jednoho upravíme nějakou vlastnost, když klikneme na další tlačítko, v Properties se přesune focus na stejnou vlastnost. Totéž platí o událostech. Když ale máme dva různé objekty, a u druhého neexistuje stejná vlastnost jako u prvního, focus padne právě na DefaultEvent, resp. DefaultProperty.

DefaultEvent

DefaultEvent udává, která událost je výchozí pro komponentu. Tato vlastnost dostane focus, jakmile otevřeme okno Properties a vybereme naši komponentu. Handler pro tuto vlastnost se také vytvoří po dvojkliku na komponentu na formuláři.

DefaultProperty funguje stejně jako DefaultEvent, ovšem s tím rozdílem, že platí pro záložku Properties a ne Events, tudíž na vlastnosti komponenty.

Okno Properties s detailem na záložky Properties a Events

DefaultEvent a DefaultProperty jsou atributy na úrovni třídy. Upravíme tedy:

<DefaultEvent("Born"), DefaultProperty("Name")> _
Public Class Person
    ...

DefaultValue je atribut, který udává výchozí hodnotu vlastnosti. Jak si můžete všimnout, pokud umístíte na formulář nějaký prvek, v panelu Properties jsou téměř všechny jeho vlastnosti vykresleny obyčejným fontem. Pokud ale nějakou změníte, ztuční. Vlastnosti, které nemají výchozí hodnotu se vykreslují tučným fontem. U naší komponenty budou ale silně všechny vlastnosti. Nedefinovali jsme jim totiž výchozí hodnotu atributem DefaultValue. My si nastavíme výchozí hodnotu u vlastnosti Name a Mail, a sice na "(none)". U ostatních vlastností to nemá moc smysl.

<DefaultValue(GetType(String), "(none)"> _

V prvním parametru říkáme, že výchozí hodnota je typu String. Funkce GetType nám zajistí, že funkce dostane jako parametr datový typ Type. Samotný String předat nemůžeme, protože se jedná o datový typ a nemůže být použit jako výraz.

Description

Další užitečný atribut je Description. Mnohdy je obtížné najít vhodný název pro vlastnost či událost. Buď nebývá dost krátký nebo dost jednoznačný. Pro vývojáře je pak zdržující, když musí testovat, k čemu dotyčná vlastnost je (například pokud používá third-party komponentu, která má nedostatečnou dokumentaci). Atribut Description v takových případěch značně ulehčuje práci. Definuje totiž text nápovědy v okně Properties. Naše komponenta má vlastnosti pojmenované jednoznačně, ovšem krátká nápověda neuškodí ani u těch nejjednoznačnějších vlastností či událostí. Doplňme si tedy krátké texty ke každé vlastnosti. Inspirovat se můžeme popisy u komponent z Visual Studia. Valná většina z nich začíná na "Gets or sets", což dodržím i já.

DesignOnly

Atribut DesignOnly určuje, zda je možno nastavovat hodnotu vlastnosti pouze v režimu návrhu, nebo i za běhu programu. Jak funguje poznáte, když si na formulář umístíte PropertyGrid, nastavíte mu SelectedObject na Person1 a k Person1 přidáte jakoukoliv vlastnost s DesignOnly(True). V okně Properties bude normálně možné nastavovat tuto vlastnost, ovšem při spuštění nebude možno hodnotu této vlastnosti změnit. Ani kódem, ani přes PropertyGrid na Formu.

Nenapadlo mě žádné praktické využití a cpát to do ukázky jen proto, aby to tam bylo, nebudu. Pokud Vás napadá nějaké konstruktivní využití tohoto atributu, určitě se o něj s námi podělte v diskusi.

DesignTimeVisible

Tento atribut se nepoužívá na třídy, které mají grafické znázornění. Jeho najčastější použití je tam, kde komponenta má nějaká subkomponenty, které si vykreslje sama. Třída pro subkomponentu bude pak DesignTimeVisible(False), aby nebyla v listě s komponentami v Designeru.

DisplayName

DisplayName je velice užitečný atribut. Jako parametr si bere text, který určí, jak se má jmenovat vlastnost v PropertyGridu (panel Properties je pouhý PropertyGrid). Pokud tedy nemáte chuť vytvářet komplexní uživatelské rozhraní například pro nastavení aplikace, je možné vytvořit si třídu s odpovídajícími vlastnostmi, nastavit jim DisplayName a rázem dostanete dokonalý prvek k editaci nastavení, místo například desítek CheckBoxů, RadioButtonů a dalších komponent. My si pro demonstraci nastavíme české texty do DisplayName pro naší osobu. Pro skryté vlastnosti to samozřejmě není třeba.

Formulář s PropertyGridem zobrazující české texty místo jmen vlastností

Já sice nejsem velkým fanouškem lokalizace a počešťování, ale obrovskou výhodu vidím v tom, že například můžeme nastavit více user-friendly verze jmen vlastností. Není Anually Bolded Dates pro uživatele lepší, než AnuallyBoldedDates?

ToolBoxItem, ToolBoxBitmap

ToolBoxItem udává, zda se má třída připojit k ToolBoxu. To logicky chceme. Defaultní hodnota atributu je True, takže je netřeba ho definovat. ToolBoxBitmap už je zajímavější. Udává resource, který se použije jako ikona pro třídu, na kterou je atribut aplikován.

< ... , ToolboxBitmap(GetType(Person), "PersonBitmap.png")> _

Obrázek zachycující komponentu v liště s komponentami reprezentovanou ikonou nastavenou přes ToolBoxBitmap

Do ToolBoxBitmap zadáme jméno obrazového souboru o velikosti 16x16 pixelů.

Závěrem

V tomto článku jsme si probrali některé často používané atributy jmenného prostoru System.ComponentModel. V příštím díle bych rád probral TypeConvertery, které se používají k tomu, aby bylo možné vlastnost rozkliknout a editovat po složkách. Jako například Location – možno rozkliknout na X a Y.

Zdrojové kódy

 

hodnocení článku

1 bodů / 1 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Všechny díly tohoto seriálu

3. UITypeEditory 09.02.2009
2. TypeConvertery 28.12.2008
1. Atributy jmenného prostoru System.ComponentModel 23.12.2008

 

 

 

Nový příspěvek

 

Diskuse: Vytváření vlastích komponent – 1. část

Velice Vám děkuji za článek o tvorbě komponent. Je velice dobře napsaný a myslím si, že i začátečník v programování rychle pochopí, jak si svou komponentu napsat. Mám jen malý, spíše kosmetický problém. Nepodařilo se mi přidat obrázek do panelu nástrojů. Pořád se mi zobrazuje standardní ikona. Procházel jsem Váš ukázkový soubor a veškerá nastavení mám snad správně. Svůj obrázek mám přidám do Resource souboru a pořád nic. můžete mi prosím poradit?

Zadání mám asi tako:

<ToolboxBitmap(GetType(SNMP), "snmp.png")> Public Class ...

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Přesně takový problém se stal i mě při psaní článku. Myslel jsem, že je chyba u mne, tak jsem to nechal být, ale jak vidím, asi je někde chyba. Teď bohužel nemůžu vyzkoušet, ale zkuste místo png použít ico či bmp (průhlednou barvu reprezentuje Color.Magenta).

Zkusím se na to co nejdřív mrknout...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Díky za radu, použil jsem soubor ico a vše funguje, jak má. Ještě jednou dík

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Také jsem zápasil se zobrazováním vlastní ikony pro můj ovládací prvek. Vygooglil jsem si následující návod Microsoftu, pomocí kterého jsem to dal konečně do kupy.

http://support.microsoft.com/kb/311315

Krátce. Soubor s ikonou je buď mimo soubor assembly nebo je v ní. Pokud je mimo, tak se musí zařídit jeho distribuce spolu s assembly. Pro zabudování do assembly lze použít následující postup.

1. Zvolit Project -> Add existing item a zvolit soubor s ikonou.

2. Vybrat přidaný objekt (obrázek) v Soution Exploreru a změnit vlastnost Build Action na Embedded Resource.

Jste hotovi.

Poznámka:

Pokud se obrázek jmenuje stejně jako třída, pak stačí přidat atribut takto:

<ToolboxBitmap("mojetrida.ico")> _
Class MojeTrida
End Class

V případě, že se třída a obrázek jmenují jinak, je potřeba zvolit jiný konstruktor pro tento atribut (ToolboxBitmap)

<ToolboxBitmap(GetType(MojeTrida), "ikona.ico")> _
Class MojeTrida
End Class

Po tomto mi to již začalo fungovat.

Co mi nefunguje, je atribut <Category("foo")> _ a vlastnosti se nezobrazují ve své vlastní nové kategorii. Zkusím to ještě dogooglit.

Snad to někomu pomůže.

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Skuste si prepnut v okne properties - toolbar okna - zotriedenei na (+-)iconka nie podla abecedy (az)iconka vtedy je to v grupach

nahlásit spamnahlásit spam 0 odpovědětodpovědět

http://www.bayaniccamasir.com

nahlásit spamnahlásit spam 0 odpovědětodpovědět

<A HREF="http://www.bayaniccamasir.com">lingerie</A>

nahlásit spamnahlásit spam 0 odpovědětodpovědět

elbise modelleri www.gozdekadin.com moda, magazin,

gelinlik modelleri, evlilik, www.ruyadugun.com

flange,flanges, flanş, www.demirtasmakina.com

klima, toshiba, www.klimafiyatlar.com

iç giyim, bayan iç giyim, www.ucuzicgiyim.net

tanga, www.tangasepeti.com

lingerie www.kadinicgiyim.net

nahlásit spamnahlásit spam 0 odpovědětodpovědět

www.bektasi.net

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Vytváření vlastích komponent – 1. část

Díky za článek, je velmi užitečný, sám jsem si z něj odvodil spoustu věcí.

Zajímá mě, jak ovlivňuje DesignOnly chování programu a vývojového prostředí, případně kde mohu mít chybu.

Mám komponentu s tímto problematickým kódem

Imports System.ComponentModel
Public Class ComPLCBit
	Private _Alloc As PLCAddress
	'***********************************
	'*Definice adresy
	'***********************************
	<Category("PLC"), Description("Set Address in PLC"), DisplayName("Address")> _
	Public Property Alloc() As PLCAddress
		Get
			Return _Alloc
		End Get
		Set(ByVal value As PLCAddress)
			_Alloc = value
		End Set
	End Property
End Class

a definovanou třídou PLCAddress, která slouží k nastavení vlastností v property gridu

Imports System.ComponentModel
Imports System.ComponentModel.TypeConverter
Imports System.Text.RegularExpressions

<TypeConverter(GetType(PLCAddressConverter))> _
Public Class PLCAddress
	'********************************
	'* Deklarace konstruktoru
	'********************************

	Public Sub New(ByVal Regtype As Char, ByVal RegData As Char, ByVal RegNumber As String, ByVal RegBit As String)
		_RegType = Regtype
		_RegData = RegData
		_RegNumber = RegNumber
		_RegBit = RegBit
	End Sub
	Public Sub New()

	End Sub


	<Browsable(False)> _
 Public ReadOnly Property Address() As String
		Get
			Return _RegType & _RegData & _RegNumber & _RegBit
		End Get
	End Property

	'********************************
	'*Definice typu adresy - umisteni
	'********************************
	Private _RegType As Char
	<RefreshProperties(RefreshProperties.Repaint), TypeConverter(GetType(TypePropertyConverter)), DisplayName("1-Register Type"), Description("Select register Type")> _
 Public Property RegType() As String
		Get
			Return _RegType
		End Get
		Set(ByVal value As String)
			Dim rex As String = ""
			Select Case _RegType
				Case "M", "C"
					rex = "^[0-9]{1,5}$"
				Case "I", "O"
					rex = "^[0-9A-F]{1,4}$"
				Case "S"
					rex = "^[0-9]{1,4}$"
			End Select
			'str = Address.RegNumber + Address.RegBit
			If Regex.IsMatch(_RegNumber, rex) Then
				_RegType = value
			Else
				Throw New ArgumentException("RegT Data Number Notvalid")
			End If
		End Set
	End Property

	'********************************
	'*Definice datoveho typu adresy 
	'********************************
	Private _RegData As Char
	<RefreshProperties(RefreshProperties.Repaint), TypeConverter(GetType(DataPropertyConverter)), DisplayName("2-Data Type"), Description("Select Data Type")> _
 Public Property RegData() As String
		Get
			Return _RegData
		End Get
		Set(ByVal value As String)
			Dim rex As String = "^[WLF]$"
			If _RegData = "B" And Regex.IsMatch(value, rex) Then
				_RegBit = ""
			End If
			_RegData = value
		End Set
	End Property

	'********************************
	'*Definice cisla registru adresy
	'********************************
	Private _RegNumber As String
	<RefreshProperties(RefreshProperties.Repaint), DisplayName("3-Register Number"), Description("Set Register Number")> _
 Public Property RegNumber() As String
		Get
			Return _RegNumber
		End Get
		Set(ByVal value As String)
			Dim rex As String = ""
			Select Case _RegType
				Case "M", "C"
					rex = "^[0-9]{1,5}$"
				Case "I", "O"
					rex = "^[0-9A-F]{1,4}$"
				Case "S"
					rex = "^[0-9]{1,4}$"
			End Select
			'str = Address.RegNumber + Address.RegBit
			If Regex.IsMatch(value, rex) Then
				_RegNumber = value
			Else
				Throw New ArgumentException("Reg Num Data Number Notvalid")
			End If
		End Set
	End Property

	'********************************
	'*Definice cisla bitu adresy 
	'********************************
	Private _RegBit As String
	<RefreshProperties(RefreshProperties.Repaint), TypeConverter(GetType(BitPropertyConverter)), DisplayName("4-Bit Number"), Description("Select register Bit")> _
 Public Property RegBit() As String
		Get
			Return _RegBit
		End Get
		Set(ByVal value As String)
			Dim rex As String = "^[0-9A-F]$"
			If _RegBit = "" And Regex.IsMatch(value, rex) Then
				_RegData = "B"
			End If
			_RegBit = value
		End Set
	End Property

	'********************************
	'*Definice vyberu por typ adresy 
	'********************************
	Shared ReadOnly Property SVCTypes() As StandardValuesCollection
		Get
			Return New StandardValuesCollection(New Char() {"M", "S", "I", "O", "C"})
		End Get
	End Property
	'********************************
	'*Definice vyberu datoveho typu
	'********************************
	Shared ReadOnly Property SVCDatas() As StandardValuesCollection
		Get
			Return New StandardValuesCollection(New Char() {"W", "L", "F", "B"})
		End Get
	End Property

	'********************************
	'*Definice vyberu cisla bitu 
	'********************************
	Shared ReadOnly Property SVCBits() As StandardValuesCollection
		Get
			Return New StandardValuesCollection(New String() {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"})
		End Get
	End Property
End Class

'*********************************
'*Definice zobrazeni datoveho typu
'*********************************
Public Class DataPropertyConverter
	Inherits StringConverter

	Public Overrides Function GetStandardValuesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
		Return True	' Říká, že máme vlastní kolekci hodnot, které chceme používat
	End Function

	Public Overrides Function GetStandardValuesExclusive(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
		Return True	' A zakazuje, aby uživatel mohl do pole psát. Musí si jednoduše jednu z možností vybrat.
	End Function

	Public Overrides Function GetStandardValues(ByVal context As System.ComponentModel.ITypeDescriptorContext) As System.ComponentModel.TypeConverter.StandardValuesCollection
		Return PLCAddress.SVCDatas	' Vrací kolekci řetězců. Správně by měla být deklarována zde, v konverteru (proto ten krkolomný datový typ), ale pro přehlednost a praktičnost jsme jí umístil do třídy Mood.
	End Function
End Class

'*********************************
'*Definice zobrazeni typu registru
'*********************************
Public Class TypePropertyConverter
	Inherits StringConverter

	Public Overrides Function GetStandardValuesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
		Return True	' Říká, že máme vlastní kolekci hodnot, které chceme používat
	End Function

	Public Overrides Function GetStandardValuesExclusive(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
		Return True	' A zakazuje, aby uživatel mohl do pole psát. Musí si jednoduše jednu z možností vybrat.
	End Function

	Public Overrides Function GetStandardValues(ByVal context As System.ComponentModel.ITypeDescriptorContext) As System.ComponentModel.TypeConverter.StandardValuesCollection
		Return PLCAddress.SVCTypes	' Vrací kolekci řetězců. Správně by měla být deklarována zde, v konverteru (proto ten krkolomný datový typ), ale pro přehlednost a praktičnost jsme jí umístil do třídy Mood.
	End Function

End Class

'*********************************
'*Definice zobrazeni Bitu registru
'*********************************
Public Class BitPropertyConverter
	Inherits StringConverter

	Public Overrides Function GetStandardValuesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
		Return True	' Říká, že máme vlastní kolekci hodnot, které chceme používat
	End Function

	Public Overrides Function GetStandardValuesExclusive(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
		Return True	' A zakazuje, aby uživatel mohl do pole psát. Musí si jednoduše jednu z možností vybrat.
	End Function

	Public Overrides Function GetStandardValues(ByVal context As System.ComponentModel.ITypeDescriptorContext) As System.ComponentModel.TypeConverter.StandardValuesCollection
		Return PLCAddress.SVCBits		' Vrací kolekci řetězců. Správně by měla být deklarována zde, v konverteru (proto ten krkolomný datový typ), ale pro přehlednost a praktičnost jsme jí umístil do třídy Mood.
	End Function

End Class

'********************************
'*Property Konvertor  
'********************************
Public Class PLCAddressConverter
	Inherits ExpandableObjectConverter
	'*Povoleni konverze do stringu (Pro PropertyGrid)
	Public Overrides Function CanConvertFrom(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal sourceType As System.Type) As Boolean
		Return sourceType Is GetType(String) OrElse MyBase.CanConvertFrom(context, sourceType)
	End Function

	'*Povoleni konverze ze stringu (Pro PropertyGrid)
	Public Overrides Function CanConvertTo(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal destinationType As System.Type) As Boolean
		Return destinationType Is GetType(String) OrElse MyBase.CanConvertTo(context, destinationType)
	End Function

	'*Konverze ze stringu v PropertyGridu do PLCAddress
	Public Overrides Function ConvertFrom(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal culture As System.Globalization.CultureInfo, ByVal value As Object) As Object
		If TypeOf (value) Is String Then
			Dim str As String = DirectCast(value, String)
			Dim RexN As String = "^[MSIOC][WLFB]"
			Dim RegType As Char
			Dim RegData As Char
			Dim RegNumber As String
			Dim RegBit As String = ""
			Dim FormatStr As String = ""
			RegType = Mid(str, 1, 1)
			RegData = Mid(str, 2, 1)
			RegNumber = Mid(str, 3)

			If Regex.IsMatch(str, RexN) Then
				Select Case RegType
					Case "M", "C"
						FormatStr = "{0:D5}"
						RexN = "^[0-9]{5}"
					Case "I", "O"
						FormatStr = "{0:X4}"
						RexN = "^[0-9A-F]{4}"
					Case "S"
						FormatStr = "{0:D4}"
						RexN = "^[0-9]{4}"
				End Select
				Select Case RegData
					Case "W", "L", "F"
						RexN = RexN & "$"
						If Regex.IsMatch(RegNumber, RexN) Then
							Return New PLCAddress(RegType, RegData, Format(FormatStr, CInt(RegNumber)), RegBit)
						Else
							Throw New ArgumentException(Mid(str, 3) & " don't match '" & RexN & "'")
							Return Nothing
						End If

					Case "B"
						RexN = RexN + "[0-9A-F]$"
						If Regex.IsMatch(RegNumber, RexN) Then
							RegBit = Right(RegNumber, 1)
							RegNumber = Left(RegNumber, Len(RegNumber) - 1)
							Return New PLCAddress(RegType, RegData, Format(FormatStr, CInt(RegNumber)), RegBit)
						Else
							Throw New ArgumentException(Mid(str, 3) & " don't match '" & RexN & "'")
							Return Nothing
						End If
				End Select
			End If
		End If
		Return MyBase.ConvertFrom(context, culture, value)
	End Function

	'*Konverze z PLCAddress do stringu v PropertyGridu
	Public Overrides Function ConvertTo(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal culture As System.Globalization.CultureInfo, ByVal value As Object, ByVal destinationType As System.Type) As Object
		If destinationType Is GetType(String) AndAlso value IsNot Nothing Then
			Dim Address As PLCAddress = DirectCast(value, PLCAddress)
			Dim FormatStr As String = String.Empty
			Dim FormatNum As String = ""
			Dim tmp As Integer
			Select Case Address.RegType
				Case "M", "C"
					FormatStr = "{0:D5}"
				Case "I", "O"
					FormatStr = "{0:X4}"
					FormatNum = "&H"
				Case "S"
					FormatStr = "{0:D4}"
			End Select
			tmp = Val(FormatNum + Address.RegNumber)
			Return String.Format("{0}{1}{2}{3}", Address.RegType, Address.RegData, String.Format(FormatStr, tmp), Address.RegBit)
		End If
		Return MyBase.ConvertTo(context, culture, value, destinationType)
	End Function
End Class

Problém je v tom, že chci zamezit zápis k třídě PLCAddres a pokud vložím DesignOnly(True) k definici třídy nebo k jejím vlastnostem, tak při uzavření a novém otevření projektu dojde ke ztrátě nastavených hodnot

Díky za radu

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Nemyslím, že jde o chybu. Spíš je to standardní chování. Já jsem nikdy nic takového neřešil, ale nejspíš bych zkusil použít My.Setings a tam při změně hodnoty té vlastnosti ukládat novou hodnotu, která by se v konstruktoru poté opět vyvolávala. Snad je Vám to něco platné, příjemný den!

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Díky za nápad, po chvíli studování My.settings jsem zjistil, že nastavení lze ukládát do ručně vytvořených parametrů. Vzhledem k tomu, že množství výskytu v projektu není možné určit, je toto řešení spíše přitěžující

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Vytváření vlastích komponent – 1. část

Díky za článek, osobně vítám každé vykročení do tajů .NET neboť je podstatně více vlastností VB studia, které neznám, než těch druhých. Jen se mi nepodařilo vyzkoušet "DefauldValue" a "ToolboxBitmap" možná jsem se někde ztratil. Pracuju s VB 2008 EE.

Jan

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Napište, co se Vám nedaří, a já se Vám pokusím pomoci. A u "DefaultValue" - v příspěvku jste napsal 'd', zkontrolujte, jestli máte Default správně v kódu.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

No mne nefunguje (ani v kodu staženém z konce článku) zobrazování "(none)". Vlastnost Name zobrazí "Jméno a přijmení" jakožto název, ale místo "(none)" se zobrazí "Person1".

Jan

nahlásit spamnahlásit spam 0 odpovědětodpovědět

To je tím, že se vlastnost jmenuje Name a Visual Studio tuto vlastnost automaticky vyplňuje při přenesení komponenty na formulář. Přejmenujte ji například na PersonsName a mělo by to být ok.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

    <Category("Personal"), DefaultValue(GetType(String), "(none)"), Description("Gets or sets name of person."), DisplayName("Jme a příjmení")> _
    Public Property NamePer() As String
        Get
            Return _name
        End Get
        Set(ByVal value As String)
            If Not String.IsNullOrEmpty(value) Then
                _name = value
            Else
                Throw New ArgumentNullException("value")
            End If
        End Set
    End Property

Nekde je zadrhel, tohle je to co mi nechodi.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pak si do konstruktoru přidejte příkaz Me.NamePer = "(none)". Mě to pracuje normálně.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Je mi líto jsem nějak huř chapavej kam myslíte "do konstruktoru" ? Nenašel jsme místo kde by mi to překladač nepodtrhl modrou vlnovkou.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

V pořádku. Konstruktor je speciální procedura, která se zavolá při vytváření instance komponenty. Její zápis vypadá takto:

Public Sub New()
    ' Nějaké příkazy na inicializaci komponenty
End Sub

Konstruktor může mít samozřejmě i parametry, ale aby VS dokázalo komponentu vytvořit, musí mít třída i konstruktor bez parametrů.

A teď v Vašemu problému. Naše komponenta má v konstruktoru dva příkazy. Za prvé, nastaví provátní proměnnou _alive na True, a za druhé vyvolá událost Born(). Vy si přidejte třetí příkaz, kde nastavíte vlastnosti NamePer hodnotu "(none)".

Druhá možnost je nechat konstruktor tak, jak je, a nastavit "(none)" jako počáteční hodnotu privátmí proměnné _name. Tedy takto:

Public Class Person
    Inherits Component
    
    Private _name As String = "(none)"
    Private _birth As Date
    Private _mail As String
' ...

PropertyGrid se pak dotáže na hodnotu NamePera a ta mu vrátí místo String.Empty (což vrací nyní) "(none)", což bude výchozí hodnota.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Tak jste úspěšný učitel, pořilo se mi to. "(none)" se zobrazí při novém načtení komponenty z toolboxu, kdešto u - DisplayName("Jmeno a přijmení")se projeví změna hned při jakémkoli přepsání. A to mne zmátlo. Díky a veselého silvestra.

Jan

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Díky, jsem rád, že jsem Vám pomohl. Též přeji příjemný Silvestr. :)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Vytváření vlastích komponent – 1. část

<meta http-equiv="refresh" content="0;URL=http://cikcik.tk">

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Diskuse: Vytváření vlastích komponent – 1. část

Moc hezký článek - stručný, ale velmi obsáhlý... Jen tak dál.

Zajímalo by mě, do čeho všeho se pustíš, vlastní komponenty a jejich návrh je hodně rozsáhlé téma.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Děkuji za pochvalu. Premiéra dopadla lépe, než jsem doufal :-).

Chystám ještě dva díly - TypeConvertery a DropDownEditory. Ovšem je třeba osvěžit si všechny oblasti vývoje komponent a doučit se, co ještě neovládám, takže další článek asi nebude hned zítra :-).

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Ono to tak býva, že napsání článku znamená si věc důkladně prozkoušet a doučit se mezery...

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Ano, právě proto články píši... Jedině tak se dokopu si něco zopakovat a doučit se :-).

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback