OlapDataSourceModel を使用して Controller 側で igPivotGrid のデータを定義する

以前の弊社のブログに、GridModel クラスを使用して igGrid の定義を View 側( cshtml ファイル)ではなく、 Controller 側でを行う方法をご紹介したものがございました。この方法はグリッドにバインドするデータが可変であり、それに応じてグリッドの定義を行いたい場合などに有効です。

igPivotGrid は行や列に表示する項目やメジャーとなる項目の定義を OlapDataSource で行うコントロールですが、これも OlapDataSourceModel クラスを使用して Controller 側でデータ定義を行うことが可能です。

今回は、このクラスを使用して Controller 側で igPivotGrid のデータを定義する方法をご紹介します。

 


初めに、Html Helper を使用して View 側で FlatDataSource を生成する通常の方法をみてみましょう。

今回 Model として使用するのは以下のように定義した SalesItem クラスです。

 

SalesItem.cs

public class SalesItem
{
	public string ProductCategory { get; set; }
	public string SellerName { get; set; }
	public double UnitPrice { get; set; }
	public int UnitsSold { get; set; }
	public string SalesDate { get; set; }
}

 


View 側へは SalesItem を以下のようなリストにして渡します。

 

HomeController.cs

public ActionResult Index()
{
	var sales = new List<SalesItem>() { 
		new SalesItem(){ 
			ProductCategory = "Clothing", 
			SellerName = "Stanley Brooker", 
			UnitPrice = 12.814, 
			UnitsSold = 282, 
			SalesDate = DateTime.Today.ToString()
		},
		new SalesItem(){ 
			ProductCategory = "Bikes", 
			SellerName = "Elisa Longbottom", 
			UnitPrice = 49.579, 
			UnitsSold = 201, 
			SalesDate = DateTime.Today.AddMonths(-14).ToString()
		},
		new SalesItem(){ 
			ProductCategory = "Accessories", 
			SellerName = "Erica Wild", 
			UnitPrice = 3.565, 
			UnitsSold = 68, 
			SalesDate = DateTime.Today.AddMonths(-20).ToString()
		}
	};

	return View(sales.AsQueryable());
}

 

 

そして、View では上記のリストデータを DataSource として以下のように OlapDataSource を生成します。

 

Index.cshtml

@model IQueryable<WebApplication1MVC.Models.SalesItem>
.....

@(Html.Infragistics()
    .OlapDataSource()
    .ID("flatDataSource")
    .DataSourceOptions(dataSourceOptions => dataSourceOptions
        .Columns("[SalesDate].[SalesDate]")
        .Rows("[ProductCategory].[ProductCategory]")
        .Measures("[Measures].[UnitPrice]")
        .FlatDataOptions(flatOptions =>
            flatOptions.Metadata(metadata =>
                metadata.Cube(cube => cube.Name("Sales")
                    .MeasuresDimension(measuresDimension => measuresDimension.Measures(
                        measures =>
                        {
                            measures.AddMeasure().Name("UnitPrice").Caption("Unit Price")
                                .Aggregator("$.ig.OlapUtilities.prototype.sumAggregator('UnitPrice')");
                            measures.AddMeasure().Name("UnitsSold").Caption("Units Sold")
                                .Aggregator("$.ig.OlapUtilities.prototype.sumAggregator('UnitsSold')");
                        })
                    )
                    .Dimensions(dimensions =>
                    {
                        dimensions.AddDimension().Name("Seller").Caption("Seller").Hierarchies(hiearachies =>
                        {
                            hiearachies.AddHierarchy().Name("Seller").Caption("Seller").Levels(levels =>
                            {
                                levels.AddLevel().Name("AllSellers").Caption("All Sellers")
                                    .MemberProvider("function(item) {return 'All Sellers';}");
                                levels.AddLevel().Name("SellerName").Caption("Seller Name")
                                    .MemberProvider("function(item) {return item.SellerName; }");
                            });
                        });
                        dimensions.AddDimension().Name("SalesDate").Caption("Sales Date").Hierarchies(hierarchies =>
                        {
                            hierarchies.AddHierarchy().Name("SalesDate").Caption("Sales Date").Levels(levels =>
                            {
                                levels.AddLevel().Name("AllPeriods").Caption("All Periods")
                                    .MemberProvider("function(item) { return 'All Periods'; }");
                                levels.AddLevel().Name("Year").Caption("Year")
                                    .MemberProvider("$.ig.OlapUtilities.prototype.dateMemberProvider('year', 'SalesDate')");
                                levels.AddLevel().Name("Quarter").Caption("Quarter")
                                    .MemberProvider("$.ig.OlapUtilities.prototype.dateMemberProvider('quarter', 'SalesDate')");
                                levels.AddLevel().Name("Month").Caption("Month")
                                    .MemberProvider("$.ig.OlapUtilities.prototype.dateMemberProvider('month', 'SalesDate')");
                                levels.AddLevel().Name("Date").Caption("Date")
                                    .MemberProvider("$.ig.OlapUtilities.prototype.dateMemberProvider('date', 'SalesDate')");
                            });
                        });
                        dimensions.AddDimension().Name("ProductCategory").Caption("Product Category").Hierarchies(
                            hiearachies =>
                                hiearachies.AddHierarchy().Name("ProductCategory").Caption("Product Category").Levels(levels =>
                                {
                                    levels.AddLevel().Name("AllProducts").Caption("All Products")
                                        .MemberProvider("function(item) {return 'All Products'; }");
                                    levels.AddLevel().Name("ProductCategory").Caption("Product Category")
                                        .MemberProvider("function(item) {return item.ProductCategory; }");
                                })
                        );
                    })
                )
            )
            .DataSource(Model)
            .DataBind()
        )
    )
    .Render()
)

 

 

上記のコードで行われている内容ですが、OlapDataSource の Columns、Rows、Measures オプションに対してそれぞれ初期ロード時に列、行、メジャーとなる項目を設定しています。そして、今回は FlatDataSource を使用しますので、そのオプション設定としてメタデータを定義した cube を作成しています。メジャー項目はMeasuresDimension の Measures コレクションに、行列項目は Dimensions コレクションに追加します。各項目では、name に加えてメジャー項目ではセルの計算式となる aggregator、行列項目ではデータの階層となるhierarchies の設定が必要です。最後に、DataSource には Controller から送られた Model が割り当てています。

さて、このように定義した OlapDataSource は、igPivotGrid や igPivotDataSelector の DataSourceID に ID を指定して

 

Index.cshtml

<div style="float:left;">
@(Html.Infragistics()
    .PivotDataSelector()
    .ID("dataSelector")
    .DataSourceID("flatDataSource")
    .Width("300")
    .Height("600")
    .Render()
)
</div>
<div style="float: left; ">
@(Html.Infragistics()
    .PivotGrid()
    .ID("pivotGrid")
    .Width("800")
    .Height("600")
    .DataSourceID("flatDataSource")
    .GridOptions(opt =>
    {
        opt.Features(f => f.Resizing());
    })
    .Render()
)
</div>

 

 

このように表示されます。

 

image

 

それでは、上で行った OlapDataSource の定義を OlapDataSourceModel クラスを使用して行ってみます。完成したインスタンスは ViewResult として返しますので、Contoller の Index() は以下のようになります。

 

HomeController.cs

public ActionResult Index()
{
	var sales = new List<SalesItem>() { 
		new SalesItem(){ 
			ProductCategory = "Clothing", 
			SellerName = "Stanley Brooker", 
			UnitPrice = 12.814, 
			UnitsSold = 282, 
			SalesDate = DateTime.Today.ToString()
		},
		new SalesItem(){ 
			ProductCategory = "Bikes", 
			SellerName = "Elisa Longbottom", 
			UnitPrice = 49.579, 
			UnitsSold = 201, 
			SalesDate = DateTime.Today.AddMonths(-14).ToString()
		},
		new SalesItem(){ 
			ProductCategory = "Accessories", 
			SellerName = "Erica Wild", 
			UnitPrice = 3.565, 
			UnitsSold = 68, 
			SalesDate = DateTime.Today.AddMonths(-20).ToString()
		}
	};


	OlapDataSourceModel odsm = new OlapDataSourceModel();
	odsm.ID = "flatDataSource";
	odsm.DataSourceOptions.Columns = "[SalesDate].[SalesDate]";
	odsm.DataSourceOptions.Rows = "[ProductCategory].[ProductCategory]";
	odsm.DataSourceOptions.Measures = "[Measures].[UnitPrice]";
	odsm.DataSourceOptions.FlatDataOptions.DataSource = sales;

	CubeMetadata cmd = new CubeMetadata();
	cmd.Name = "Sales";

	MeasuresDimensionMetadata mdmd = new MeasuresDimensionMetadata();
	mdmd.Measures.Add(new MeasureMetadata() { 
		Name = "UnitPrice", 
		Caption = "Unit Price", 
		Aggregator = "$.ig.OlapUtilities.prototype.sumAggregator('UnitPrice')" 
	});
	mdmd.Measures.Add(new MeasureMetadata() { 
		Name = "UnitsSold", 
		Caption = "Units Sold", 
		Aggregator = "$.ig.OlapUtilities.prototype.sumAggregator('UnitsSold')" 
	});
	cmd.MeasuresDimension = mdmd;

	List<LevelMetadata> liSellerLevels = new List<LevelMetadata>();
	liSellerLevels.Add(new LevelMetadata() { 
		Name = "AllSellers", 
		Caption = "All Sellers", 
		MemberProvider = "function(item) {return 'All Sellers';}" 
	});
	liSellerLevels.Add(new LevelMetadata() { 
		Name = "SellerName", 
		Caption = "Seller Name", 
		MemberProvider = "function(item) {return item.SellerName; }" 
	});
	List<HierarchyMetadata> liSellerHierarchies = new List<HierarchyMetadata>();
	liSellerHierarchies.Add(new HierarchyMetadata() { 
		Name = "Seller", 
		Caption = "Seller", 
		Levels = liSellerLevels 
	});
	cmd.Dimensions.Add(new DimensionMetadata() { 
		Name = "Seller", 
		Caption = "Seller", 
		Hierarchies = liSellerHierarchies });

	List<LevelMetadata> liDateLevels = new List<LevelMetadata>();
	liDateLevels.Add(new LevelMetadata() { 
		Name = "AllPeriods", 
		Caption = "All Periods", 
		MemberProvider = "function(item) { return 'All Periods'; }" 
	});
	liDateLevels.Add(new LevelMetadata() { 
		Name = "Year", 
		Caption = "Year", 
		MemberProvider = "$.ig.OlapUtilities.prototype.dateMemberProvider('year', 'SalesDate')" 
	});
	liDateLevels.Add(new LevelMetadata() { 
		Name = "Month", 
		Caption = "Month", 
		MemberProvider = "$.ig.OlapUtilities.prototype.dateMemberProvider('month', 'SalesDate')" 
	});
	liDateLevels.Add(new LevelMetadata() { 
		Name = "Date", 
		Caption = "Date", 
		MemberProvider = "$.ig.OlapUtilities.prototype.dateMemberProvider('date', 'SalesDate')" 
	});
	List<HierarchyMetadata> liDateHierarchies = new List<HierarchyMetadata>();
	liDateHierarchies.Add(new HierarchyMetadata() { 
		Name = "SalesDate", 
		Caption = "Sales Date", 
		Levels = liDateLevels 
	});
	cmd.Dimensions.Add(new DimensionMetadata() { 
		Name = "SalesDate", 
		Caption = "Sales Date", 
		Hierarchies = liDateHierarchies 
	});

	List<LevelMetadata> liProductLevels = new List<LevelMetadata>();
	liProductLevels.Add(new LevelMetadata() { 
		Name = "AllProducts", 
		Caption = "All Products", 
		MemberProvider = "function(item) {return 'All Products'; }" 
	});
	liProductLevels.Add(new LevelMetadata() { 
		Name = "ProductCategory", 
		Caption = "Product Category", 
		MemberProvider = "function(item) {return item.ProductCategory; }" 
	});
	List<HierarchyMetadata> liProductHierarchies = new List<HierarchyMetadata>();
	liProductHierarchies.Add(new HierarchyMetadata() { 
		Name = "ProductCategory", 
		Caption = "Product Category", 
		Levels = liProductLevels 
	});
	cmd.Dimensions.Add(new DimensionMetadata() { 
		Name = "ProductCategory", 
		Caption = "Product Category", 
		Hierarchies = liProductHierarchies 
	});

	odsm.DataSourceOptions.FlatDataOptions.Metadata.Cube = cmd;
	odsm.DataSourceOptions.FlatDataOptions.DataBind();

	return View(odsm);
}

 

 

