Oracle開発ツールのいくつかは、PL/SQL の引数が配列の場合、自由に値がセットできなくて、苦労するケースもあるかと思います。
Oracle SQL Developer のデバッグ実行にて、『PL/SQL ブロック』を編集することで、配列型の引数に、好きな値を設定する事ができます。
郵便番号/住所/緯度経度データ等の地理情報を、XML or JSON で取得できるサービス『HeartRails Geo API』にて、エリア情報を叩くと、こういう値が返ってきます。
{ "response": { "area": [ "北海道", "東北", "関東", "中部", "近畿", "中国", "四国", "九州" ] } }
この結果を、グリッドの ItemsSource に流し込んで、いい感じに表示しようと思い、以下のように書いたら、何とも微妙な結果になりました。
Http リクエストを投げるところと、デシリアライズのところは省略しています。
また、受け側は dynamic型にしています。
(フォーム部分は省略しています。といっても、「myDataGrid01」という Name の DataGrid があれば何でもいい訳ですが。)
List<dynamic> areaList = new List<dynamic>(); foreach (var item in responseData.response.area) // 「responseData」にデシリアライズされたデータが格納されています。 { areaList.Add(item); } myDataGrid01.ItemsSource = areaList;
余計なものが色々入ってます。
必用なのは Valueなので、指定して抽出。
List<dynamic> areaList = new List<dynamic>(); foreach (var item in responseData.response.area) { areaList.Add(item.Value); } myDataGrid01.ItemsSource = areaList;
なぜか Lengthが取れるという妙な結果に・・・。
json のパースの仕方がどうこうという訳でなく、DataGrid の ItemsSource に、配列を放り込むと、こうなるみたいです。
なので、List<string>
のデータでも、同様の現象が起こります。
どうしても DataGridで表現しなければならないなら、配列の部分を Dictionaryにする or 自作のクラスを定義して、それに放り込むかですが、本来のデータに不純物を入れ込む事になるので、ちょっと避けたい。
という訳で、こういった場合は DataGridでなく、ListView を使う方法が最良ではないでしょうか。
以下では、「myListView01」という Name の ListView を定義しています。
List<dynamic> areaList = new List<dynamic>(); foreach (var item in responseData.response.area) { areaList.Add(item); } myListView01.ItemsSource = areaList;
DataGrid は色々できて便利なんですが、その分操作が難しかったり、変にバッドノウハウを知っておかないとハマる原因になったりするので、やる事がシンプルなら、ListViewでいい気がします。
こういう状況。
List<Users> //Model(のリスト) List<ExtendUsers> //Modelを拡張したクラス(のリスト)
こういうのがあって、List<ExtendUsers>
に、List<Users>
の要素をブチ込みたい、といったケース。
ストレートにダウンキャストが使えないんで、以下のような工夫をしてみた。
分割しているのは、全部繋げるとスクロールバーが一番下にしか来なくて、読みづらかったためです。
//親クラス class Users { public int Id { get; set; } public string Name { get; set; } public int Position { get; set; } } //子クラス class ExtendUsers : Users { public bool IsChecked { get; set; } //画面の制御用として、子だけで使いたいプロパティ public ExtendUsers(Users value) //コンストラクタの引数に、親のインスタンスを渡す { //--------------------- // 親要素の全プロパティをリストアップし、子に同じ値を設定 //--------------------- PropertyInfo[] propertyInfoinfoArray = value.GetType().GetProperties(); //プロパティをリストアップ foreach (PropertyInfo item in propertyInfoinfoArray) //リストアップしたプロパティをループで回す { var property = value.GetType().GetProperty(item.Name); //プロパティを取得 property.SetValue(this, item.GetValue(value)); //子に親と同じ値をセット } } }
//Model定義されたクラスのリスト(ここに書いてると、そう見えないけど、そういう事にしといて下さい。) private List<Users> _users; //Model定義されたクラスを拡張した要素を詰め込んだリスト private List<ExtendUsers> _extendUsers; private void MyButton01_Click() { _extendUsers = new List<ExtendUsers>(); foreach (var item in _users) //Model定義された要素が入ったリストをループ回す { ExtendUsers el = new ExtendUsers(item); //子のインスタンス作成時、親のインスタンスを引数に渡す。(詳細は上記を参照) _extendUsers.Add(el); //親のインスタンスと同じ値を設定した子を、リストに追加 } }
//============================ // サンプルソースを動かすために用意した。本当はDBから引っ張ってくる //============================ private void SetUsersList() { _users = new List<Users>(); _users.Add(new Users { Id = 1, Name = "Tanaka", Position = 1 }); _users.Add(new Users { Id = 2, Name = "Yamada", Position = 1 }); _users.Add(new Users { Id = 3, Name = "Watanabe", Position = 2 }); }
もっといい方法がありそうだけど、今の自分にはこの辺が限界。
以上を踏まえて、サンプルソースで説明。
//親クラス class ParentClass { } //子クラス class ChildClass : ParentClass { } private void MyButton01_Click() { //=========================== // アップキャスト //=========================== ParentClass parent01; ChildClass child01; //子クラスのインスタンスを生成 child01 = new ChildClass(); //子クラスのインスタンスを、親クラスに代入可能。 parent01 = child01; //=========================== // ダウンキャスト(エラー) //=========================== ParentClass parent02; ChildClass child02; //親クラスのインスタンスを生成 parent02 = new ParentClass(); //キャストできるかどうか確認(falseになります) if (parent02 is ChildClass) { //キャスト時にエラーが発生する child02 = (ChildClass)parent02; } //asを使えば キャストできない場合 nullが入る child02 = parent02 as ChildClass; //=========================== // ダウンキャスト //=========================== ParentClass parent03; ChildClass child03; //親クラスのインスタンスを、子クラスで生成 parent03 = new ChildClass(); //ダウンキャスト可。 child03 = (ChildClass)parent03; }
以下、ボタンを押したら google.co.jp の内容を取得するプログラムです。
フォーム側は WPF や Windows Forms あたりで適当に用意して下さい。
private void Button01_Click(object sender, RoutedEventArgs e) { //呼び出し先が async void の場合、呼び出し元に awaitは不要 Button01_ClickContentAsync(); } //非同期メソッドには async キーワードを付ける。 private async void Button01_ClickContentAsync() { string targetURL = "http://www.google.co.jp/"; //呼び出し先が async Task の場合、呼び出し元に awaitを記述する。 await HttpGetRequestAsync(targetURL); } private async Task HttpGetRequestAsync(string targetURL) { using (var _httpClient = new HttpClient()) { //Task<string> は string が返る Task<string> response = _httpClient.GetStringAsync(targetURL); //Task で取得した値を取り出すには、await を使用する。 string contents = await response; Console.WriteLine(contents); } }
初めのうちは、「async」って何?(Microsoft Docsを読む)、「await」って何?(Microsoft Docsを読む)、「Task」って(略)
・・・と、構文1つ1つを調べながら進めていくより、『非同期処理にて使用する構文』と、ひとまとめにして読み進める方が、理解しやすいんじゃないかと思います。
非同期処理について調べていると、ディープな世界に踏み込んでいったり、過去の歴史まで遡りながら解説しているサイトが多く、
「理論は後でちゃんと学ぶから、まず、どんなコード書けばいいの?」という人向けの記事が少ないなー、と思ったんで、エントリにしてみた。
System.Windows.Controls.Grid は、Grid.Row と Grid.Column にて、要素のポジションを指定します。
動的に要素を配置する場合、SetValue にて、Grid.RowProperty と Grid.ColumnProperty を設定するとOKです。
xaml側
<Window x:Class="PracticeWPF.MyWindow19" 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:local="clr-namespace:PracticeWPF" mc:Ignorable="d" Title="MyWindow19" Height="200" Width="200"> <Grid> <Grid x:Name="myGrid01" Width="150" Height="150"> <Grid.RowDefinitions> <RowDefinition Height="1*"/> <RowDefinition Height="1*"/> <RowDefinition Height="1*"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*"/> <ColumnDefinition Width="1*"/> <ColumnDefinition Width="1*"/> </Grid.ColumnDefinitions> </Grid> </Grid> </Window>
cs側
using System.Windows; using System.Windows.Controls; namespace PracticeWPF { /// <summary> /// Gridの指定位置に要素を追加 /// </summary> public partial class MyWindow19 : Window { public MyWindow19() { InitializeComponent(); SetGridItems(); } private void SetGridItems() { Button b0_0 = new Button(); b0_0.Content = "0-0"; b0_0.SetValue(Grid.RowProperty, 0); b0_0.SetValue(Grid.ColumnProperty, 0); myGrid01.Children.Add(b0_0); Button b0_2 = new Button(); b0_2.Content = "0-2"; b0_2.SetValue(Grid.RowProperty, 0); b0_2.SetValue(Grid.ColumnProperty, 2); myGrid01.Children.Add(b0_2); Button b1_1 = new Button(); b1_1.Content = "1-1"; b1_1.SetValue(Grid.RowProperty, 1); b1_1.SetValue(Grid.ColumnProperty, 1); myGrid01.Children.Add(b1_1); Button b2_2 = new Button(); b2_2.Content = "2-2"; b2_2.SetValue(Grid.RowProperty, 2); b2_2.SetValue(Grid.ColumnProperty, 2); myGrid01.Children.Add(b2_2); } } }