5/30/2010

SilverlightにおけるCustom Template Controlの作り方について

どうもJudaです。
今回はSilverlightにおけるカスタムテンプレートコントロールの説明です。
コントロールのカスタムテンプレートとユーザーコントロール継承の違いですが、私見では、
  1. カスタムテンプレートは、再利用可能なユーザーコントロールの開発
  2. ユーザーコントロール継承は、再利用を含めないユーザーコントロールの開発
であり、後者のユーザーコントロール継承は、特定の部位に別のコントロールを埋め込んだりと言うことを基本的に考えていない場合だと思います。もちろん様々な方法が考えられますが、構造を変えたりはできないので、基本的には作成した際の構造を逸脱することは出来ず、またユーザーコントロールの構造を残したままの改造なので、DependencyPropertyの数が増えすぎる傾向にあります。
今回はCustomTemplateControlの話なのですが、こちらの開発に関しては、注意することは主には二つ。
  1. TemplatePartAttributeなどのパラメータは今度の実装者がどういうパラメータをUIとして定義しているのかを知るための補助的な情報であること。メタデータとして定義されるので、当たり前ですが。
  2. GetTemplateChildというメソッドを使って、自身で定義したフィールド変数にそのコントロールへの参照を設定します。これをしないと煩雑な呼び出しがいっぱいなMFCみたいなことになるので、注意です。
呼び出しのタイミングですが、MSDNのベストプラクティスによれば、OnApplyTemplateのオーバーライドのタイミングが最速になるようです。またイベントの定義の問題などもありますので、変数を直に触らせるのではなく、いくつかのレイヤーをかませて抽象化して、エラーを発生させない機構を作る必要がありますが、あくまで再利用を考えれば、ベストプラクティスに乗っとる必要性がありますが、自己で管理しているレベルでの開発ならば、そこまで神経質になる必要性はなさそうです。
テンプレートコントロールの呼び出しタイミングですが、コンストラクタ→Load→OnApplyTempleteになるので、カスタムユーザーコントロールからの移植の場合には注意が必要になります。

またGeneric.xamlに記述されるので、Blendではすこぶる開発しにくいと思います。また基本的にクラスの定義部分が大きくなりすぎる感がありますので、可能であれば、Partial Classの利用をおすすめします。

5/23/2010

Webサービスのリファレンスの追加に関して。

どうもJudaです。
Webサービスのリファレンスの追加に関して(VS2008)。
Webサービスの追加を行うと、こっそりReferenceファイルが生成されますが、定義から飛ばないと生成されたものを確認できません。定義を確認するとわかるのですが、クラスがpartialで定義されています。これが何を意味するのかと言うと、自動生成のファイルのバックエンドへ変更点を書き込むと更新時に修正、変更した部分を破棄されてしまうので、別ファイルで定義を明確に書いてねって事みたいです。
例えば、EntityのEntityDataという名前のクラスが取得される場合に、その中の要素はPropertyとして生成されます。これに対して、INotifyPropertyChangedを実装しようとします。しかしそれをReferenceに書いてしまうと、更新時に破棄されますので、別ファイルに名前空間に整合性を持たせつつ、PartialなEntityDataを定義します。あとはPartialのキーワードを利用して、各項目のOnChangedやOnChanging(object value)を定義してやれば、独立してプロパティの変更前と変更後の処理を定義出来ます。これでINotifyPropertyChangedを実装可能になります。

5/22/2010

DataGridとの憂鬱

どうもJudaです。
MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Reflection;

namespace AgScheduler
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
var list = DataEntity.Users;
PropertyInfo[] infos = typeof(UserInfo).GetProperties();
//var q = (from rec in list
// select new { Name = rec.名前, Norma = rec.年計, Result = rec.実績 })
// .ToArray();
this.DataContext = infos.AsQueryable();

}

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
PropertyInfo[] infos = typeof(UserInfo).GetProperties();
this.dataGrid1.RowHeight = 30;
this.Foreground = new SolidColorBrush(Colors.Red);
}


private void Button_Click(object sender, RoutedEventArgs e)
{

}

private void dataGrid1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{

}
}
public class hoge
{
public string Name { get; set; }
public double Norma { get; set; }
public double Result { get; set; }
}
}

MainPage.xaml

<UserControl
x:Class="AgScheduler.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:dataInput="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input"
xmlns:ctrl="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="800">
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="620*" />
</Grid.ColumnDefinitions>
<ctrl:DataGrid Name="dataGrid1"
ItemsSource="{Binding}" Grid.Column="2" Margin="0" AutoGenerateColumns="True"
SelectionChanged="dataGrid1_SelectionChanged" />
<Button Content="Help" Click="Button_Click"/>
</Grid>
</UserControl>

DataEntity.cs

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Linq;

namespace AgScheduler
{
public class DataEntity
{
public static UserInfo CreateUserInfo()
{
return new UserInfo()
{
ID = 0,
実績 = 80,
年計 = 1200,
名前 = "テスト太郎"
};
}
public static IQueryable Users {
get
{
var list = new List();
list.AddRange(new UserInfo[]{
CreateUserInfo(),
CreateUserInfo(),
CreateUserInfo(),
CreateUserInfo(),
CreateUserInfo(),
CreateUserInfo(),
CreateUserInfo(),
CreateUserInfo()
});
return list.AsQueryable();
}
set { }
}
public static IQueryable Projects { get; set; }
}
public class UserInfo
{
public int ID { get; set; }
public string 名前 { get; set; }
public double 年計 { get; set; }
public double 実績 { get; set; }
}
public class ProjectInfo
{
public int ID { get; set; }
public string ProjectName { get; set; }
public double ProjectAmount { get; set; }
}
}


明示的なデータ構造がわかるものじゃないと中身を表示してくれないし、そもそもPropertyInfoは中身を表示してくれない。意味がわからない。無名構造体でも表示はしてくれない。どういうことだ。適応のさせかたのどこかで間違えたことは確かなのだが、どこかわからない。無名構造体が使えないのでは、DataGridに動的にデータを適応しようと思うと困るのだが。

5/19/2010

Codeの表示のテスト

どうもJudaです。
MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Reflection;

namespace AgScheduler
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
var list = DataEntity.Users;
PropertyInfo[] infos = typeof(UserInfo).GetProperties();
var q = (from rec in DataEntity.Users
select new
{
Name = rec.名前,
Product = rec.年計,
Amount = rec.実績
}).AsQueryable();
this.dataGrid1.ItemsSource = q;
this.dataGrid1.UpdateLayout();

}

private void Button_Click(object sender, RoutedEventArgs e)
{

}

private void dataGrid1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{

}
}
}

5/16/2010

Silverlightにおける各種画像のエンコード、デコード

どうもJudaです。
Silverlight をつかって画像を処理を行いたいなぁとおもっていたり、ファイルを取得して再度変換したいときに、大変なことに気がつきます。
再変換出来ないじゃん
BMPでしか保存出来ないのに、BMP読めないじゃん
意味がわかりません。Silverlightでは、基本的なポリシーとして不適切な攻撃をされる可能性を最小化し、それぞれの実装者の責任に問題を置き直しています。さまざまな部分でセキュリティに重きを置いています。
でもまぁ、そのおかげでいろいろな部分で変更が効くようになっているので助かります。
とりあえず画像データのEncode,Decodeのためのオープンソースを紹介します。
とりあえずソースを読んでいますが、なかなか便利ですね。

5/14/2010

ADO.NETのあれこれ

どうもJudaです。
BaseListとBaseEntityの話
まさにこの通りで、Reference.csに自動生成されているものに対してINotifyPropertyChangedを実装しないといけないので、面倒で面倒で仕方ないです。
そもそもEntityを生で扱うとめんどくさいことになるので、困りますね。

5/11/2010

LINQ

どうもJudaです。
LINQはここがめちゃくわしい。
日向ぼっこデベロッパhandcraftの備忘録
http://handcraft.blogsite.org/ComponentGeek/ShowArticle/66.aspx

5/10/2010

ADO.NET Data Service のデータの追加、削除、更新

どうもJudaです。

ADO.NET Data Service のデータの追加、削除、更新についてのサイト

ADO.NET Data Services Part 7: Data Modification - Client

http://lostintangent.com/2007/12/30/adonet-data-services-part-7-data-modification-client/

こりゃ詳しい。


5/06/2010

ADO.NET Data Serviceについて

どうもJudaです。

ADO.NET Data Servicesについてですが、主キーでNot NullableなAutoIncrimentなカラムの値の設定方法ですが、どうも値を自動で上書きされるようです。

それ以上に注意しないといけないのは、Entity FrameworkのEntity Data Modelで接続部分をになってくれる構造体群に対しては、接続元になっているDBの各列の型、既定値、Null許容かなどの、「SQL Expressでつくったから、Wizardがやってくれている」と幻想をいだいているものは大半がダメです。そげぶされます。

明示的に設定するようにMSDNでも書いてあります。調べないとわからないのですけど、ちょっとはどこかに書いて欲しいものであります。

また失敗した場合のエラーログが欲しい場合は、Wizardが書いてくれているコードに対して、いくつかの属性を設定すればより詳しいエラーメッセージを得られるのですが、前に書いたのを忘れたので、探しています。属性についても本当に調べにくい。そのくせ、属性すごく重要。

それとLINQにはAutoIncrimentに関する操作は特にはないです。だから今度はUpdateで揉めそうです。うわー、嫌だなぁー。

5/05/2010

SilverlightとDBの連携

どうもJudaです。

Silverlight : ADO.NET Data Services (Silverlight)

http://msdn.microsoft.com/ja-jp/library/cc838234(v=VS.95).aspx

まぁ連携についての情報はここが一番詳しそうです。

ちなみに疑問になるのは、Entity Frameworkを利用した際に、Viewに該当するものは、基本的にUpdateやDeleteは出来ないのではないかと言うことであり、Wizardを通じて、AddToで定義されるメソッドにもViewのものが混在しうるけれども、これについてはプログラマが意識的に使わないように心がけないといけないものなのだろうか?

5/04/2010

SilverlightでのDataDrivenでの注意

どうもJudaです。

プロパティの変更を通知するインターフェイスの実装をしているクラス
INotifyPropertyChangeでの注意。

文字列で指定するプロパティ名は、
別の参照されている部分で使われているバインディングパスの名前と
同一でないと機能しない。

だからバインドを統括するようなクラスをDataContextにして
それぞれ同じデータを別のエイリアスでつかっている場合には、
それら全てに適応できるように読み換えや
同時に複数の変更を通知するようにしないといけない。

本当はエイリアスのような使い方をする場合には
もっと気をつかった設計を行う必要性があると思われる。

もっともなるべく同一の名称になるようにクラスを調整する方が推奨されるだろう。
しかし今回のような注意点は、複数の提供元によって作成されたコントロール間で
協調させたい場合には、協調を制御する統括クラスにはそれなりの対応が求められる。

SilverlightでのXMLシリアライズ

どうもJudaです。

dobon.net

かずきのBlogさん

MSDN + MSDNライブラリ

waりとnaはてな日記

すまないが、XMLの書き出し、読み込みをもうちょっと簡単にしたい。

System.Runtime.Serialization.DataContractSerializer

をつかえば、なんとかなる。というか、なんとかできる。

でも正しい使い方なのかわからない。

とりあえずSilverlightでXMLを読み書きするときには、便利なクラス。

というか、XMLの解析をガチでやらせようと思うと、めんどくさくてくさくて、仕方がないです。

ありがとう、XMLの簡単な読み書き機能を作ってくれた開発者の方。

それにしてもXMLにある潜在的なセキュリティーホールとか怖いなぁ。まぁ、全ての入力はすべからく怖いのか。