View では、Controller より送られた Model を OlapDataSource に設定するだけです。

 

Index.cshtml

@model Infragistics.Web.Mvc.OlapDataSourceModel
.....

@(Html.Infragistics().OlapDataSource(Model))

 

 

今回のサンプルはこちらからダウンロードいただけます。
(当サンプルは16.2.20162. 2040を使用して作成されました)

 

最後までお読みくださり、ありがとうございました。

ASP.NET アプリケーションで QR コード入りの PDF を作成する

以前のブログで Windows Forms アプリケーションにて WPF コントロールの XamBarcode を使用する方法をご案内致しました。

今回はウェブ版の ASP.NET アプリケーションで QR コードを取り扱う方法をご紹介します。

Infragistics ASP.NET 製品には、QR コードやバーコードを作成することのできるコントロールがございません。そこで、以前のブログのようにQR コードの作成には Infragistics WPF のコントロールである XamQRCodeBarcode を使用します。今回はさらにその画像を取り込んで PDF ファイルを作成してみたいと思います。PDF の作成には、 Infragistics ASP.NET 製品に含まれる Document ライブラリを使用します。



それでは、完成したアプリケーションをご覧ください。

image


テキストボックスに文字列を入力して「 Create PDF 」ボタンをクリックすると、、、

image


このような PDF が生成されました。この QR コードは動的に作成されており、値は先ほど入力した”my test qr”となっています。

 

今回のアプリケーションは2つのプロジェクトから成り立っています。
ひとつは外部からのインプットデータを使用して XamQRCodeBarcode を通してイメージファイルを生成する WPF のプロジェクト、もう一つは、その exe ファイルを呼び出し、生成されたイメージファイルを使用してPDF ファイルを作成する ASP.NET プロジェクトです。

ホストとなるのは後者の ASP.NET プロジェクトとなります。

 

それでは、まず WPF プロジェクトから見てみます。

xaml ファイルに XamQRCodeBarcode を配置します。

 

<ig:XamQRCodeBarcode Name="barcode" Loaded="barcode_Loaded" />

 

Loaded のタイミングで QR コードのイメージファイルを作成するため、イベントをフックアップしておきます。

次にコードビハインドです。
MainWindow のコンストラクタで、プロジェクトへのインプットデータであるコマンドライン引数( Environment.GetCommandLineArgs() )を使用して XamQRCodeBarcode を生成します。

 

public MainWindow()
{
	InitializeComponent();
	string[] args = Environment.GetCommandLineArgs();

	this.barcode.Data = args[2];
	this.barcode.Height = 200;
	this.barcode.Width = 200;
	this.barcode.ErrorCorrectionLevel = QRCodeErrorCorrectionLevel.Low;
	this.barcode.BarsFillMode = BarsFillMode.EnsureEqualSize;
}


続いて FrameworkElement から画像ファイルを生成するメソッドを記述します。

public void CreateImage(FrameworkElement element)
{
	string[] args = Environment.GetCommandLineArgs();
	string path = args[1];

	double width = element.Width;
	double height = element.Height;

	RenderTargetBitmap bmpCopied = new RenderTargetBitmap((int)Math.Round(width), 
		(int)Math.Round(height), 96, 96, PixelFormats.Default);
	DrawingVisual dv = new DrawingVisual();

	using (DrawingContext dc = dv.RenderOpen())
	{
		VisualBrush vb = new VisualBrush(element);
		dc.DrawRectangle(vb, null, new Rect(new Point(), new Size(width, height)));
	}

	bmpCopied.Render(dv);

	PngBitmapEncoder encoder = new PngBitmapEncoder();
	encoder.Frames.Add(BitmapFrame.Create(bmpCopied));

	FileStream stream5 = new FileStream(path, FileMode.Create);
	encoder.Save(stream5);

	this.Close();
}


ここでは CommandLineArgs から取得したパスに生成した画像ファイルを書き出しています。

上記のメソッド CreateImage(FrameworkElement) は、XamQRCodeBarcode でフックアップしておいたLoaded イベントで実行します。XamQRCodeBarcode の生成の完了を待って画像ファイルを作成するためです。

 

private void barcode_Loaded(object sender, RoutedEventArgs e)
{
	CreateImage(barcode);
}

 

WPF プロジェクトの実装は以上です。

テストを行う際はコマンドライン引数を指定してください。第一引数は QR コードの画像保存先のファイルパス、第二引数は QR コードのデータです。


続いてメインとなる ASP.NET プロジェクトを作成します。

aspx ファイルに、QR コードのデータを入力するための TextBox、PDF ファイルの作成を実行するボタンを配置します。

<asp:Label ID="Label1" runat="server" Text="Label">Enter QRcode Text:</asp:Label>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
</br></br>
<asp:Button ID="Button1" runat="server" Text="Create PDF" OnClick="Button1_Click" />

 

コードビハインドでは、2つのメソッドを定義します。先ほど作成した WPF プロジェクトを実行して QR コードの画像ファイルを生成するメソッド CreateImage(string) と PDF ファイルを生成するメソッドCreateReport() です。

CreateImage(string) は引数に送られた string をコマンド引数に送りながら WPF プロジェクトの exe を実行します。以下がメソッドの定義です。中で Process インスタンスを生成して実行しています。

 

private void CreateImage(string data)
{
	string barcode;
	if (data == "")
	{
		barcode = "testBarcodeData";
	}
	else
	{
		barcode = '"' + data + '"';
	}

	string dir = (Server.MapPath("~/Images") + "\\testBarcode.bmp");

	string[] args = { dir, barcode};
	string arg = String.Join(" ", args);

	Process proc = new Process();
	//proc.StartInfo.FileName = "The path to the executable WPF file like this -> 
    //C:\\Users\\username\\Documents\\visual studio 2012\\Projects\\ASP_NET_QRCode\\xamQRBarcode\\xamQRBarcode\\bin\\Debug\\xamQRBarcode.exe"
	proc.StartInfo.Arguments = arg;
	proc.StartInfo.UseShellExecute = false;
	proc.StartInfo.RedirectStandardOutput = true;
	proc.Start();
	proc.WaitForExit(30000);
}


ここで、Process の StartInfo.FileName プロパティには WPF プロジェクトの .exe ファイルへのパスを割り当てる必要があります。.exe ファイルは WPF プロジェクトの bin\Debug フォルダ内にあります。アプリケーションを実行する環境に合わせて、正しいパスを設定してください。

 

続いて CreateReport() では以下のようにPDFファイルを生成します。

InfragisticsのDocument ライブラリを使用しますので、必要な dll (Infragistics45.WebUI.Documents.ReportsおよびInfragistics45.WebUI.Documents.Core) を Visual Studio の参照設定に追加してください。

 

private void CreateReport()
{
	Report report = new Report();

	ISection section1 = report.AddSection();

	string dir = (Server.MapPath("~/Images") + "\\testBarcode.bmp");

	Infragistics.Documents.Reports.Graphics.Image img = 
		new Infragistics.Documents.Reports.Graphics.Image(dir);

	IText imageText = section1.AddText();
	imageText.AddContent(img, new Size(200, 200));

	report.Publish(Server.MapPath("~/PDF") + "\\Report.pdf", FileFormat.PDF);
	System.Diagnostics.Process.Start(Server.MapPath("~/PDF") + "\\Report.pdf");
}

 

QR コードの画像ファイルから Image インスタンスを作成し、Report のセクションに追加しています。生成された PDF ファイルは上記 Report インスタンスの Publish() メソッドで指定されているパス( ASP.NET プロジェクト内の PDF フォルダ)に保存されます。

最後に、これらのメソッドをボタンのクリックサーバーサイドイベントで実行します。

CreateImage(string) には、画面上の TextBox の Text データを送ります。

 

protected void Button1_Click(object sender, EventArgs e)
{
	CreateImage(TextBox1.Text);

	CreateReport();
}

 

QR コード入りの PDF を作成するアプリケーションの実装は以上です。

 

今回のサンプルはこちらからダウンロードいただけます。
(当サンプルは16.2.20162.2045 ( WPF )および16.2.20162.2013( ASP.NET )を使用して作成されました)

今回も最後までお読みくださり、ありがとうございました。

Windows Forms でホストした XamBarcode をプリンター印刷する

Infragistics 製品にはバーコードやQRコードを生成することのできるコントロールが含まれています。 Windows Forms 版には専用の UltraBarcode コントロール( UltraCode128Barcode や UltraQRCodeBarcode )がございますが、プリンターでの印刷の際にはフォームに表示されている時と比べて若干鮮明度が劣るようです。一方、 WPF 版の XamBarcode コントロールは印刷時も鮮明度が保たれます。そこで、今回は Windows Forms アプリケーションで ElementHost コントロールによってWPFコントロールであるXamBarcodeをホストし、印刷する方法をご紹介します。

Windows Forms で WPF コントロールをホストするために、まずは Windows Forms のソリューションに新規ライブラリとして「WPFユーザーコントロールライブラリ」を追加します。デフォルトの名前( WpfControlLibrary1 )のままライブラリを追加しますと、Visual Studio のソリューションエクスプローラは以下のような表示となります。

image


WPF のマークアップファイルである UserControl1.xaml が自動的に追加されています。

このファイルに、XamBarcode コントロールを配置していきます。

WpfControlLibrary1 プロジェクトの参照設定に、以下の3つの Infragistics アセンブリを追加し、

InfragisticsWPF4.Controls.Barcodes
InfragisticsWPF4.DataVisualization
InfragisticsWPF4

UserControl1.xaml には以下を追加して XamBarcode コントロールの配置を行います。

 

xmlns:ig=http://schemas.infragistics.com/xaml


<ig:XamCode128Barcode x:Name="myBarcode" Data="test code" CodeType="Standard"/>

 


