📄 accordion.cs
字号:
/// and hooks up the appropriate event listener for the
/// DataSourceViewChanged event. The return value is the new view (if
/// any) that was connected to. An exception is thrown if there is
/// a problem finding the requested view or data source.
/// </summary>
/// <returns>New View</returns>
[SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", Justification = "Assembly is not localized")]
private DataSourceView ConnectToDataSourceView()
{
// If the current view is correct, there is no need to reconnect
if (_currentViewValid && !DesignMode)
return _currentView;
// Disconnect from old view, if necessary
if ((_currentView != null) && (_currentViewIsFromDataSourceID))
{
// We only care about this event if we are bound through the DataSourceID property
_currentView.DataSourceViewChanged -= new EventHandler(OnDataSourceViewChanged);
}
// Connect to new view
IDataSource ds = null;
string dataSourceID = DataSourceID;
if (!string.IsNullOrEmpty(dataSourceID))
{
// Try to find a DataSource control with the ID specified in DataSourceID
Control control = NamingContainer.FindControl(dataSourceID);
if (control == null)
throw new HttpException(String.Format(CultureInfo.CurrentCulture, "DataSource '{1}' for control '{0}' doesn't exist", ID, dataSourceID));
ds = control as IDataSource;
if (ds == null)
throw new HttpException(String.Format(CultureInfo.CurrentCulture, "'{1}' is not a data source for control '{0}'.", ID, dataSourceID));
}
if (ds == null)
{
// DataSource control was not found, construct a temporary data source to wrap the data
return null;
}
else
{
// Ensure that both DataSourceID as well as DataSource are not set at the same time
if (DataSource != null)
throw new InvalidOperationException("DataSourceID and DataSource can't be set at the same time.");
}
// IDataSource was found, extract the appropriate view and return it
DataSourceView newView = ds.GetView(DataMember);
if (newView == null)
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "DataSourceView not found for control '{0}'", ID));
_currentViewIsFromDataSourceID = IsBoundUsingDataSourceID;
_currentView = newView;
// If we're bound through the DataSourceID proeprty, then we care about this event
if ((_currentView != null) && (_currentViewIsFromDataSourceID))
_currentView.DataSourceViewChanged += new EventHandler(OnDataSourceViewChanged);
_currentViewValid = true;
return _currentView;
}
/// <summary>
/// Bind the Accordion to its DataSource
/// </summary>
public override void DataBind()
{
// Don't databind to a data source control when the control is in the designer but not top-level
if (IsBoundUsingDataSourceID && DesignMode && (Site == null))
return;
// do our own databinding
RequiresDataBinding = false;
OnDataBinding(EventArgs.Empty);
}
/// <summary>
/// DataBind the Accordion to its panes
/// </summary>
/// <param name="e">EventArgs</param>
protected override void OnDataBinding(EventArgs e)
{
base.OnDataBinding(e);
//Only bind if the control has the DataSource or DataSourceID set
if (this.DataSource!=null || IsBoundUsingDataSourceID)
{
// reset the control state
ClearPanes();
ClearChildViewState();
// and then create the control hierarchy using the datasource
CreateControlHierarchy(true);
ChildControlsCreated = true;
}
}
/// <summary>
/// Create the new control hierarchy of AccordionPanes
/// (using the DataSource if specificed)
/// </summary>
/// <param name="useDataSource">Whether or not we should use the DataSource</param>
protected virtual void CreateControlHierarchy(bool useDataSource)
{
int count = -1;
IEnumerable dataSource = null;
List<AccordionPane> itemsArray = new List<AccordionPane>();
if (!useDataSource)
{
object viewCount = ViewState[ItemCountViewStateKey];
// ViewState must have a non-null value for ItemCount because we check for
// this in CreateChildControls
if (viewCount != null)
{
count = (int)viewCount;
if (count != -1)
{
List<object> dummyList = new List<object>(count);
for (int i = 0; i < count; i++)
dummyList.Add(null);
dataSource = dummyList;
itemsArray.Capacity = count;
}
}
}
else
{
dataSource = GetData();
count = 0;
ICollection collection = dataSource as ICollection;
if (collection != null)
itemsArray.Capacity = collection.Count;
}
if (dataSource != null)
{
int index = 0;
foreach (object dataItem in dataSource)
{
AccordionPane ap = new AccordionPane();
Controls.Add(ap);
CreateItem(dataItem, index, AccordionItemType.Header, ap.HeaderContainer, HeaderTemplate, useDataSource);
CreateItem(dataItem, index, AccordionItemType.Content, ap.ContentContainer, ContentTemplate, useDataSource);
itemsArray.Add(ap);
count++;
index++;
}
}
// If we're binding, save the number of items contained in the repeater for use in round-trips
if (useDataSource)
ViewState[ItemCountViewStateKey] = ((dataSource != null) ? count : -1);
}
/// <summary>
/// Create an AccordionPane's item (either Header or Content) and raise the ItemCreated event
/// </summary>
/// <param name="dataItem">Item's data</param>
/// <param name="index">Index</param>
/// <param name="itemType">Type of the item (Header or Content)</param>
/// <param name="container">Control to fill</param>
/// <param name="template">Template for the binding</param>
/// <param name="dataBind">Whether or not to bind</param>
private void CreateItem(object dataItem, int index, AccordionItemType itemType, AccordionContentPanel container, ITemplate template, bool dataBind)
{
if (template == null)
return;
AccordionItemEventArgs itemArgs = new AccordionItemEventArgs(container, itemType);
OnItemCreated(itemArgs);
container.SetDataItemProperties(dataItem, index, itemType);
template.InstantiateIn(container);
if (dataBind)
{
container.DataBind();
OnItemDataBound(itemArgs);
}
}
/// <summary>
/// Ensure that the Accordion has been databound if it needed to be
/// </summary>
protected void EnsureDataBound()
{
try
{
_throwOnDataPropertyChange = true;
if (RequiresDataBinding && !string.IsNullOrEmpty(DataSourceID))
DataBind();
}
finally
{
_throwOnDataPropertyChange = false;
}
}
/// <summary>
/// Returns an IEnumerable that is the DataSource, which either came
/// from the DataSource property or from the control bound via the
/// DataSourceID property.
/// </summary>
/// <returns>DataSource</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Performs complex action")]
protected virtual IEnumerable GetData()
{
_selectResult = null;
DataSourceView view = ConnectToDataSourceView();
if (view != null)
{
Debug.Assert(_currentViewValid);
// create a handle here to make sure this is a synchronous operation.
_selectWait = new EventWaitHandle(false, EventResetMode.AutoReset);
view.Select(SelectArguments, new DataSourceViewSelectCallback(DoSelect));
_selectWait.WaitOne();
}
else if (DataSource != null)
{
_selectResult = DataSource as IEnumerable;
}
return _selectResult;
}
/// <summary>
/// Create the DataSourceSelectArguments (which just defaults to the Empty value
/// because we don't want to sort, filter, etc.)
/// </summary>
/// <returns>DataSourceSelectArguments</returns>
protected virtual DataSourceSelectArguments CreateDataSourceSelectArguments()
{
return DataSourceSelectArguments.Empty;
}
/// <summary>
/// Select the data
/// </summary>
/// <param name="data">Data</param>
private void DoSelect(IEnumerable data)
{
_selectResult = data;
_selectWait.Set();
}
/// <summary>
/// Wrap the CommandArgs of an ItemCommand event with AccordionCommandEventArgs
/// </summary>
/// <param name="source">Source</param>
/// <param name="args">EventArgs</param>
/// <returns>Whether the event was handled</returns>
protected override bool OnBubbleEvent(object source, EventArgs args)
{
bool handled = false;
AccordionCommandEventArgs accordionArgs = args as AccordionCommandEventArgs;
if (accordionArgs != null)
{
OnItemCommand(accordionArgs);
handled = true;
}
return handled;
}
/// <summary>
/// This method is called when DataMember, DataSource, or DataSourceID is changed.
/// </summary>
[SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", Justification = "Assembly is not localized")]
protected virtual void OnDataPropertyChanged()
{
if (_throwOnDataPropertyChange)
throw new HttpException("Invalid data property change");
if (_initialized)
RequiresDataBinding = true;
_currentViewValid = false;
}
/// <summary>
/// Indicate that we need to be databound whenever the DataSourceView changes
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="args">EventArgs</param>
protected virtual void OnDataSourceViewChanged(object sender, EventArgs args)
{
RequiresDataBinding = true;
}
/// <summary>
/// Raise the ItemCommand event
/// </summary>
/// <param name="args">EventArgs</param>
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Using appropriate EventArgs for the Event")]
protected virtual void OnItemCommand(AccordionCommandEventArgs args)
{
if (ItemCommand != null)
ItemCommand(this, args);
}
/// <summary>
/// Raise the ItemCreatedEvent
/// </summary>
/// <param name="args">EventArgs</param>
protected virtual void OnItemCreated(AccordionItemEventArgs args)
{
if (ItemCreated != null)
ItemCreated(this, args);
}
/// <summary>
/// Raise the ItemDataBound event
/// </summary>
/// <param name="args">EventArgs</param>
protected virtual void OnItemDataBound(AccordionItemEventArgs args)
{
if (ItemDataBound != null)
ItemDataBound(this, args);
}
#endregion
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -