Esempio di gestione dello stato dei tipi personalizzati
Aggiornamento: novembre 2007
In questo esempio viene illustrato come attivare una proprietà complessa, ovvero una proprietà il cui tipo è una classe che a sua volta ha proprietà, per far sì che faccia parte dello stato di visualizzazione ASP.NET tramite l'implementazione dell'interfaccia IStateManager. Come descritto in Esempio di proprietà dei controlli server, è possibile utilizzare la proprietà ViewState del controllo personalizzato per gestire lo stato delle proprietà semplici. Tuttavia, per gestire lo stato di una proprietà Collection o di una proprietà che dispone di sottoproprietà, è necessario implementare una proprietà in sola lettura, mentre come parte del tipo di proprietà si implementa di solitoIStateManager.
Il tipo StateManagedAuthor definito in questo esempio illustra le modalità di implementazione di IStateManager. La classe StateManagedAuthor è un tipo complesso che dispone a sua volta di sottoproprietà quali FirstName e LastName. La proprietà Author del controllo BookNew descritta in Esempio di gestione dello stato delle proprietà personalizzate è di tipo StateManagedAuthor.
L'implementazione dell'interfaccia IStateManager in StateManagedAuthor viene descritta nella sezione "Illustrazione del codice" più avanti in questo argomento.
Listato di codice per la classe StateManagedAuthor
' StateManagedAuthor.vb
Option Strict On
Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.Globalization
Imports System.Web.UI
Namespace Samples.AspNet.VB.Controls
< _
TypeConverter(GetType(StateManagedAuthorConverter)) _
> _
Public Class StateManagedAuthor
Implements IStateManager
Private isTrackingViewStateValue As Boolean
Private viewStateValue As StateBag
Public Sub New()
Me.New(String.Empty, String.Empty, String.Empty)
End Sub
Public Sub New(ByVal first As String, ByVal last As String)
Me.New(first, String.Empty, last)
End Sub
Public Sub New(ByVal first As String, ByVal middle As String, _
ByVal last As String)
FirstName = first
MiddleName = middle
LastName = last
End Sub
< _
Category("Behavior"), _
DefaultValue(""), _
Description("First name of author"), _
NotifyParentProperty(True) _
> _
Public Overridable Property FirstName() As String
Get
Dim s As String = CStr(ViewState("FirstName"))
If s Is Nothing Then s = String.Empty
Return s
End Get
Set(ByVal value As String)
ViewState("FirstName") = value
End Set
End Property
< _
Category("Behavior"), _
DefaultValue(""), _
Description("Last name of author"), _
NotifyParentProperty(True) _
> _
Public Overridable Property LastName() As String
Get
Dim s As String = CStr(ViewState("LastName"))
If s Is Nothing Then s = String.Empty
Return s
End Get
Set(ByVal value As String)
ViewState("LastName") = value
End Set
End Property
< _
Category("Behavior"), _
DefaultValue(""), _
Description("Middle name of author"), _
NotifyParentProperty(True) _
> _
Public Overridable Property MiddleName() As String
Get
Dim s As String = CStr(ViewState("MiddleName"))
If s Is Nothing Then s = String.Empty
Return s
End Get
Set(ByVal value As String)
ViewState("MiddleName") = value
End Set
End Property
Protected Overridable ReadOnly Property ViewState() _
As StateBag
Get
If viewStateValue Is Nothing Then
viewStateValue = New StateBag(False)
If isTrackingViewStateValue Then
CType(viewStateValue, _
IStateManager).TrackViewState()
End If
End If
Return viewStateValue
End Get
End Property
Public Overrides Function ToString() As String
Return ToString(CultureInfo.InvariantCulture)
End Function
Public Overloads Function ToString( _
ByVal culture As CultureInfo) As String
Return TypeDescriptor.GetConverter( _
Me.GetType()).ConvertToString(Nothing, culture, Me)
End Function
#Region "IStateManager implementation"
Public ReadOnly Property IsTrackingViewState() As Boolean _
Implements IStateManager.IsTrackingViewState
Get
Return isTrackingViewStateValue
End Get
End Property
Public Sub LoadViewState(ByVal savedState As Object) _
Implements IStateManager.LoadViewState
If savedState IsNot Nothing Then
CType(ViewState, _
IStateManager).LoadViewState(savedState)
End If
End Sub
Public Function SaveViewState() As Object _
Implements IStateManager.SaveViewState
Dim savedState As Object = Nothing
If viewStateValue IsNot Nothing Then
savedState = CType(viewStateValue, _
IStateManager).SaveViewState
End If
Return savedState
End Function
Public Sub TrackViewState() _
Implements IStateManager.TrackViewState
isTrackingViewStateValue = True
If viewStateValue IsNot Nothing Then
CType(viewStateValue, IStateManager).TrackViewState()
End If
End Sub
#End Region
Protected Sub SetDirty()
viewStateValue.SetDirty(True)
End Sub
End Class
End Namespace
// StateManagedAuthor.cs
using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Web.UI;
namespace Samples.AspNet.CS.Controls
{
[
TypeConverter(typeof(StateManagedAuthorConverter))
]
public class StateManagedAuthor : IStateManager
{
private bool _isTrackingViewState;
private StateBag _viewState;
public StateManagedAuthor()
:
this(String.Empty, String.Empty, String.Empty)
{
}
public StateManagedAuthor(string first, string last)
:
this(first, String.Empty, last)
{
}
public StateManagedAuthor(string first, string middle, string last)
{
FirstName = first;
MiddleName = middle;
LastName = last;
}
[
Category("Behavior"),
DefaultValue(""),
Description("First name of author"),
NotifyParentProperty(true)
]
public virtual String FirstName
{
get
{
string s = (string)ViewState["FirstName"];
return (s == null) ? String.Empty : s;
}
set
{
ViewState["FirstName"] = value;
}
}
[
Category("Behavior"),
DefaultValue(""),
Description("Last name of author"),
NotifyParentProperty(true)
]
public virtual String LastName
{
get
{
string s = (string)ViewState["LastName"];
return (s == null) ? String.Empty : s;
}
set
{
ViewState["LastName"] = value;
}
}
[
Category("Behavior"),
DefaultValue(""),
Description("Middle name of author"),
NotifyParentProperty(true)
]
public virtual String MiddleName
{
get
{
string s = (string)ViewState["MiddleName"];
return (s == null) ? String.Empty : s;
}
set
{
ViewState["MiddleName"] = value;
}
}
protected virtual StateBag ViewState
{
get
{
if (_viewState == null)
{
_viewState = new StateBag(false);
if (_isTrackingViewState)
{
((IStateManager)_viewState).TrackViewState();
}
}
return _viewState;
}
}
public override string ToString()
{
return ToString(CultureInfo.InvariantCulture);
}
public string ToString(CultureInfo culture)
{
return TypeDescriptor.GetConverter(
GetType()).ConvertToString(null, culture, this);
}
#region IStateManager implementation
bool IStateManager.IsTrackingViewState
{
get
{
return _isTrackingViewState;
}
}
void IStateManager.LoadViewState(object savedState)
{
if (savedState != null)
{
((IStateManager)ViewState).LoadViewState(savedState);
}
}
object IStateManager.SaveViewState()
{
object savedState = null;
if (_viewState != null)
{
savedState =
((IStateManager)_viewState).SaveViewState();
}
return savedState;
}
void IStateManager.TrackViewState()
{
_isTrackingViewState = true;
if (_viewState != null)
{
((IStateManager)_viewState).TrackViewState();
}
}
#endregion
internal void SetDirty()
{
_viewState.SetDirty(true);
}
}
}
Illustrazione del codice
La classe StateManagedAuthor descrive il modello di implementazione dell'interfaccia IStateManager comunemente utilizzata dai tipi complessi ASP.NET. StateManagedAuthor definisce una proprietà denominata ViewState memorizzata in una variabile privata di tipo StateBag e chiamata viewState in C# e viewStateValue in Visual Basic. La proprietà ViewState simula la proprietà ViewState della classe Control. StateManagedAuthor memorizza le proprietà nel dizionario ViewState nello stesso modo in cui un controllo memorizza le proprietà semplici nel dizionario ViewState della classe Control.
L'interfaccia IStateManager dispone di un'unica proprietà IsTrackingViewState e di tre metodi: TrackViewState, SaveViewState e LoadViewState. La semantica dei membri dell'interfaccia IStateManager è uguale alla semantica dei metodi corrispondenti della classe Control.
La proprietà IsTrackingViewState attiva un tipo per l'implementazione di IStateManager da coordinare con il monitoraggio dello stato nel controllo in cui il tipo viene utilizzato. La classe StateManagedAuthor utilizza un campo Boolean privato (isTrackingViewState in C# e isTrackingViewStateValue in Visual Basic) per memorizzare questa proprietà. Durante l'implementazione di TrackViewState, StateManagedAuthor imposta isTrackingViewState o isTrackingViewStateValue su true. Richiama inoltre il metodo IStateManager.TrackViewState del campo viewState o viewStateValue privato corrispondente alla proprietà ViewState. Il metodo TrackViewState avvia il monitoraggio delle modifiche degli elementi memorizzati nella proprietà ViewState. Ciò significa che se un elemento del dizionario ViewState viene impostato dopo aver richiamato TrackViewState in ViewState, l'elemento viene contrassegnato automaticamente come modificato.
Durante l'implementazione del metodo SaveViewState, StateManagedAuthor richiama solo il metodo corrispondente al viewState privato o al campo viewStateValue. Analogamente, durante l'implementazione del metodo LoadViewState, StateManagedAuthor richiama solo il metodo corrispondente alla proprietà ViewState. Come descritto in Esempio di proprietà dei controlli server, il tipo StateBag della proprietà ViewState implementa IStateManager ed è un dizionario con la gestione dello stato incorporata.
Quando viene eseguita l'implementazione di IStateManager nel controllo utilizzando un tipo, questi consente di conservare lo stato e richiamare i metodi di gestione dello stato del tipo da TrackViewState, SaveViewState, nonché i metodi LoadViewState del controllo personalizzato. Pertanto, il controllo BookNew descritto in Esempio di gestione dello stato delle proprietà personalizzate richiama i metodi TrackViewState, SaveViewState e LoadViewState di StateManagedAuthor dalla sua implementazione di tali metodi.
Listato di codice per la classe StateManagedAuthorConverter
Nel seguente listato di codice, StateManagedAuthorConverter è il convertitore di tipi personalizzato associato a StateManagedAuthor tramite l'attributo TypeConverterAttribute. La classe StateManagedAuthorConverter attiva la conversione dal tipo String al tipo StateManagedAuthor e viceversa, come descritto in Esempio di convertitore di tipi. In questo esempio, StateManagedAuthorConverter viene utilizzato per stampare il nome completo dell'autore nel metodo Render della classe BookNew.
Nota: |
---|
Il tipo StateManagedAuthor non necessita di un convertitore di tipi per la gestione dello stato. StateManagedAuthorConverter viene fornito come classe di utilità opzionale per le conversioni da stringa a valore. Quando viene implementato un convertitore di tipi per un tipo personalizzato, è necessario eseguire l'override del metodo ToString del tipo per richiamare il convertitore di tipi e visualizzare una rappresentazione in forma di stringa, come mostrato nel listato di codice per StateManagedAuthor. |
' StateManagedAuthorConverter.vb
Imports System
Imports System.ComponentModel
Imports System.ComponentModel.Design.Serialization
Imports System.Globalization
Imports System.Reflection
Namespace Samples.AspNet.VB.Controls
Public Class StateManagedAuthorConverter
Inherits ExpandableObjectConverter
Public Overrides Function CanConvertFrom( _
ByVal context As ITypeDescriptorContext, _
ByVal sourceType As Type) As Boolean
If sourceType Is GetType(String) Then
Return True
End If
Return MyBase.CanConvertFrom(context, sourceType)
End Function
Public Overrides Function CanConvertTo( _
ByVal context As ITypeDescriptorContext, _
ByVal destinationType As Type) As Boolean
If destinationType Is GetType(String) Then
Return True
End If
Return MyBase.CanConvertTo(context, destinationType)
End Function
Public Overrides Function ConvertFrom( _
ByVal context As ITypeDescriptorContext, _
ByVal culture As CultureInfo, ByVal value As Object) _
As Object
If value Is Nothing Then
Return New StateManagedAuthor()
End If
If (TypeOf value Is String) Then
Dim s As String = CStr(value)
If s.Length = 0 Then
Return New StateManagedAuthor()
End If
Dim parts() As String = s.Split(" ".ToCharArray)
If (parts.Length < 2) Or (parts.Length > 3) Then
Throw New ArgumentException( _
"Name must have 2 or 3 parts.", "value")
End If
If parts.Length = 2 Then
Return New StateManagedAuthor(parts(0), parts(1))
End If
If parts.Length = 3 Then
Return New StateManagedAuthor(parts(0), _
parts(1), parts(2))
End If
End If
Return MyBase.ConvertFrom(context, culture, value)
End Function
Public Overrides Function ConvertTo( _
ByVal context As ITypeDescriptorContext, _
ByVal culture As CultureInfo, ByVal value As Object, _
ByVal destinationType As Type) As Object
If value IsNot Nothing Then
If Not (TypeOf value Is StateManagedAuthor) Then
Throw New ArgumentException( _
"Name must have 2 or 3 parts.", "value")
End If
End If
If destinationType Is GetType(String) Then
If value Is Nothing Then
Return String.Empty
End If
Dim auth As StateManagedAuthor = _
CType(value, StateManagedAuthor)
If auth.MiddleName <> String.Empty Then
Return String.Format("{0} {1} {2}", _
auth.FirstName, _
auth.MiddleName, _
auth.LastName)
Else
Return String.Format("{0} {1}", _
auth.FirstName, _
auth.LastName)
End If
End If
Return MyBase.ConvertTo(context, culture, value, _
destinationType)
End Function
End Class
End Namespace
// StateManagedAuthorConverter.cs
using System;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Globalization;
using System.Reflection;
namespace Samples.AspNet.CS.Controls
{
public class StateManagedAuthorConverter :
ExpandableObjectConverter
{
public override bool CanConvertFrom(
ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(
ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(
ITypeDescriptorContext context,
CultureInfo culture, object value)
{
if (value == null)
{
return new StateManagedAuthor();
}
if (value is string)
{
string s = (string)value;
if (s.Length == 0)
{
return new StateManagedAuthor();
}
string[] parts = s.Split(' ');
if ((parts.Length < 2) || (parts.Length > 3))
{
throw new ArgumentException(
"Name must have 2 or 3 parts.", "value");
}
if (parts.Length == 2)
{
return new StateManagedAuthor(parts[0], parts[1]);
}
if (parts.Length == 3)
{
return new StateManagedAuthor(parts[0],
parts[1], parts[2]);
}
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context,
CultureInfo culture, object value, Type destinationType)
{
if (value != null)
{
if (!(value is StateManagedAuthor))
{
throw new ArgumentException(
"Name must have 2 or 3 parts.", "value");
}
}
if (destinationType == typeof(string))
{
if (value == null)
{
return String.Empty;
}
StateManagedAuthor auth = (StateManagedAuthor)value;
if (auth.MiddleName != String.Empty)
{
return String.Format("{0} {1} {2}",
auth.FirstName,
auth.MiddleName,
auth.LastName);
}
else
{
return String.Format("{0} {1}",
auth.FirstName,
auth.LastName);
}
}
return base.ConvertTo(context, culture,
value, destinationType);
}
}
}
Creazione e utilizzo dell'esempio
Compilare le classi StateManagedAuthor e StateManagedAuthorConverter elencate in questo argomento utilizzando il controllo BookNew elencato in Esempio di gestione dello stato delle proprietà personalizzate e l'enumerazione BookType elencata in Esempio di proprietà dei controlli server.
Per informazioni sulla compilazione e l'uso di esempi di controlli personalizzati, vedere Generazione degli esempi dei controlli server personalizzati.
Vedere anche
Concetti
Esempio di gestione dello stato delle proprietà personalizzate
Esempio di proprietà dei controlli server
Generazione degli esempi dei controlli server personalizzati