今回は XamCode128Barcode を使用しました。コードのデータは ”test code” としました。Visual Studio のデザイナ画面にバーコードが表示されていることをご確認ください。

 

image

 

次に、このユーザーコントロールを Windows Forms に追加します。
Form1.cs のデザイナ画面を開き、ツールボックスから先ほど作成した UserControl をフォーム上へドラッグドロップしてください。これにより、WPF コントロールをホストするための ElementHost は自動的に生成されます。
さらに、印刷処理実行用にボタンをフォームに追加しておいてください。


ここからは印刷処理の実装です。
バーコードコントロールを印刷するには、バーコードの画像データを一旦 Image インスタンスにしてからPrintDocumentを使用して画像の印刷を行います。


変数として Image インスタンスを以下のように宣言してから、

private Image image;


フォームに追加しておいたボタンの Click イベントを以下のように実装します。

private void button1_Click(object sender, EventArgs e)
{
	XamCode128Barcode codeToPrint = 
		(elementHost1.Child as UserControl1).FindName("myBarcode") as XamCode128Barcode;

	int height = Convert.ToInt32(codeToPrint.ActualHeight);
	int width = Convert.ToInt32(codeToPrint.ActualWidth);

	RenderTargetBitmap renderTargetBitmap = 
		new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Default);
	renderTargetBitmap.Render(codeToPrint);

	using (MemoryStream outStream = new MemoryStream())
	{
		BitmapEncoder encoder = new TiffBitmapEncoder();
		encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
		encoder.Save(outStream);
		this.image = new System.Drawing.Bitmap(outStream);
	}

	PrintDocument printDocument = new PrintDocument();
	printDocument.PrintPage += PrintDocument_PrintPage;
	printDocument.Print();
}

private void PrintDocument_PrintPage(object sender, PrintPageEventArgs e)
{
	e.Graphics.DrawImage(this.image, new Point(0, 0));
	e.HasMorePages = false;
}

 

 

UserControl 上の XamCode128Barcode へは、ElementHost の Child から  FindName() メソッドを使用してアクセスします。ここでも XamCode128Barcode を参照しますので、必要な Infragistics アセンブリをプロジェクトの参照設定に追加してください。

 

アプリケーションを実行してみます。


clip_image005

 

XamBarcode コントロールが Windows Forms のフォームに表示されました。

ボタンのクリックでバーコードが印刷されます。

 

今回のサンプルはこちらからダウンロードいただけます。
(当サンプルは16.2.20162.1006バージョンを使用して作成されました)

 

最後までお読みくださり、ありがとうございました。

igGrid でカスタムのリモートページングを実装する(Web API を使用)

igGrid のページング機能はレコードデータを複数のページに分け、データの読み込みを表示するページ分のみとすることでパフォーマンスを向上させる機能です。

データの取得はローカルまたはリモートで実行できますが、今回ご紹介するのはリモートでデータチャンクを取得し、表示する方法です。

igGrid のリモートページングは Infragistics ASP.NET MVC ラッパーを使用する場合は GridDataSourceActionAttribute 属性を付与したアクションメソッドを作成し、 ActionResult として IQueryable タイプのデータを返すだけで自動的にページング処理が行われます。

ここでは、そのような GridDataSourceActionAttribute を使用するのではなく、カスタムの実装にてリモートページングを実装してみます。サーバーサイドのフレームワークには ASP.NET MVC および Web API を使用します。

作成後の igGrid は次のような見た目になります。

 

image

 

igGrid は1ページに必要なデータレコードのみ(ここでは10レコード)を取得して表示しています。右下のページ番号をクリックしたタイミングでそのページに必要なデータを再取得します。また、1ページに表示するレコード数は右上のドロップダウンから変更することができます。

 

それでは、まずクライアントサイドの igGrid の記述から始めます。今回は Angular を使用してグリッドの定義を行いますが、 javascript や Razor 構文を使用しても同様の機能を実装できます。

Angular の sampleApp モジュールを新規作成し、 gridController コントローラーの登録を行います。

 

<script type="text/javascript">
        var sampleApp = angular.module('sampleApp', ['igniteui-directives']);
        sampleApp.controller('gridController', function ($scope) {
            $scope.actionURL = "/api/products";
        });
</script>

 

actionURL としてデータ取得先の URL を保持する変数を定義しました。 ProductsControllerのアクションに対してデータのリクエストを行う予定です。

続いて DOM 側での Angular ディレクティブを使用した igGrid の定義です。

 

    <div ng-app="sampleApp" ng-controller="gridController">
        <ig-grid id="grid1"
                    data-source=actionURL
                    width="100%"
                    height="400px"
                    primary-key="ProductID"
                    auto-commit="true"
                    auto-generate-columns="false"
                    response-data-key="data">
            <columns>
                <column key="ProductID" header-text="ProductID" width="50px" data-type="number"></column>
                <column key="Name" header-text="Name" width="250px" data-type="string"></column>
                <column key="UnitPrice" header-text="UnitPrice" width="200px" data-type="number"></column>
            </columns>
            <features>
                <feature name="Paging" type="remote" page-size="10" record-count-key="recordCountKey"
                            page-size-url-key="pageSize" page-index-url-key="page">
                </feature>
            </features>
        </ig-grid>
    </div>

 

data-source オプションには、先ほどコントローラーで定義を行った actionURL が設定されています。

カスタムのページングを実装する際のポイントは、 igGrid の response-data-key オプション、および ui.igGridPaging の record-count-key、 page-size-url-key、 page-index-url-keyオプションです。 response-data-key にはデータレコードを保持するプロパティ名、record-count-key にはトータルのデータレコード数を保持するプロパティ名を指定します。

グリッドは、ページに表示するデータを data-source オプションに指定された URL に対してリクエストしますが、その際に必要なデータのページインデックスと必要な行数はpage-index-url-key と page-size-url-key オプションに指定されたパラメータ名で送信します。

クライアントサイドでの igGrid のページング設定は以上です。

 

サーバーサイドで必要なのは、上記グリッドがデータをリクエストするアクションで必要なレコードデータを返す処理です。どのページインデックスで何行分のデータが必要かの情報はパラメータで渡されます。

今回は Web API を使用しますので、 ApiController に HttpResponseMessage を返すアクションメソッドを定義しますが、グリッドのページングで使用するためにはコンテンツは Json で返す必要があります。そこで、ヘルパークラスを使用し、必要なデータ( response-data-key と record-count-key オプションに指定されたプロパティと、行データそのもの)を Json にまとめます。以下は ApiController を継承して作成した ProductsController の定義です。

 

    public class ProductsController : ApiController
    {
        ProductList productList = new ProductList();

        public HttpResponseMessage GetGridData(string page, string pageSize)
        {
            var records = productList.GetProductsToShow(page, pageSize);
            return new HttpResponseMessage()
            {
                Content = new JsonContent(new
                {
                    recordCountKey = 100,   
                    responseDataKey = "data",
                    data = records,
                })
            };
        }
    }

    public class JsonContent : HttpContent
    {
        private readonly MemoryStream _Stream = new MemoryStream();

        public JsonContent(object value)
        {
            var jw = new JsonTextWriter(new StreamWriter(_Stream)) { Formatting = Formatting.Indented };
            var serializer = new JsonSerializer();
            serializer.Serialize(jw, value);
            jw.Flush();
            _Stream.Position = 0;

        }
        protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
        {
            _Stream.CopyTo(stream);
            var tcs = new TaskCompletionSource<object>();
            tcs.SetResult(null);
            return tcs.Task;
        }

        protected override bool TryComputeLength(out long length)
        {
            length = _Stream.Length;
            return true;
        }
    }

上記の GetGridData アクションで使用されている ProductList クラスのGetProductsToShow() は、データ全レコードの中から指定されたページのデータのみ返すメソッドです。 ProductList クラスは以下を使用しました。

 

    public class ProductList
    {
        private List<Product> Products;

        public ProductList()
        {
            Products = new List<Product>();

            for (int i = 0; i < 100; i++)
            {
                Product product = new Product();
                product.ProductID = i;
                product.Name = "Test Product " + i;
                product.UnitPrice = 1000 * (i % 10);

                Products.Add(product);
            }
        }

        public IQueryable<Product> GetProductsToShow(string page, string pageSize)
        {
            int pageIndex = Convert.ToInt32(page);
            int numOfRows = Convert.ToInt32(pageSize);

            return Products.Skip(pageIndex * numOfRows).Take(numOfRows).AsQueryable<Product>();
        }
    }

    public class Product
    {
        public int ProductID { get; set; }
        public string Name { get; set; }
        public int UnitPrice { get; set; }
    }

 

igGrid のリモートページングの実装は以上です。

 

今回のサンプルはこちらからダウンロードいただけます。
(本サンプルは、16.2バージョンで作成されました)

 

最後までお読みくださり、ありがとうございました。

WebDataGrid で複数列のドロップダウンを作成する

 

以前のブログにて WebDataGrid でカスケードのドロップダウン列を作成する方法をご紹介しました。今回は、一つの列のドロップダウンで複数列を持つリストを表示させる方法をご紹介します。

下の図は完成後の WebDataGrid です。DropDownCol 列のドロップダウンに WebDataGrid を表示することにより、複数列表示を行っています。このサンプルではドロップダウン内のグリッドで選択された行のうち、 col2 列の値がドロップダウンの選択値( = WebDataGrid のセルの値)となります。

 

clip_image002

 

コーディングを始めます。

まずは aspx 上での WebDataGrid の定義、およびコードビハインド側でデータソース用に定義したDataTableです。

 

        <ig:WebDataGrid ID="WebDataGrid1" runat="server" Height="350px" 
								Width="400px" DataKeyFields="ID" AutoGenerateColumns="False">
            <Columns>
                <ig:BoundDataField DataFieldName="ID" Key="ID">
                    <Header Text="ID">
                    </Header>
                </ig:BoundDataField>
                <ig:BoundDataField DataFieldName="DropDownCol" Key="DropDownCol">
                    <Header Text="DropDownCol">
                    </Header>
                </ig:BoundDataField>
                <ig:BoundDataField DataFieldName="TextCol" Key="TextCol">
                    <Header Text="TextCol">
                    </Header>
                </ig:BoundDataField>
            </Columns>
            <EditorProviders>
                <ig:DropDownProvider ID="DropDownProvider1">
                    <EditorControl runat="server" ID="WebDropDown1" 
										DisplayMode="DropDownList">
                    </EditorControl>
                </ig:DropDownProvider>
            </EditorProviders>
            <Behaviors>
                <ig:EditingCore>
                    <Behaviors>
                        <ig:CellEditing>
                            <ColumnSettings>
                                <ig:EditingColumnSetting ColumnKey="DropDownCol" 
													EditorID="DropDownProvider1" />
                            </ColumnSettings>
                        </ig:CellEditing>
                    </Behaviors>
                </ig:EditingCore>
            </Behaviors>
        </ig:WebDataGrid>
    private DataTable getGridData()
    {
        DataTable table = new DataTable();

        table.Columns.Add("ID", typeof(Int32));
        table.Columns.Add("DropDownCol", typeof(string));
        table.Columns.Add("TextCol", typeof(string));

        table.Rows.Add(new object[] { 0, "test2", "Kanagawa" });
        table.Rows.Add(new object[] { 1, "test3", "Tokyo" });
        table.Rows.Add(new object[] { 2, "test1", "Chiba" });
        table.Rows.Add(new object[] { 3, "test4", "Saitama" });

        table.PrimaryKey = new DataColumn[] { table.Columns["ID"] };

        return table;
    }

 

