はじめに
最近、タスクはリスト内のフィールドの値で色付けされたカレンダーを作成することでした。
同時に、シートを着色するだけでなく、カレンダーのブロックにさまざまなスタイルを適用する必要があるという事実により、タスクは少し複雑でした。
実装
最初の考えは、オブジェクトモデルから色付けしようとすることでした。
しかし...判明したように、月間カレンダー0_0に表示される要素のみがペイントできます
ちなみに、これらの要素には別の特徴があります。これについては以下で詳しく説明します。
まず、WebPartは凡例を表示するために作成されました。
public class StyledCalendar : System.Web.UI.WebControls.WebParts.WebPart
{
#region [ Properties ]
[Personalizable, Browsable( false )]
public string FieldID
{
get ;
set ;
}
[Personalizable, Browsable( false )]
public string ListID
{
get ;
set ;
}
[Personalizable, Browsable( false )]
public List <ItemData> Colored
{
get ;
set ;http://habrahabr.ru/edit/topic/60813/#
}
#endregion
// .............
}
* This source code was highlighted with Source Code Highlighter .
カラーリング用のリストの選択を確実にするために、クラスが作成されました。
[ Serializable ]
public class ItemData
{
public string CSS { get ; set ;}
public string JavaScript { get ; set ; }
public string ItemGUID { get ; set ; }
public string ItemText { get ; set ; }
}
public class StyledCalendarEditorPart : EditorPart, IPostBackEventHandler
{
private DropDownList _ddlFields;
private DropDownList _ddlValues;
private DropDownList _ddlCalendars;
//
protected override void CreateChildControls()
{
Panel groupPanel = new Panel();
_ddlFields = new DropDownList();
_ddlValues = new DropDownList();
_ddlCalendars = new DropDownList();
_txtStyleName = new TextBox();
_txtStyleName.ID = "txtStyleName" ;
_btnChange = new Button();
_btnChange.Text = "Change Style" ;
_btnChange.OnClientClick = "openStyleWindow()" ;
_ddlValues.Attributes.Add( "onchange" , "onFieldValueChange(this, '" + _txtStyleName.ClientID + "')" );
_ddlCalendars.SelectedIndexChanged += new EventHandler(_ddlCalendars_SelectedIndexChanged);
_ddlCalendars.AutoPostBack = true ;
if (_list != String .Empty )
_ddlCalendars.Text = _list;
_ddlFields.SelectedIndexChanged += new EventHandler(_ddlFields_SelectedIndexChanged);
_ddlFields.AutoPostBack = true ;
if (_field!= String .Empty)
_ddlFields.Text = _field;
groupPanel.Controls.Add( new LiteralControl( "<br>" ));
groupPanel.Controls.Add( new LiteralControl( "Calendars on page:<br>" ));
groupPanel.Controls.Add(_ddlCalendars);
groupPanel.Controls.Add( new LiteralControl( "<br>" ));
groupPanel.Controls.Add( new LiteralControl( "Choice Fields:<br>" ));
groupPanel.Controls.Add(_ddlFields);
groupPanel.Controls.Add( new LiteralControl( "<br>" ));
groupPanel.Controls.Add( new LiteralControl( "Field Value:<br>" ));
groupPanel.Controls.Add(_ddlValues);
groupPanel.Controls.Add( new LiteralControl( "<br>" ));
groupPanel.Controls.Add( new LiteralControl( "<br>" ));
groupPanel.Controls.Add(_btnChange);
groupPanel.Controls.Add( new LiteralControl( "<br>" ));
groupPanel.Controls.Add( new LiteralControl( "Template Preview:<br>" ));
_lbPreview = new Label();
_lbPreview.Text = MakePreview();
groupPanel.Controls.Add(_lbPreview);
groupPanel.Controls.Add( new LiteralControl( "<br>" ));
groupPanel.Controls.Add( new LiteralControl( "Style Name:<br>" ));
groupPanel.Controls.Add(_txtStyleName);
this .Controls.Add(groupPanel);
}
//
}
* This source code was highlighted with Source Code Highlighter .
ウィンドウを開いたプロジェクトにjsファイルが追加されました
ウィンドウの内容-LAYOUTSに置かれたSetStyle.aspxファイル
実際には、着色の組織に進むことができます。
経験的に(リフレクター)、リストのテンプレートがどこから来たかがわかりました
TEMPLATES \ CONTROLTEMPLATES \ DefaultTemplates.aspx
その中には次のようなものがあります:
< SharePoint:RenderingTemplate ID ="CalendarViewMonthItemMultiDayTemplate" runat ="server" >
< Template >
< div class ="<%# DataBinder.Eval(Container," DivClass "," ")%>" dir ="<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container," DataItem . Direction "," "))%>" >
< table border ="0" width ="100%" cellspacing = 0 cellpadding = 0 dir ="<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container," DataItem . Direction "," "))%>" >
< tr >
< td class ="<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container," DataItem . BackgroundColorClassName "," "))%>"
onmouseover ="this.className='<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container," DataItem . BackgroundColorClassName "," "))%>sel';"
onmouseout ="this.className='<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container," DataItem . BackgroundColorClassName "," "))%>';"
href ="<%# SPHttpUtility.HtmlUrlAttributeEncode(DataBinder.Eval(Container," DataItem . DisplayFormUrl "," "))%>?ID=<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container," DataItem . ItemID "," "))%>"
ONCLICK ="GoToLink(this);return false;" target ="_self"
>
< a onfocus ="OnLink(this)"
href ="<%# SPHttpUtility.HtmlUrlAttributeEncode(DataBinder.Eval(Container," DataItem . DisplayFormUrl "," "))%>?ID=<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container," DataItem . ItemID "," "))%>"
ONCLICK ="GoToLink(this);return false;" target ="_self"
tabindex =&# 60 ;%# DataBinder . Eval ( Container , "TabIndex" )%&# 62 ;
>
< b > <% # SPHttpUtility.HtmlEncode(DataBinder.Eval(Container, "DataItem.Title" , "{0:G}" )) %> </ b >
</ a >
</ td >
</ tr >
</ table >
</ div >
</ Template >
</ SharePoint:RenderingTemplate >
* This source code was highlighted with Source Code Highlighter .
そして、アイテムのカレンダーの各タイプに対して。
このファイルを変更する必要はありません。 CONTROLTEMPLATESフォルダーに任意の名前で独自のファイルを作成できます。 SharepointはIDでテンプレートを検索しますが、control-templateのタイプをチェックするため、テンプレート自体から継承することはできません-それは封印されています:((
内容:
< SharePoint:renderingtemplate id ="CalendarViewWeekItemTemplate" runat ="server" >
< Template >
item'a
</ Template >
</ SharePoint:renderingtemplate >
* This source code was highlighted with Source Code Highlighter .
最初は、Bindingを追加するというアイデアがありましたが、予約フィールドに加えて、zl-listに到達することは不可能でした:(
次に、テンプレートコントロールが書き込まれ、その中にテーブルの一部が挿入されました。
残念ながら、このメカニズムは動作しなかったため、このケースのソースコードは残りませんでした。
月間カレンダー、特にCalendarViewMonthItemMultiDayTemplateに関連付けられたアイテム
デバッガーから判断すると、バインディングが到着したとき、ほとんどすべての制御フィールドがヌルでした。
他のコントローラーではすべてが機能しました0_o
次に、概念が変更されました。テンプレートからHTMLコードを厳密に生成し、Sharepointオブジェクトモデルを介してリストからデータを取得する、新しい非テンプレートコントロールが作成されました。
その結果、テンプレートコードは次のように要約されました。
< SharePoint:renderingtemplate id ="CalendarViewWeekItemTemplate" runat ="server" >
< Template >
< myCompany:MyCompanyCalendarViewDayItemCtrl ID ="myCompanyCalendarViewDayItemCtrl1" runat ="server" >
</ myCompany:MyCompanyCalendarViewDayItemCtrl >
</ Template >
</ SharePoint:renderingtemplate >
* This source code was highlighted with Source Code Highlighter .
クラスの実装:
public class RenderItemData
{
public string ItemName { get ; set ; }
public string ItemStyle { get ; set ; }
public string ItemDisplayFormUrl { get ; set ; }
public string ItemId { get ; set ; }
public string ItemTitle { get ; set ; }
public string ItemDefaultBackground { get ; set ; }
public string ItemDirection { get ; set ; }
}
[ToolboxData( "<{0}:MyCompanyCalendarViewMonthItemCtrl runat=server></{0}:MyCompanyCalendarViewMonthItemCtrl>" )]
public class MyCompanyCalendarView : WebControl
{
public static Dictionary< string , RenderItemData> _dict;
RenderItemData _item;
private string _dispType;
[Bindable( true )]
[Category( "Appearance" )]
[Localizable( true )]
protected string DisplayType
{
get
{
return _dispType;
}
set
{
_dispType = value ;
}
}
public MyCompanyCalendarView()
{
if (_dict == null )
{
_dict = new Dictionary< string , RenderItemData>();
}
}
protected override void OnLoad( EventArgs e)
{
WebPartManager wp = WebPartManager.GetCurrentWebPartManager( this . Page );
StyledCalendar cal = null ;
foreach (WebPart part in wp.WebParts)
{
cal = part as StyledCalendar;
if (cal != null )
{
break ;
}
}
if (cal == null )
{
return ;
}
SPCalendarItem calItem = (SPCalendarItem)((Microsoft.SharePoint.WebControls.SPCalendarItemContainer)( this .Parent)).DataItem;
_item = new RenderItemData();
_item.ItemTitle = calItem.Title;
_item.ItemId = calItem.ItemID;
_item.ItemDisplayFormUrl = calItem.DisplayFormUrl;
_item.ItemDefaultBackground = calItem.BackgroundColorClassName;
_item.ItemDirection = calItem.Direction;
using (SPWeb web = SPContext.Current.Web)
{
SPList list = web.Lists[ new Guid (cal.ListID)];
string fieldValue = String .Empty;
string [] recId = calItem.ItemID.Split( new char [] { '.' });
foreach (SPListItem listItem in list.Items)
{
if (recId.Length > 1)
{
if (listItem.ID.ToString() == recId[0])
{
fieldValue = listItem[ new Guid (cal.FieldID)].ToString();
break ;
}
}
else
if (listItem.ID.ToString() == calItem.ItemID)
{
fieldValue = listItem[ new Guid (cal.FieldID)].ToString();
break ;
}
}
_item.ItemName = fieldValue;
foreach (ItemData data in cal.Colored)
{
if (data.ItemText == _item.ItemName)
{
_item.ItemStyle = data.CSS;
}
}
// Item - .
if (_dict.ContainsKey(calItem.DisplayFormUrl + _item.ItemId.ToString()))
{
_dict.Remove(calItem.DisplayFormUrl + _item.ItemId.ToString());
}
_dict.Add(calItem.DisplayFormUrl + _item.ItemId.ToString(), _item);
}
base .OnLoad(e);
}
// Item'
// - , ,
protected virtual string GetInnerTemplate(RenderItemData renderData, SPCalendarItem calendarItem, SPCalendarItemContainer container)
{
StringBuilder sb = new StringBuilder ();
string background = calendarItem.BackgroundColorClassName;
string bgsel = calendarItem.BackgroundColorClassName + "sel" ;
if (renderData != null && String .IsNullOrEmpty(renderData.ItemStyle) == false )
{
background += "_m" ;
bgsel += "_m" ;
}
sb.AppendFormat( "<td class='{0}'" , background);
sb.AppendFormat( "onmouseover=\"this.className='{0}';\"" , bgsel);
sb.AppendFormat( "onmouseout=\"this.className='{0}';\"" , background);
sb.AppendFormat( "href='{0}?ID={1}'" , calendarItem.DisplayFormUrl, calendarItem.ItemID);
sb.AppendFormat( "ONCLICK='GoToLink(this);return false;' target='_self'" );
sb.AppendFormat( ">" );
sb.AppendFormat( "<a onfocus='OnLink(this)'" );
if (renderData != null && ! String .IsNullOrEmpty(renderData.ItemStyle))
{
sb.AppendFormat( " {0} " , renderData.ItemStyle);
}
sb.AppendFormat( "href='{0}?ID={1}'" , calendarItem.DisplayFormUrl, calendarItem.ItemID);
sb.AppendFormat( "ONCLICK='GoToLink(this);return false;' target='_self'" );
sb.AppendFormat( "tabindex={0}" , container.TabIndex);
sb.AppendFormat( ">" );
sb.AppendFormat( "<b>{0:G}</b>" , calendarItem.Title);
sb.AppendFormat( "</a>" );
sb.AppendFormat( "</td>" );
return sb.ToString();
}
protected override void Render(HtmlTextWriter writer)
{
CreateChildControls();
SPCalendarItemContainer cont = Parent as SPCalendarItemContainer;
SPCalendarItem item = cont.DataItem as SPCalendarItem;
RenderItemData renderData = null ;
_dict.TryGetValue(item.DisplayFormUrl + item.ItemID, out renderData);
string background = item.BackgroundColorClassName;
string bgsel = item.BackgroundColorClassName + "sel" ;
string suffix = String .Empty;
if (renderData != null && String .IsNullOrEmpty(renderData.ItemStyle) == false )
{
suffix = "_m" ;
}
background += suffix;
bgsel += suffix;
StringBuilder sb = new StringBuilder ();
if (renderData != null && ! String .IsNullOrEmpty(renderData.ItemStyle))
{
sb.AppendFormat( "<div {0} dir='{1}'>" , renderData.ItemStyle, item.Direction);
}
else
{
sb.AppendFormat( "<div class='{0}' dir='{1}'>" , cont.DivClass, item.Direction);
}
string tableStyle = "" ;
switch (item.CalendarType)
{
case 0:
String .Format( "class='ms-cal-tdayitem{0}'" , suffix);
break ;
case 1: // Week Item
tableStyle = String .Format( "class='ms-cal-tweekitem{0}'" , suffix);
break ;
case 2:
tableStyle = String .Format( "class='ms-cal-tmonthitem{0}'" , suffix);
break ;
default :
tableStyle = string .Empty;
break ;
}
sb.AppendFormat( "<table border='0' width='100%' cellspacing=0 cellpadding=0 dir='{0}' {1}>" , item.Direction, tableStyle);
sb.AppendFormat( "<tr>" );
sb.Append(GetInnerTemplate(renderData, item, cont));
sb.AppendFormat( "</tr>" );
sb.AppendFormat( "</table>" );
sb.AppendFormat( "</div>" );
writer.Write(sb.ToString());
base .Render(writer);
}
}
* This source code was highlighted with Source Code Highlighter .
さらに、複数の子孫が異なるタイプのItem'ovに継承されました。
実際の子コントロールはテンプレートに挿入されます。
展開する
- TEMPLATES \ CONTROLTEMPLATESのテンプレートを含むすべてのページをコピーします
- TEMPLATES \ LAYOUTSのポップアップウィンドウに表示されるページをコピーします
- プロジェクトアセンブリをGACに配置します
- SafeControlサイトでアセンブリを登録します
結果として何が起こったのか:
このアプローチを提供するものは何ですか?
コーデックスには、ページへのJavaScript接続を介して同様のカレンダーが実装されているプロジェクトがあります。
短所:
- JSエラーが発生し、左側のコンポーネントのページのどこかですべてがクラッシュし、多くのユーザーがデバッガーをデフォルトでオフにしているため、何も表示されません。
- 限られたカスタマイズオプション
このアプローチを提供するもの:
- Silverlightコンポーネントが特定のセルに挿入されるバージョンを作成しています。
- 主観的に、カレンダーのレンダリング速度が向上しました(すべてのバインディングはコードから取得されます)
- 同様に、コントローラーをテンプレートコントローラーに置き換えることができます。
この作業は、残念ながらHabréのアカウントを持っていない友人と一緒に実施されましたが、本当にそれに参加したいので、彼に提供された招待に感謝します:)
ご清聴ありがとうございました!