列は <Columns> 以下に「 ID 」、「 DropDownCol 」、「 TextCol 」の3列を定義しました。 DropDownCol をドロップダウンを表示させる列として使用します。ID はプライマリーキー列です。

エディタとしてドロップダウンを使用するため、 DropDownProvider を <EditorProviders> に追加しました。また、セル編集を有効にするため、 <Behaviors> に EditingCore.CellEditing を定義しました。 EditingColumnSetting 設定により、 DropDownCol 列に DropDownProvider が紐づけられています。

 

このままでは DropDownProvider のエディタコントロールである WebDropDown1 はまだ空の状態です。 ドロップダウンに WebDataGrid を表示させるための ItemTemplate を実装します。

コードビハインドにて ITemplate インターフェイスを実装したクラスの定義を行います。

 

private class MultiColumnTemplate : ITemplate
{
	public void InstantiateIn(Control container)
	{
		//WebDataGridを生成します
		WebDataGrid myGrid = new WebDataGrid();

		myGrid.ID = "TemplateGrid";
		myGrid.DataSource = GetDropDownData();
		myGrid.DataBind();
		myGrid.Width = new Unit("100%");

		//WebDataGridの選択機能を有効にします
		myGrid.Behaviors.CreateBehavior<Selection>();
		myGrid.Behaviors.Selection.CellClickAction = CellClickAction.Row;
		myGrid.Behaviors.Selection.RowSelectType = SelectType.Single;

		//RowSelectionChangedクライアントサイドイベントをフックアップします
		myGrid.Behaviors.Selection.SelectionClientEvents.RowSelectionChanged = "TemplateGrid_RowSelectionChanged";

		container.Controls.Add(myGrid);
	}

	private DataTable GetDropDownData()
	{
		DataSet ds = new DataSet();

		DataTable table = new DataTable();

		table.Columns.Add("col1", typeof(Int32));
		table.Columns.Add("col2", typeof(string));
		table.Columns.Add("col3", typeof(string));

		for (int i = 0; i < 5; i++)
		{
			table.Rows.Add(new object[] { i, "test" + i.ToString(), "TEST" });
		}

		table.PrimaryKey = new DataColumn[] { table.Columns["col1"] };

		ds.Tables.Add(table);

		return table;
	}
}

 

InstantiateIn() メソッドでテンプレートに使用する WebDataGrid を生成しています。ここではデータのバインドを行い、選択機能を有効にしておきます。行選択が行われた際に発生する RowSelectionChanged イベントがフックアップされていますが、内容は後ほど説明します。

 

次に、同じくコードビハインドにて DropDownProvider の設定を行います。

以下の記述をコードビハインドの Page_Load() に追加します。上で作成した MultiColumnTemplate クラスの割り当てもここで行います。

 

//ドロップダウンの幅を設定します
DropDownProvider1.EditorControl.DropDownContainerWidth = 400;

//DropDownItemを作成し、WebDropDownに追加します
DropDownItem ddItem = new DropDownItem();
DropDownProvider1.EditorControl.Items.Add(ddItem);

//WebDropDownのドロップダウンで使用するItemTemplate(WebDataGrid)を割り当てます
DropDownProvider1.EditorControl.ItemTemplate = new MultiColumnTemplate();

 

続いて、ドロップダウンの動作を補足するためのクライアントサイドイベントの実装を行います。先ほどのコードに以下を追加してクライアントサイドイベントのフックアップを行います。

 

//DropDownProviderのクライアントサイドイベントをフックアップします
DropDownProvider1.EditorControl.ClientEvents.ValueChanging = "DropDownProvider1_ValueChanging";
DropDownProvider1.EditorControl.ClientEvents.DropDownOpening = "DropDownProvider1_DropDownOpening";
DropDownProvider1.EditorControl.ClientEvents.DropDownOpened = "DropDownProvider1_DropDownOpened";

 

ここからはこれまでにフックアップしておいたクライアントサイドイベントを javascript で定義していきます。

まず、 ItemTemplate の WebDataGrid で選択行が変わった際に発生する RowSelectionChanged イベントです。ここでは、選択されたグリッド行からドロップダウンの選択値として表示したいセルの値を取得し、 WebDropDown1 の値として設定する処理を実装します。

 

function TemplateGrid_RowSelectionChanged(sender, e) {
	//WebDataGrid の選択された行コレクションを取得します
	var selectedRows = e.getSelectedRows();

	//選択された行コレクションから選択されている行を取得します
	var row = selectedRows.getItem(0);

	//行の 2 番目のセル オブジェクトを取得します
	var cell = row.get_cell(1);

	//セルのテキストを取得します
	var text = cell.get_text();

	//WebDropDownに選択された行の値を設定します
	ig_controls.WebDataGrid1_WebDropDown1.set_currentValue(text, true);
}

 

次に、 DropDownProvider1 の ValueChanging イベントではデフォルトのイベント処理をキャンセルするため、falseを返します。

 

    function DropDownProvider1_ValueChanging(sender, eventArgs) {
        //デフォルトのValueChangingイベントをキャンセルします
        eventArgs.set_cancel(true);
    }

 

DropDownProvider1 のドロップダウンが開く直前に発生する DropDownOpening イベントでは、現在選択されている WebDropDown1 の値を ItemTemplate 内の WebDataGrid の行データから探し、該当する行を選択状態にする処理を行います。

 

    function DropDownProvider1_DropDownOpening(sender, eventArgs) {
        var grid = ig_controls.WebDataGrid1_WebDropDown1_0_TemplateGrid;
        var curentValue = ig_controls.WebDataGrid1_WebDropDown1.get_currentValue();
        var selectedIndex = -1;
        //グリッドの行コレクションをループして選択行を探します
        for (var i = 0; i < grid.get_rows().get_length() ; i++)
        {
            if (grid.get_rows().get_row(i).get_cell(1).get_value() == curentValue)
            {
                selectedIndex = i;
                break;
            }
        }
        //現在の選択をクリアします
        grid.get_behaviors().get_selection().get_selectedRows().clear();
        if (selectedIndex != -1)
        {
            //グリッドの行を選択します
            grid.get_behaviors().get_selection().get_selectedRows().add(grid.get_rows().get_row(selectedIndex));
        }
    }

 

最後に、 ItemTemplate の WebDataGrid がクリックされたタイミングでドロップダウンが閉じるようにするため、ドロップダウンが開いた直後に発生する DropDownOpened イベントで WebDataGrid のエレメントに focus イベントを設定し、 colseDropDown() を実行します。ここでは jQuery を使用しています。

 

function DropDownProvider1_DropDownOpened(sender, eventArgs) {
        //グリッドの行が選択された(グリッドがフォーカスを受けた)タイミングでドロップダウンをクローズする(jQueryを使用)
        $("#WebDataGrid1_WebDropDown1_0_TemplateGrid")
        .focus(function () {
            sender.closeDropDown();
        });
    }

以上で複数列のドロップダウンは完成です。

 

今回のサンプルはこちらからダウンロードいただけます。
(本サンプルは16.1.20161.2044バージョンで作成されました) 

 

最後までお読みくださり、ありがとうございました。

Excelワークシートのコピー

今回も Infragistics Ignite UI の Excel ライブラリに関するご紹介です。

このライブラリをご利用いただきますと、既存の Excel ファイルのデータを javascript のインスタンスとして取り込み、プログラムからデータの変更を行って新たなワークブックを作成いただくことができます。

今回ご紹介するのは、ワークシートの内容を別のワークシートへコピーする方法です。

例えばテンプレートとなるワークシートがあって、それを複数のシートに複製してそれぞれに別のデータを書き込みたい場合などにご利用いただけるのではないかと思います。

ワークシートのクラスである ig.excel.Worksheet は様々な情報を保持しますが、基本的には必要なデータだけを選んで一つ一つコピー元のワークシートからコピー先のワークシートへコピーいただく作業になります。

ここでは、一般的によく使用される情報のみをピックアップしてコピーを行ってみたいと思います。

それでは、コピーのためのファンクションの定義を始めます。

 

function copyWorksheet(fromWorksheet, toWorksheet)
{

//ここにコピーを実装します

}

 

copyWorksheet ファンクションはコピー元( fromWorksheet )とコピー先( toWorksheet )の二つのig.excel.Worksheet インスタンスをとります。ファンクションの実行前は toWorksheet は空白であり、実行後は fromWorksheet と同じ内容になります。

ファンクション内のコードの実装を始めます。

コピー元のワークシートの行コレクションをループし、行の高さをコピーしてから行内のセルコレクションをループして列幅、関数、セル値、そしてセルのフォーマットをコピーします。

 

var rowsIter = fromWorksheet.rows().getEnumerator();
	while (rowsIter.moveNext()) {

		var row = rowsIter.current();

		//行の高さをコピーします
		toWorksheet.rows(row.index()).height(row.height());

		var cellsIter = row.cells().getEnumerator();
		while (cellsIter.moveNext()) {

			var cell = cellsIter.current();

		// 列の幅をコピーします
		toWorksheet.columns(cell.columnIndex()).width(fromWorksheet.columns(cell.columnIndex()).width());

		if (cell.formula() != null){
			// 関数をコピーします
			toWorksheet.rows(row.index()).cells(cell.columnIndex()).applyFormula(cell.formula().toString());
		}
		else{
			// セルの値をコピーします
			toWorksheet.rows(row.index()).cells(cell.columnIndex()).value(cell.value());
		}

		// セルのフォーマットをコピーします
		toWorksheet.rows(row.index()).cells(cell.columnIndex()).cellFormat().setFormatting(cell.cellFormat());
	}
}

 

続いてセルの結合情報をコピーします。結合セルには結合セルのフォーマットもありますので、そちらのコピーも行います。

 

//セルの結合情報をコピーします
var mcrIter = fromWorksheet.mergedCellsRegions().getEnumerator();
while (mcrIter.moveNext()) {
	var mcr = mcrIter.current();
	toWorksheet.mergedCellsRegions().add(mcr.firstRow(), mcr.firstColumn(), mcr.lastRow(), mcr.lastColumn());
	toWorksheet.mergedCellsRegions(toWorksheet.mergedCellsRegions().count() - 1).cellFormat().setFormatting(mcr.cellFormat());
}

 

以上により、ワークシートの行の高さ、列幅、セルの値、関数、フォーマットと結合情報はコピーされました。

ワークシートのその他の情報も同様の実装を行うことによりコピーいただけます。

copyWorksheet ファンクションのサンプルはこちらから。
(本サンプルは16.1バージョンで作成されました)

クライアントサイドで Excel ファイルを操作する

今回ご紹介する Infragistics Ignite UI の Excel ライブラリは、javascript を使用してクライアントサイドのみで Excel ファイルの作成や保存を行う機能を持っています。

簡単な Excel テンプレートの作成や保存、読み込みと編集の例を通して、ライブラリの実力をご覧ください。

 

それでは、まずは Excel を新規で作成してみましょう。

以下の一文は新しい workbook インスタンスを生成します。

 

//workbookインスタンスを2007(.xlsx)ファイル形式で生成する
var newWorkbook = new $.ig.excel.Workbook( $.ig.excel.WorkbookFormat.excel2007 );

この状態では newWorkbook は空のワークブックです。ワークシートを追加しましょう。

 

//新規ワークシートを追加する
var worksheet1 = newWorkbook.worksheets().add("NewSheet1");

空のワークシート "NewSheet1" が追加されました。

 

次に、このシートにテンプレートを作成します。

Microsoft Excel で開くとこのように表示されるテンプレートを作りたいと思います。

 

image

C、D、E列のセルには書式を設定し、数値が入力された場合は貨幣マークの入った金額の形式で表示されるようにします。また、合計セルにはA~D支店の合計値が表示されるよう、SUM 関数を設定します。

 

以下は上記テンプレートを作成するためのコードです。

 

//罫線を設定
for (var i = 1; i <= 6; i++ )
{
	for (var j = 1; j <= 4; j++)
	{
		worksheet1.rows(i).cells(j).cellFormat().rightBorderStyle($.ig.excel.CellBorderLineStyle.thin);
		worksheet1.rows(i).cells(j).cellFormat().bottomBorderStyle($.ig.excel.CellBorderLineStyle.thin);
	}
}
		
//セルに文字列を書き込む
worksheet1.getCell("C2").value("1月");
worksheet1.getCell("D2").value("2月");
worksheet1.getCell("E2").value("3月");
worksheet1.getCell("B3").value("A支店");
worksheet1.getCell("B4").value("B支店");
worksheet1.getCell("B5").value("C支店");
worksheet1.getCell("B6").value("D支店");
worksheet1.getCell("B7").value("合計");
		
//セルに背景色を設定する
var bgPink = $.ig.excel.CellFill.createSolidFill("#FF99CC");
var bgBlue = $.ig.excel.CellFill.createSolidFill("#CCFFFF");
worksheet1.getCell("C2").cellFormat().fill(bgPink);
worksheet1.getCell("D2").cellFormat().fill(bgPink);
worksheet1.getCell("E2").cellFormat().fill(bgPink);
worksheet1.getCell("B3").cellFormat().fill(bgBlue);
worksheet1.getCell("B4").cellFormat().fill(bgBlue);
worksheet1.getCell("B5").cellFormat().fill(bgBlue);
worksheet1.getCell("B6").cellFormat().fill(bgBlue);
		
//セルに関数を設定する
worksheet1.getCell("C7").applyFormula("=Sum(C3:C6)");
worksheet1.getCell("D7").applyFormula("=Sum(D3:D6)");
worksheet1.getCell("E7").applyFormula("=Sum(E3:E6)");
		
//C,D,E列に書式を設定する
worksheet1.columns(2).cellFormat().formatString("\"¥\"#,##0;[Red]\"¥\"\\-#,##0");
worksheet1.columns(3).cellFormat().formatString("\"¥\"#,##0;[Red]\"¥\"\\-#,##0");
worksheet1.columns(4).cellFormat().formatString("\"¥\"#,##0;[Red]\"¥\"\\-#,##0");
			
//数式の再計算を手動モードにする
newWorkbook.calculationMode($.ig.excel.CalculationMode.manual);	

 

これでテンプレートが完成しました。

 

次に、ig.excel.Workbook クラスの save() メソッドを使用してこの workbook インスタンスを Excel ファイルとして保存しましょう。保存のためのファンクションを以下のように定義しました。

 

	function saveWorkbook(workbookToSave, fileName)
	{
		workbookToSave.save({ type: 'blob' }, 
			function (data) {
				saveAs(data, fileName);
			},
			function (error) {
			}
		);
	}

第一引数の workbookToSave は workbook インスタンス、第二引数は保存時のデフォルトのファイル名です。

 

先ほどテンプレートを作成した newWorkbook を保存するには、以下を実行します。

 

//workbookインスタンスをExcelファイルに書き出す
saveWorkbook(newWorkbook, "template.xlsx");

 


ローカルマシンに Excel のテンプレートファイルを保存いただけたことと思います。

 

続きまして、今度は逆に Excel のファイルをプログラム上に取り込んでみます。これには、ig.excel.Workbook クラスの load() メソッドを使用します。

まず、ユーザーがファイルを選択できるよう、html に input タグ (type=”file”) を追加します。accept 属性には、Excel ファイルのみリストアップされるようにタイプの指定を行います。

 

<input type="file" id="input" accept="application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"/>

 

上記 input でファイルが選択された際に発生する change イベントを利用して Excel ファイルから workbook インスタンスを生成し、変数に保管します。

 

var myWorkbook;

$("#input").on("change", function () {
	var excelFile;
	var fileReader = new FileReader();
			
	if (this.files.length > 0) {
		excelFile = this.files[0];
		if (excelFile.type === "application/vnd.ms-excel" || 
			excelFile.type === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" || 
			(excelFile.type === "" && (excelFile.name.endsWith("xls") || excelFile.name.endsWith("xlsx")))) {
				fileReader.readAsArrayBuffer(excelFile);
		}
	}

	fileReader.onload = function (e) {
		var buffer = new Uint8Array(fileReader.result);
		//選択されたExcelファイルを読み込み、workbookインスタンスを生成する
		$.ig.excel.Workbook.load(buffer, 
			function (wb) {
				myWorkbook = wb;
			}, 
			function (error) {
			}
		);
	}
});

 

これでユーザーが選択した Excel ファイルを変数 myWorkbook に取り込むことができます。

試しに、初めに作成したテンプレートファイル template.xlsx を上記を使ってプログラムに取り込んでみてください。

 

今度は取り込んだ myWorkbook のテンプレートに実際にデータを書き込んでみます。

 

		var worksheet1 = myWorkbook.worksheets(0);
					
		//セルにデータを書き込む
		//A支店
		worksheet1.rows(2).cells(2).value(1234);
		worksheet1.rows(2).cells(3).value(2413);
		worksheet1.rows(2).cells(4).value(823);
		//B支店
		worksheet1.rows(3).cells(2).value(-314);
		worksheet1.rows(3).cells(3).value(14);
		worksheet1.rows(3).cells(4).value(-21);
		//C支店
		worksheet1.rows(4).cells(2).value(432);
		worksheet1.rows(4).cells(3).value(124);
		worksheet1.rows(4).cells(4).value(62);
		//D支店
		worksheet1.rows(5).cells(2).value(63251);
		worksheet1.rows(5).cells(3).value(43545);
		worksheet1.rows(5).cells(4).value(45266);

		//数式の再計算を行う
		myWorkbook.recalculate(true);	

 

データを書き込んだワークブックは先ほど定義した saveWorkbook() を使って新たな名前で保存することができます。

 

//workbookインスタンスをExcelファイルに書き出す
saveWorkbook(myWorkbook, "data1.xlsx");

 

このように保存されました。

 

image

テンプレート作成時に設定しておいたセルの書式、そして SUM 関数が機能していることをご確認ください。

 

今回はここにもう少しだけ編集を加えてみます。

追加されたデータを見ますと、こちらの企業ではB支店の業績が芳しくないようです。ig.excel.WorksheetRowCollectionのremove() メソッドを使用して、B支店の業績を削除してしまいましょう。さらに、同じく insert() メソッドを使用してタイトル行を追加してみます。

 

		var worksheet1 = myWorkbook.worksheets(0);
		
		//B支店行を削除					
		worksheet1.rows().remove(3);

		//タイトル行を追加				
		worksheet1.rows().insert(1);
		//セルを結合してタイトルを書き込む
		var mergedRegion1 =  worksheet1.mergedCellsRegions().add(1, 1, 1, 4);
		mergedRegion1.value("営業実績");
		worksheet1.rows(1).cells(1).cellFormat().alignment($.ig.excel.HorizontalCellAlignment.center);
		
		//数式の再計算を行う
		myWorkbook.recalculate(true);

 

saveWorkbook() で保存しますと、このような Excel が出来上がりました。

 

image

タイトル行が加わり、B支店が削除されました。合計欄は再計算されています。

 

Ignite UI の Excel ライブラリの使用例をご紹介しました。

 

今回のサンプルはこちらから。
(本サンプルは16.1バージョンで作成されました)

igDataChart に Canvas 要素を追加する

Ignite UI の igDataChart で時折見られるご要望に、図形やテキストなどの視覚要素を追加したいというものがあります。そこで、今回はチャートエリアにカスタムの HTML Canvas を追加する方法をご紹介します。

今回サンプルに使用するチャートは折れ線グラフです。シリーズの最大値と最小値となる地点に横線を引いてラベルを付けてみたいと思います。

目指すチャートはこちらです。

 

image

赤線の Max ラインと青線の Min ライン、およびそのラベルがカスタムで追加した Canvas 要素です。



それでは、コーディングです。

まず、 Canvas を追加するためのヘルパークラス「MyCanvas」を定義します。

コンストラクタはターゲットとする igDataChartのID、X軸とY軸をインプットとします。

function MyCanvas(chart, x, y) {
	this.attached = false;
	this.chartId = chart;
	this.xAxis = x;
	this.yAxis = y;
}


MyCanvas  クラスの attachCanvas() ファンクションは、 html に <canvas> タグを追加します。igDataChart は <canvas> のレイヤー構造になっていますので、ブランクの canvas を新たに追加する形です。

MyCanvas.prototype.attachCanvas = function (chartElement) {
	this.element = chartElement;
	var canvases = chartElement.find("canvas");
	this.renderCanvas = $("<canvas class='myCanvas' style='position: absolute; top: 0; left: 0;'></canvas>");
	if (canvases.length > 0) {
		this.overlay = $(canvases[canvases.length - 1]);
		this.overlay.before(this.renderCanvas);
		this.renderCanvas.attr("width", this.overlay.attr("width"));
		this.renderCanvas.attr("height", this.overlay.attr("height"));
		this.attached = true;
	}
};


続きまして、 draw() メソッドでは、先ほど追加した <canvas> から2Dコンテキストを取得し、図を描いていきます。まずは igDataChart のチャート領域でクリップします。実際の図の描画は最後のaddMinAndMaxLines() ファンクションで行います。

MyCanvas.prototype.draw = function () {

	if (!this.attached) {
		this.attachCanvas($("#" + this.chartId));
	}

	if (this.context == null) {
		this.context = this.renderCanvas[0].getContext("2d");
	}

	this.context.clearRect(0, 0, this.renderCanvas.attr("width"), this.renderCanvas.attr("height"));

	var viewport = this.element.igDataChart("option", "gridAreaRect");

	this.context.save();
	this.context.beginPath();
	this.context.moveTo(viewport.left, viewport.top);
	this.context.lineTo(viewport.left + viewport.width, viewport.top);
	this.context.lineTo(viewport.left + viewport.width, viewport.top + viewport.height);
	this.context.lineTo(viewport.left, viewport.top + viewport.height);
	this.context.lineTo(viewport.left, viewport.top);
	this.context.clip();

	this.addMinAndMaxLines(viewport);
};


そして、次が addMinAndMaxLines() の中身です。

MyCanvas.prototype.addMinAndMaxLines = function (viewport) {
	//y=925の位置にMaxライン、y=100の位置にMinラインを表示させる
	var maxYValue = 925;
	var minYValue = 100;
	var maxPos = this.element.igDataChart("scaleValue", this.yAxis, maxYValue);
	var minPos = this.element.igDataChart("scaleValue", this.yAxis, minYValue);

	//Max値のlineとtextを描画する
	this.context.strokeStyle = "red";
	this.context.fillStyle = "red";
	this.context.lineWidth = 1.0;
	this.context.beginPath();
	this.context.moveTo(viewport.left, maxPos);
	this.context.lineTo(viewport.left + viewport.width, maxPos);
	this.context.stroke();
	this.context.textBaseline = "bottom";
	this.context.fillText("Max:" + maxYValue, viewport.left, maxPos);

	//Min値のlineとtextを描画する
	this.context.strokeStyle = "blue";
	this.context.fillStyle = "blue";
	this.context.beginPath();
	this.context.moveTo(viewport.left, minPos);
	this.context.lineTo(viewport.left + viewport.width, minPos);
	this.context.stroke();
	this.context.textBaseline = "bottom";
	this.context.fillText("Min:" + minYValue, viewport.left, minPos);

	this.context.restore();
};

 


ヘルパークラスの定義は以上です。

後は、クラスをインスタンス化し、 igDataChartのrefreshCompleted() イベントで draw() メソッドを実行するだけです。 refreshCompleted() イベントを使用するのは 、igDataChart がズームされた際にそのズームレベルによって Canvas 要素を書き換える必要があるからです。

では、 igDataChart の定義です。

//チャートデータ
var data = [
	{ "Country": "Canada", "Coal": 400, "Oil": 100, "Gas": 175, "Nuclear": 225 },
	{ "Country": "China", "Coal": 925, "Oil": 200, "Gas": 350, "Nuclear": 400 },
	{ "Country": "Russia", "Coal": 550, "Oil": 100, "Gas": 250, "Nuclear": 475 },
	{ "Country": "Australia", "Coal": 450, "Oil": 100, "Gas": 150, "Nuclear": 175 },
	{ "Country": "United States", "Coal": 800, "Oil": 250, "Gas": 475, "Nuclear": 575 },
	{ "Country": "France", "Coal": 375, "Oil": 150, "Gas": 350, "Nuclear": 275 }
];

//チャートの定義
$("#chart").igDataChart({
	width: "100%",
	height: "400px",
	dataSource: data,
	verticalZoomable: true,
	horizontalZoomable: true,
	axes: [
	{
		name: "xAxis",
		type: "categoryX",
		label: "Country"
	},
	{
		name: "yAxis",
		type: "numericY",
		minimumValue: 0,
		maximumValue: 1000
	}
	],
	series: [
		{
			name: "Coal",
			type: "line",
			xAxis: "xAxis",
			yAxis: "yAxis",
			valueMemberPath: "Coal"
		},
		{
			name: "Oil",
			type: "line",
			xAxis: "xAxis",
			yAxis: "yAxis",
			valueMemberPath: "Oil"
		},
		{
			name: "Gas",
			type: "line",
			xAxis: "xAxis",
			yAxis: "yAxis",
			valueMemberPath: "Gas"
		}
	],
	refreshCompleted: function (e, ui) {
		myCanvas.draw();
	}
});


上記の igDataChart で使用するためには、 MyCanvas は次のようにインスタンス化します。

 

var myCanvas = new MyCanvas("chart", "xAxis", "yAxis");


必要な実装は以上です。


今回の MyCanvas  クラスのファンクションを応用すれば、チャートのX軸やY軸の位置を指定して様々な線や図形を描くことができ、また注釈のようなテキストも表示することが可能です。

例えば、特定のデータポイントを強調してみたり、

image

 

特定の領域に背景色をつけたりすることができます。

image

 

チャートに自由に視覚要素を追加してみてください。

 

サンプルのダウンロードはこちらから。
(htmlファイル: 本サンプルは16.1バージョンで作成されました)

igGridExcelExporterのエクスポートをカスタマイズする

Infragistics Ignite UI では、v15.2よりクライアントサイド API を使用してグリッドコントロールを Excel ファイルへ自動でエクスポートする igGridExcelExporter が正式にサポートされております。最新バージョンであるV16.1現在、igGridExcelExporter にてエクスポートが可能なコントロールは igGrid、 igHierarchicalGrid、 igTreeGrid で、それらのフィルター、非表示、ページング、並べ替え、集計、列固定、および仮想化の各機能がサポートされています。

エクスポートの方法はとても簡単です。必要なスクリプトファイルを読み込み、グリッドコントロールを定義したら以下の一行を実行するだけです。

$.ig.GridExcelExporter.exportGrid($("#グリッドのID"));

今回は上記の自動のエクスポート機能に加えて、セルの色付けやフォーマットの設定など、比較的ご要望の多いカスタマイズを行う方法をご紹介します。

 

まず、エクスポートを行うigGridを定義します。
今回は northwind のデータを使用して「EmployeeID」、「FirstName」、「LastName」の3列のみの簡単なグリッドを作成します。 Features のセクションでは Sorting(並べ替え)の機能のみ有効にしました。

 

$("#igGrid1").igGrid(
{
	autoGenerateColumns:false,
	width:"600px",
	primaryKey: "EmployeeID",
	columns: [
		{ key: "EmployeeID", headerText: "EmployeeID", dataType: "number", width: "200px" },
		{ key: "FirstName", headerText: "FirstName", dataType: "string", width: "200px" },
		{ key: "LastName", headerText: "LastName", dataType: "string", width: "200px" }
	],
	dataSource: northwind.results,
	features:[
		{
			name: "Sorting",
			type: "local"
		}
	]
});

 

Html の body には上記 igGrid コントロールのプレースホルダとなる table 要素を追加しておきます。

 

<table id="igGrid1"></table>

 

グリッド “igGrid1” は以下のような見た目になっています。

 

image

 

次に、 html 上にエクスポートを実行するためのボタンを用意します。

 

<input type="button" id="exportIgGrid" value="igGrid Excel Export" />

 

上記ボタンの click イベントをハンドルし、 igGridExcelExporter の exportGrid() メソッドを使用して “igGrid1” をエクスポートする処理を追加します。エクスポートされるファイル名( filename )とワークシート名( worksheetName )の指定も合わせて行っています。

 

$("#exportIgGrid").click(function () {
	$.ig.GridExcelExporter.exportGrid(
		$("#igGrid1"), 
		{
			fileName: "igGrid",
			worksheetName: "Sheet1"
		}
	);
});

 

ボタンをクリックすると、このような Excel が生成されました。

 

image

 

 

それでは、ここで少しカスタマイズを加えてセルにスタイルを設定してみたいと思います。

igGridExcelExporter ではエクスポート時に発生するコールバックを利用して Excel にカスタマイズを加えることが可能です。今回は、ヘッダーセルのエクスポートが終了したときのコールバック headerCellExported を使用してセルに背景色を、またセルのエクスポートが終了したときに発生する cellExported でセルの文字の色とイタリック体の設定を追加してみたいと思います。

コールバックは以下のように設定します。

 

$.ig.GridExcelExporter.exportGrid(
	$("#igGrid1"), 
	{
		fileName: "igGrid",
		worksheetName: "Sheet1"
	},
	{
		headerCellExported: function(sender, args) {
			//「FirstName」列のヘッダのみ背景色をredにする。
			if (args.columnKey == "FirstName") {
				args.xlRow.getCellFormat(args.columnIndex).fill($.ig.excel.CellFill.createSolidFill("red"));
			}
		},
		cellExported: function(sender, args) {
			//「FirstName」列のセルのみ文字色をblueに、文字をイタリック体にする。
			if (args.columnKey == "FirstName" && args.rowId != null) {
				args.xlRow.getCellFormat(args.columnIndex).font().colorInfo(new $.ig.excel.WorkbookColorInfo("blue"));
				args.xlRow.getCellFormat(args.columnIndex).font().italic(true);
			}
		}
	}
);

 

エクスポートを実行すると、 Excel はこのように変化しました。
「FirstName」列のみ、ヘッダーセルの背景色とセルの文字色が変わり、文字がイタリック体になっています。

 

image

 

 

さて、次は Ignite UI の階層構造を持つグリッドである igHierarchicalGrid をエクスポートしてみたいと思います。先ほどと同じく、 northwind のデータを使用して以下のようにグリッドの定義を行いました。

 

$("#hierarchicalGrid").igHierarchicalGrid({
	width: "800px",
	autoGenerateColumns: false,
	dataSource: northwind,
	responseDataKey: "results",
	dataSourceType: "json",
	columns: [
		{ key: "EmployeeID", headerText: "EmployeeID", dataType: "number", width: "250px" },
		{ key: "FirstName", headerText: "FirstName", dataType: "string", width: "250px" },
		{ key: "LastName", headerText: "LastName", dataType: "string", width: "250px" }
	],
	autoGenerateLayouts: false,
	columnLayouts: [
		{
			key: "Orders",
			responseDataKey: "results",
			width: "1000px",
			autoGenerateColumns: false,
			primaryKey: "OrderID",
			columns: [
				{ key: "OrderID", headerText: "OrderID", dataType: "number", width: "150px" },
				{ key: "CustomerID", headerText: "CustomerID", dataType: "string", width: "150px"},
				{ key: "ShipName", headerText: "ShipName", dataType: "string", width: "150px" },
				{ key: "ShipCountry", headerText: "ShipCountry", dataType: "string", width: "150px" },
				{ key: "Freight", headerText: "Freight", dataType: "number", width: "150px" }
			]
		}
	]
});

 

Html:

<table id="hierarchicalGrid"></table>

 

グリッドは子階層を展開すると次のような見た目になっています。

 

image

 

このグリッドを、先ほどと同じようにエクスポートしてみると、次のようになります。
igHierarchicalGrid の階層データは Excel 側ではアウトライン(データ行の左に展開ボタンが表示されています)を使って表現されています。

 

image

 

さて、「Freight」列のセルの左端に緑色の三角が表示されていますが、これはデータの内容が数値であるのに、文字列タイプとして保存されているためです。このようにエクスポートされてしまったのは、 igHierarchicalGrid の列定義では「Freight」は number タイプとして定義されていますが、バインドされたデータソースのデータタイプが string タイプであるためです。

これを数値タイプに変換してエクスポートしたいと思います。これには、先ほども使用したcellExported コールバックを使用します。数値への変換のついでに、フォーマットも変更してコンマ付きの小数点第二位までの固定表示にしてしまいましょう。

 

$("#exportIgHierarchicalGrid").click(function () {
	$.ig.GridExcelExporter.exportGrid(
		$("#hierarchicalGrid"), 
		{
			fileName: "igHierarchicalGrid",
			worksheetName: "Sheet1"
		},
		{
			cellExported: function(sender, args) {
				//「Freight」列のカスタマイズ
				if (args.columnKey == 'Freight') {
					//文字列データを数値データに変換する。
					args.xlRow.cells(args.columnIndex).value(parseFloat(args.cellValue));
					//コンマ付き小数点以下第二位表示のフォーマットとする。
					args.xlRow.getCellFormat(args.columnIndex).formatString("#,##0.00_ ");
				}
			}
		}
	);
});

 

「Freight」列が数値表示となりました。

 

image

 

最後に、 igHierarchicalGrid をテーブル設定のないデータとしてエクスポートする方法をご紹介します。

IgGridExcelExporter はデフォルトでグリッドコントロールを Excel のテーブルとしてエクスポートします。これまでご覧いただいた Excel データはすべて、ヘッダー部分にソート用のボタンが表示された、いわゆるテーブル形式となっていました。このため、Excel のテーブルの仕様によってエクスポートされた igHierarchicalGrid には自動的にデータには存在しないヘッダーが生成されてしまいました。(一行目の「Column1」および「Column2」です。)

そこで、これまでのようにコールバックを利用し、テーブルの設定を解除して追加されてしまったヘッダーを削除するカスタマイズを加えてみます。

具体的な方法ですが、エクスポートが終了する際に発生する exportEnding コールバックにてワークシート上のテーブル設定の削除、および自動で追加されてしまった「Column1」および「Column2」セルのテキストとフォーマットをクリアし、一行目に設定されている固定行の解除を行います。今回のサンプルコードでは、コールバックの定義は以下のようになります。

 

$.ig.GridExcelExporter.exportGrid(
.....
		exportEnding: function(sender, args) {
			//Excelのtableを削除する。
			args.worksheet.tables().removeAt(0, false);
	
			//ヘッダーのテキストとフォーマットを変更する。
			args.worksheet.getCell("D1").value("");
			args.worksheet.getCell("E1").value("");
			var blankFormat = args.worksheet.workbook().createNewWorksheetCellFormat();
			args.worksheet.getCell("D1").cellFormat().setFormatting(blankFormat);
			args.worksheet.getCell("E1").cellFormat().setFormatting(blankFormat);

			//固定行を解除する。
			args.worksheet.displayOptions().frozenPaneSettings().frozenRows(null);
		}
.....
);

 

テーブルが解除され、このような見た目になりました。

 

image

 

今回は igGridExcelExporter のコールバックを使用した様々なカスタマイズをご紹介しました。

実行可能なサンプル( html ファイルです)はこちらから。
(本サンプルは16.1バージョンで作成されました)

最後までお読み下さり、ありがとうございました。

WebDataGrid でカスケードのドロップダウンを作成する

 

ドロップダウンのリストの内容を別のドロップダウンの選択値によって変更させたい場合があります。例えば、国と州を選択するドロップダウンでは、選んだ国によって選択できる州のリストは変更したいものです。

そのようなドロップダウンを WebDataGrid の列で実現する方法をご紹介します。

下の図は完成後の WebDataGrid です。国の情報を持つ CountryCol 列のセルの選択値によって、州の情報を持つ StateCol 列のリストの中身は動的に変化します。

clip_image001

 

グリッドを作成していきます。

今回の例ではグリッドと列は以下のように定義しました。

<ig:WebDataGrid ID="WebDataGrid1" runat="server" Height="350px" Width="400px" DataKeyFields="ID" AutoGenerateColumns="False">
	<Columns>
		<ig:BoundDataField DataFieldName="ID" Key="ID">
			<Header Text="ID">
			</Header>
		</ig:BoundDataField>
		<ig:BoundDataField DataFieldName="CountryCol" Key="CountryCol">
			<Header Text="CountryCol">
			</Header>
		</ig:BoundDataField>
		<ig:BoundDataField DataFieldName="StateCol" Key="StateCol">
			<Header Text="StateCol">
			</Header>
		</ig:BoundDataField>
	</Columns>
</ig:WebDataGrid>

(プライマリーキーとなる ID 列が DataKeyFields に指定してあります。 DataKeyFields プロパティの設定は WebDataGridで編集機能をご利用いただく際に必須となります。)

 

そして、 CountryCol 列および StateCol 列でドロップダウンを表示するため、それぞれの列で使用する DropDownProvider を定義します。以下のコードを先ほどの aspx コードの<Columns>定義の後に追加します。

<EditorProviders>
	<ig:DropDownProvider ID="ddp1">
		<EditorControl ID="WebDropDown1" runat="server">
			<DropDownItemBinding TextField="Country" ValueField="Country"></DropDownItemBinding>
		</EditorControl>
	</ig:DropDownProvider>
	<ig:DropDownProvider ID="ddp2">
		<EditorControl ID="WebDropDown2" runat="server" OnItemsRequested="WebDropDown2_ItemsRequested" >
			<DropDownItemBinding TextField="State" ValueField="State"></DropDownItemBinding>
		</EditorControl>
	</ig:DropDownProvider>
</EditorProviders>

StateCol 列で使用することになる DropDownProvider のエディタコントロール(ID=”WebDropDown2”)にのみ OnItemsRequested サーバーサイドイベントをハンドリングしていますが、実装内容は後述します。また、エディタの DropDownItemBinding には TextField および ValueField にデータソースのプロパティ(カスケードする側の列では同一にしてください)を指定します。

 

続いて WebDataGrid の編集機能を有効にし、また CountryCol 列と StateCol 列にDropDownProvider を紐づける設定を行います。以下のコードを上記 <EditorProviders> の後に追加してください。

<Behaviors>
	<ig:EditingCore>
		<Behaviors>
			<ig:CellEditing>
				<CellEditingClientEvents EnteredEditMode="Wdg_EnteredEditMode" />
					<ColumnSettings>
						<ig:EditingColumnSetting ColumnKey="CountryCol" EditorID="ddp1" />
						<ig:EditingColumnSetting ColumnKey="StateCol" EditorID="ddp2" />
					</ColumnSettings>
			</ig:CellEditing>
		</Behaviors>
	</ig:EditingCore>
</Behaviors>

ここではセルが編集モードに入った時に発生する EnteredEditMode クライアントサイドイベントをハンドリングします。これは、 StateCol 列が編集モードを開始するタイミングでサーバーサイドに処理を送り、動的にリストの割り当てを行うためです。以下はイベントの実装内容です。

function Wdg_EnteredEditMode(sender, eventArgs) {
	if (eventArgs.getCell().get_column().get_key() == "StateCol") {
		var prevCellValue = eventArgs.getCell().get_row().get_cell(1).get_value();
		var editor = eventArgs.getEditor();
		editor.loadItems(prevCellValue);
	}
}


ターゲットのセルが StateCol 列である場合に、セルのドロップダウンエディタにアクセスして loadItems() メソッドを実行します。このメソッドには引数として隣りの CountryCol 列のセルで現在選択されている値を送ります。

 

さらに、 loadItems() メソッドによって呼び出されるサーバーサイドの OnItemsRequestedイベントを定義します。前述の StateCol 列で使用する DropDownProvider 内でWebDropDown2_ItemsRequested の名前でフックアップしておいたイベントです。このイベントで必要なのは、引数に送られた CountryCol 列のセルの値によって異なるリストを自身のDataSource に再バインドする処理です。

protected void WebDropDown2_ItemsRequested(object sender, Infragistics.Web.UI.ListControls.DropDownItemsRequestedEventArgs e)
{
	//e.ValueはCountryColセルの現在の選択値です。この値によってStateCol列のドロップダウンに表示したいリストを用意します。
	//リストをDataSourceに割り当て、DataBind()を実行します。

	WebDropDown dd = sender as WebDropDown;
	dd.Items.Clear();
	dd.DataSource = 用意したリスト;
	dd.DataBind();
}

必要な処理は以上です。

 

以下は今回のサンプルコードの全体像です。

aspx-------------------------------------------------------------------------------------------

<ig:WebDataGrid ID="WebDataGrid1" runat="server" Height="350px" Width="400px" DataKeyFields="ID" AutoGenerateColumns="False">
	<Columns>
		<ig:BoundDataField DataFieldName="ID" Key="ID">
			<Header Text="ID">
			</Header>
		</ig:BoundDataField>
		<ig:BoundDataField DataFieldName="CountryCol" Key="CountryCol">
			<Header Text="CountryCol">
			</Header>
		</ig:BoundDataField>
		<ig:BoundDataField DataFieldName="StateCol" Key="StateCol">
			<Header Text="StateCol">
			</Header>
		</ig:BoundDataField>
	</Columns>
	<EditorProviders>
		<ig:DropDownProvider ID="ddp1">
			<EditorControl ID="WebDropDown1" runat="server">
				<DropDownItemBinding TextField="Country" ValueField="Country"></DropDownItemBinding>
			</EditorControl>
		</ig:DropDownProvider>
		<ig:DropDownProvider ID="ddp2">
			<EditorControl ID="WebDropDown2" runat="server" OnItemsRequested="WebDropDown2_ItemsRequested" >
				<DropDownItemBinding TextField="State" ValueField="State"></DropDownItemBinding>
			</EditorControl>
		</ig:DropDownProvider>
	</EditorProviders>
	<Behaviors>
		<ig:EditingCore>
			<Behaviors>
				<ig:CellEditing>
					<CellEditingClientEvents EnteredEditMode="Wdg_EnteredEditMode" />
						<ColumnSettings>
							<ig:EditingColumnSetting ColumnKey="CountryCol" EditorID="ddp1" />
							<ig:EditingColumnSetting ColumnKey="StateCol" EditorID="ddp2" />
						</ColumnSettings>
				</ig:CellEditing>
			</Behaviors>
		</ig:EditingCore>
	</Behaviors>
</ig:WebDataGrid>

……………

<script type="text/javascript">

function Wdg_EnteredEditMode(sender, eventArgs) {
	if (eventArgs.getCell().get_column().get_key() == "StateCol") {
		var prevCellValue = eventArgs.getCell().get_row().get_cell(1).get_value();
		var editor = eventArgs.getEditor();
		editor.loadItems(prevCellValue);
	}
}

</script>

------------------------------------------------------------------------------------------------

C#---------------------------------------------------------------------------------------------

//CountryColのドロップダウンに使用するDataTable
public DataTable CountryTable { 
	get {
		System.Data.DataTable table = new DataTable();

		table.Columns.Add("CountryID", typeof(Int32));
		table.Columns.Add("Country", typeof(string));

		table.Rows.Add(new object[] { 1, "US" });
		table.Rows.Add(new object[] { 2, "Canada" });

		return table;
	}
}

//StateColのドロップダウンに使用するDataTable
public DataTable StateTable { 
	get {
		System.Data.DataTable table = new DataTable();

		table.Columns.Add("StateId", typeof(Int32));
		table.Columns.Add("Country", typeof(string));
		table.Columns.Add("State", typeof(string));

		table.Rows.Add(new object[] { 0, "US", "Arizona" });
		table.Rows.Add(new object[] { 1, "US", "California" });
		table.Rows.Add(new object[] { 2, "US", "Georgia" });
		table.Rows.Add(new object[] { 3, "Canada", "Ontario" });
		table.Rows.Add(new object[] { 4, "Canada", "Yukon" });
		table.Rows.Add(new object[] { 5, "Canada", "Quebec" });

		return table;
	}
}

protected void Page_Load(object sender, EventArgs e)
{
	if (Session["gridData"] == null)
	{
		Session["gridData"] = getGridData();
		ddp1.EditorControl.DataSource = CountryTable;
	}

	this.WebDataGrid1.DataSource = Session["gridData"];
}

protected void WebDropDown2_ItemsRequested(object sender, Infragistics.Web.UI.ListControls.DropDownItemsRequestedEventArgs e)
{
	IEnumerable<DataRow> dataRows;

	if (e.Value.ToString() == "US")
	{
		dataRows = StateTable.AsEnumerable().Where(dr => dr.Field<string>("Country") == "US");
	}
	else
	{
		dataRows = StateTable.AsEnumerable().Where(dr => dr.Field<string>("Country") == "Canada");
	}

	WebDropDown dd = sender as WebDropDown;
	dd.Items.Clear();
	dd.DataSource = dataRows.CopyToDataTable();
	dd.DataBind();
}

//WebDataGridのデータソースに使用するDataTable
private DataTable getGridData()
{
	DataTable table = new DataTable();

	table.Columns.Add("ID", typeof(Int32));
	table.Columns.Add("CountryCol", typeof(string));
	table.Columns.Add("StateCol", typeof(string));

	table.Rows.Add(new object[] { 0, "US", "Georgia" });
	table.Rows.Add(new object[] { 1, "Canada", "Ontario" });
	table.Rows.Add(new object[] { 2, "Canada", "Yukon" });
	table.Rows.Add(new object[] { 3, "US", "California" });

	table.PrimaryKey = new DataColumn[] { table.Columns["ID"] };
	
	return table;
}

------------------------------------------------------------------------------------------------

 

サンプルのダウンロードはこちらから。
(本サンプルは16.1.20161.2044バージョンで作成されました)

サテライトアセンブリを作成して WebDataGrid をローカライズする

WebDataGrid は日本語環境では日本語リソースファイル(*.resx)から文字列を読み取ってコントロールで使用される定型句を表示させます。例えば、下記の赤枠で表示されるフィルタ項目の表示文字列はリソースファイルに組み込まれています。

clip_image001

これらのリソース文字列は、プログラムから他言語等に置き換えることができません。

以下では、 このフィルタ項目を例にとって、 WebDataGrid を韓国語 (ko-KR カルチャ) にローカライズする方法をご紹介します。

今回使用する Infragistics のバージョンは ASP.NET2013 Vol2(2028) CLR.45 になります。その他のバージョンを御利用の場合は、手順中のバージョン表記部分を正しいバージョン番号に置き換えてください。

1. まず、 ”Localization” の名前で新規フォルダを作成します。(必須ではありませんが、すべてを一つのフォルダにまとめた方が後の作業が簡単です。)

2. Infragistics 製品のソースコードに含まれる、 WebDataGridStrings_runtime.resx ファイルを1で作成した Localization フォルダにコピーします。

ソースコードは Infragistics ウェブサイトの”キーとダウンロード”のページからダウンロードいただけます。

clip_image003

WebDataGridStrings_runtime.resx は、上記からダウンロードされる zip フォルダ内の Infragistics_ASPNET_20132_CLR45_Source.zip を解凍した中にございます。

(例:NetAdvantage_ASPNET_20132_CLR45_Source\Infragistics.Web.UI\Resources\WebDataGridStrings_runtime.resx)

3. Infragistics のインストールフォルダから、アセンブリファイル Infragistics45.Web.v13.2.dll を Localization フォルダにコピーします。

(例: C:\Program Files (x86)\Infragistics\2013.2\ASP.NET\CLR4.5\Bin\Infragistics45.Web.v13.2.dll)

4. Localization フォルダに移動します。

5. WebDataGridStrings_runtime.resx をコピーし、コピーしたファイルにWebDataGridStrings_runtime.ko-KR.resx と名前を付けます。

6. Visual Studio で WebDataGridStrings_runtime.ko-KR.resx を開き、文字列を訳します。フィルタドロップダウンの項目をローカライズする場合は “LS_FilterRule_” で始まる項目 、 例えば “LS_FilterRule_After”, “LS_FilterRule_Before”, “LS_FilterRule_Equlas” などになります。

clip_image005

7. Visual Studio のコマンドプロンプトを起動します。
clip_image006

8. コマンドプロンプトLocalization フォルダに移動します。

例:cd C:\Documents and Settings\Localization

9. 下記のコマンドを入力します。

sn -e Infragistics45.Web.v13.2.dll StrongName.key

上記のコマンドは Infragistics45.Web.v13.2.dll アセンブリが署名されたときに使用されたパブリックキーファイル (StrongName.key) をLocalization フォルダに抽出します。このファイルはステップ11で作成するサテライトアセンブリを署名するために使用します。

10. 下記コマンドを実行します。

Resgen WebDataGridStrings_runtime.ko-KR.resx

このコマンドは Localization フォルダにWebDataGridStrings_runtime.ko-KR.resources ファイルを生成します。

11. 下記コマンドを実行します。

Al.exe /t:lib /embed:WebDataGridStrings_runtime.ko-KR.resources,Infragistics.Web.UI.Resources.WebDataGridStrings_runtime.ko-KR.resources /culture:ko-KR /out:Infragistics45.Web.v13.2.resources.dll /template:Infragistics45.Web.v13.2.dll /keyf:StrongName.key /delay+

このコマンドは Localization フォルダにInfragistics45.Web.v13.2.resources.dll ファイル(サテライトアセンブリ)を生成します。

12. 下記コマンドを実行します。

sn -Vr Infragistics45.Web.v13.2.resources.dll

このコマンドは Infragistics45.Web.v13.2.resources.dll アセンブリを完全には署名せずに GAC にインストールさせます。

13. 下記コマンドを実行します。

gacutil -i Infragistics45.Web.v13.2.resources.dll

このコマンドはサテライトアセンブリを GAC にインストールします。

14. 通常の手順で WebDataGrid を使用するウェブサイトを作成します。(WebDataGridのフィルタ機能を有効にしておきます。)

ウェブサイトに下記変更を加え、ブラウザの現在のカルチャを使用するようにします。

(a) グローバリゼーションが正常に動作するようにするためには、 Page ディレクティブは UICulture 属性と Culture 属性が Auto に設定されている必要があります。

<%@ Page Language="C#" AutoEventWireup="true" UICulture="Auto" Culture="Auto" CodeFile="Default.aspx.cs" Inherits="_Default" %>

(b) ScriptManager の EnableScriptGlobalization 属性は true です。

<asp:ScriptManager EnableScriptGlobalization="true" ID="ScriptManager1" runat="server"/>

テスト方法について

以下では、ブラウザの使用言語を韓国語に変更して、上記で作成したウェブサイトのテストを行います。

1.インターネットエクスプローラの”インターネットオプション”を起動します。

clip_image008

2.”全般”タブの”言語”をクリックします。

clip_image009

3.言語リストに韓国語を追加し、優先順位を一番上にします。

clip_image010

4.ウェブサイトを実行し、WebDataGridのフィルタ項目が韓国語で表示されていることを確認します。

clip_image011

完成です。

今回は韓国語へのローカライズを行いましたが、同じ手順はその他の言語に対しても有効です。

UltraWebGrid から WebDataGridへの移行に関して


UltraWebGridは、NetAdvantage for ASP.NET 2011 Volume1のリリースを持ちまして廃止となりました。2011 Volume2以降のバージョンでは製品にアセンブリが含まれないため、ご利用いただくことができません。

2011 Volume2以降はUltraWebGridの後継コントロールとなるWebDataGridまたはWebHierarchicalDataGridをご利用いただけます。

UltraWebGrid では単一階層、複数階層ともに表現することのできるグリッドコントロールですが、WebDataGrid では単一階層のみ表示が可能です。複数階層を表示するシナリオでは WebHierarchicalDataGridをご利用いただきます。

オンラインサンプルページ:WebDataGrid
http://samples.jp.infragistics.com/aspnet/ComponentOverview.aspx?cn=data-grid

オンラインヘルプ:WebDataGrid
http://help.jp.infragistics.com/NetAdvantage/ASPNET/2013.1/CLR4.0/default.aspx?page=Web_WebDataGrid_WebDataGrid.html

オンラインサンプルページ:WebHierarchicalDataGrid
http://samples.jp.infragistics.com/aspnet/ComponentOverview.aspx?cn=hierarchical-data-grid

オンラインヘルプ:WebHierarchicalDataGrid
http://help.jp.infragistics.com/NetAdvantage/ASPNET/2013.1/CLR4.0/default.aspx?page=Web_WebHierarchicalDataGrid.html

UltraWebGridからWebDataGrid(WebHierarchicalDataGrid)への置き換えですが、両者は異なる内部構造を持っており、自動で変換を行うようなツールはございません。移行の際には再開発が必要となります。

下記は弊社にてUltraWebGrid から WebDataGrid コントロールへの移行されるお客様向けに用意致しております資料になります。スムーズな移行作業の手助けとなれば幸いでございます。

UltraWebGrid vs WebDataGrid/WebHierarchicalDataGrid 機能比較 (2011 Volume2)
http://blogs.jp.infragistics.com/blogs/dikehara/archive/2011/11/25/ultrawebgrid-vs-webdatagrid-webhierachicaldatagrid-2011-volume2.aspx

上記はUltraWebGridとWebDataGrid(WebHierarchicalDataGrid)の機能対応表となります。表中のセル結合機能が CTP と表示されておりますが、現在正式な機能として提供を行なっております。

また、下記はWebDataGridとWebHierachicalDataGridの機能を説明した資料となります。

NetAdvantage for ASP.NET グリッド機能チート シート:
http://users.infragistics.com/jpds/InfragisticsNAforASPNETGridCheatSheet-11.1.pdf

Gridの列を複数段表示にする

通常のグリッドは、列が横一列に並んだレイアウトになります。これをカスタム化し、多段の表示にするにはどのようにすればよいでしょうか。UltraGridを使うと、複雑なコードを記述しなくてもデザイナから簡単に実現することができます。

 

例えば従業員の名簿データをグリッドに表示したいとします。通常のレイアウトではこのようになります。名前や住所が一列に並んでいます。

 

 

 

まず、UltraGridのデザイナを使って、列を種類別にグループ分けします。例えばFirstNameLastNameTitleは個人情報のグループ、住所関連の列は住所情報のグループといった具合です。これらのグループ名も、列ヘッダに含めることができます。

 

 

 

列をグループに分けました。グループヘッダ(NewGroup0NewGroup1)が追加されました。

 

 

 

次に、列ヘッダをドラッグ・ドロップで好きな位置に置き換えます。

 

 

 

デザイナで複数段列のレイアウトが完成しました。

アプリケーションを実行してみます。

 

 

 

 

 

 

 NetAdvantage for Windows Forms トライアル版のダウンロードはこちらからどうぞ。

 

 

 

 

  

 

 

【参考】

行レイアウト デザイナの使用

http://help.jp.infragistics.com/NetAdvantage/Win/2011.2/CLR2.0/default.aspx?page=WinGrid_Using_the_Row_Layouts_Designer.html

 

デザイナを使用して行レイアウト モードで列をグループ化

http://help.jp.infragistics.com/NetAdvantage/Win/2011.2/CLR2.0/default.aspx?page=WinGrid_Grouping_Columns_in_Row_Layout_Mode_using_the_Designer.html