20210913のC#に関する記事は7件です。

エラーへの対応

例外への対応 例外とはプログラムの実行中に発生する、処理を継続することができないエラーのこと。 このような例外が発生した場合の対応方法をあらかじめ記述する必要がある。 この対応を例外処理という。 tryキーワード、catchキーワード C#にはtryキーワードとcatchキーワードを使い、例外処理を記述します。 public static void Practice_Q15_2_2() { try { var total = 1000; var line = Console.ReadLine(); var count = int.Parse(line); var ans = total / count; Console.WriteLine(ans); Console.WriteLine("正常終了"); } catch (System.DivideByZeroException) //DivideByZeroException例外をキャッチする { Console.WriteLine("ゼロは入力できません"); } catch (System.FormatException) //FormatException例外をキャッチする { Console.WriteLine("数値を入力してください"); } catch (System.Exception) { Console.WriteLine("予期しないエラーが発生しました"); } } このように例外によって種類を分けられる ただし下記のコードはコンパイルエラーになる try { : } catch (System.Exception) { Console.WriteLine("予期しないエラーが発生しました"); } catch (System.FormatException) { Console.WriteLine("ゼロは入力できません"); } catch (System.Exception) { Console.WriteLine("数値を入力してください"); } コンパイルエラーになる理由は二つあります System.Exception例外は全ての例外の継承元のクラスである try-catch構文では、コードに書かれた順番に例外の種類をチェックしていく 全ての例外はSystem.Exceptionクラスの派生クラスなので、System.ExcepExceptionクラスとは必ずis aの関係になります。 そのため、catch(System.Exception)ブロックが先頭にあると、全ての例外がここキャッチされてしまうのです。 つまり、 Console.WriteLine("ゼロは入力できません"); Console.WriteLine("数値を入力してください"); は絶対に実行されることはありません。 例外オブジェクトにアクセスする 例外のさらに詳しい情報を取得したいとき、例外オブジェクトにアクセスすることで、些細なエラー情報を取得できます。 try { Book book = null; var title = book.Title; //bookはnullなので、Titleを参照できず例外が発生 Console.WriteLine(title); } catch (Exception ex) { Console.WriteLine($"Type: {ex.GetType().Name}"); Console.WriteLine($"Message: {ex.Message}"); Console.WriteLine($"TargetSite: {ex.TargetSite}"); Console.WriteLine($"StackTrace: {ex.StackTrace}"); } 実行結果 Type: NullReferenceException Message: Object reference not set to an instance of an object. TargetSite: Void Practice_Q15_2_3() StackTrace: at practice.Program.Practice_Q15_2_3() in /Users/tamuratoorunin/Projects/practice/practice/Program.cs:line 44 exは、catchブロックで利用できる変数で、Exception例外オブジェクトを表しています。 今日の記事は以上です。ありがとうございました。 何か指摘、ご意見あればご連絡ください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Blazor WebAssembly 社内IIS環境で公開まで

はじめに この記事ではBlazor WebAssemblyをIISを使い公開するまでの記事です。 今回公開するBlazor WebAssemblyのプロジェクトは認証あり、ASP.NET Coreでホストされたプロジェクトとなります。 ※思い出しながら記事を書いています。抜けなどあるかもしれません。 インストールが必要なもの ・IIS ・ASP.NET Core Runtime ・Hosting Bundle ・.NET Runtime ・URL Rewrite ASP.NET Core Runtime / Hosting Bundle / .NET Runtime / URL Rewrite https://dotnet.microsoft.com/download/dotnet/5.0 URL Rewrite https://www.iis.net/downloads/microsoft/url-rewrite ※すべてインストールしたら再起動が必要です。 Visual Studioから発行 ターゲットランタイムはwin-x64にしています。 配置モードはフレームワーク依存でも、自己完結でも問題ないはずです。 「正常に公開されました」と出たら任意のフォルダへコピーします。 IIS上の設定 ・自己証明書の発行 IIS公開する際にSSL証明書を選択する必要があります。自己証明書を発行すれば取りあえずは社内環境で使えるようになります。 サイトの作成 アクセスされるIPアドレスとポートを設定しますが、ファイアウォールを開ける必要があります。 ユーザー権限の設定 コンテンツディレクトリの物理パスで設定したファイル全てに「IIS_IUSRS」「IUSR」ユーザーつ追加する必要があります。 appsettings.jsonの編集 ※Identityを使っている場合のみ テストで動かすためにappsettings.jsonを以下のように変更します。外部に公開する際などはNG. "IdentityServer": { "Clients": { "DAIZ.Client": { "Profile": "IdentityServerSPA" } } },       ↓  "IdentityServer": { "Key": { "Type": "Development" } } 以上でIIS社内環境で使えるようになると思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

文字列の全角・半角変換

全角文字を半角にしたい。 C#でコーディングしている同僚から、 全角から半角に変換したいんだけど、調べても「Microsoft.VisualBasic.dllを追加してStrConvを使え」というのばかり。C#で作ってるのにVisualBasicを使うのはなんか違和感 と。うん。答え出てるよね。 その変な違和感なんて捨てちゃってStrConvを使えばええやん。こんな感じやん。 Strings.StrConv(testStr, VbStrConv.Narrow, 0); と思いつつなんか方法ないかな?と調べてみたら いいのあるよね。(@tricogimmickさん ありがとう) と思ったのもつかの間、 同僚: 濁音、半濁音が混ざると文字が欠けるんだよねー 何言ってんだ??欠けるわけないやん・・・・ ほんまや!・・・いや、だから素直にStrConvをと・・・(笑 と思いつつ私なりの改変を施した。 改変 // 文字列を変換する public static string StringConvert(this string str, dwMapFlags flags) { var ci = System.Globalization.CultureInfo.CurrentCulture; // すべての文字が濁音or半濁音かもしれないので2倍化 string result = new string(' ', str.Length * 2); LCMapStringW(ci.LCID, (uint)flags, str, str.Length, result, result.Length); return result.TrimEnd(); } ・なんとなく直感で、str.Length分の文字数しか返ってこないのでおかしいのかなー   → 2倍化してみるか ・なんとなーくTrimEnd()で締めくくろうか(なんか要らんかもしれんけど) というテンションで改変(笑) 結果 うん。できたね。 もっとスマートな方法があるかもしれないし、この方法は実は違っている可能性もあるけれども、 要件はクリアしたので今回は良しとしよう。 改善 いただいたコメント、および「?」と思ったところがあったので書き換えました。 string.EndTrim(); だと、"あいうえお "とか末尾にスペースがある場合に おかしくなるなぁ・・・ /// <summary> /// 文字列を変換する /// </summary> /// <param name="str"></param> /// <param name="flags"></param> /// <returns></returns> public static string StringConvert(this string str, dwMapFlags flags) { var ci = System.Globalization.CultureInfo.CurrentCulture; // すべてが濁音 or 半濁音かもしれないので2倍化しておく string result = new string(' ', str.Length * 2); int resultCount = LCMapStringW(ci.LCID, (uint)flags, str, str.Length, result, result.Length); return resultCount > 0 ? result.Substring(0, resultCount) : result; } 実行結果が以下 いい感じかな?(だといいな)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity スクリプトからゲームオブジェクトとクラスの適用

1.適当にクラスを用意する。 public class InpGameObject : MonoBehaviour { public async Task<string> GetKey() { var ret=""; while (ret==""){ ret = Input.inputString; await Task.Delay(16); } return ret; } }//class 2.外からクラスを割り当てて呼び出す。(MonoBehaviourの無いクラスを想定) using System.Collections; using System.Collections.Generic; using UnityEngine; public class test : MonoBehaviour { // Start is called before the first frame update async void Start() { var o =new GameObject("_inp");//空のゲームオブジェクトを生成 o.AddComponent<InpGameObject>();//コンポーネントを割り当てる。 while(!Input.GetKeyDown(KeyCode.Space)){ var ret=await o.GetComponent<InpGameObject>().GetKey();//call Debug.Log(ret); await System.Threading.Tasks.Task.Delay(5); } } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity 独自の仮想キー

1.GameObjectのExtensionに。 public static async Task<string> GetVKey(this GameObject @this,int delaytime=1000/200){ ... } 2.リソースフォルダーに入れておくのみ。 //Assets/Resources/InputGetter.cs using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Threading.Tasks; public class InputGetter : MonoBehaviour { public Dictionary<string,KeyCode> keymap=new Dictionary<string, KeyCode>(){ {"<",KeyCode.A}, {">",KeyCode.D}, {"^",KeyCode.W}, {"V",KeyCode.S}, {"A",KeyCode.J}, {"B",KeyCode.K}, {"X",KeyCode.L}, {"Y",KeyCode.O}, {"L",KeyCode.U}, {"R",KeyCode.I}, {"S",KeyCode.Space}, {"P",KeyCode.Return}, }; [SerializeField] string vkey=""; public async Task<string> GetKey(int delaytime=1000/200){ vkey =""; while(vkey=="") await Task.Delay(delaytime); return vkey;//<>^V ABXYLR SP } void Update() { if(vkey=="") foreach (var k in keymap) if (Input.GetKeyDown(k.Value)) vkey = k.Key; } }//class public static class GameObjectInputExtension{ static GameObject getter; public static async Task<string> GetVKey(this GameObject @this,int delaytime=1000/200){ if(getter==null){ getter = new GameObject("InputGetter"); getter.AddComponent<InputGetter>(); } return await getter.GetComponent<InputGetter>().GetKey(delaytime); } }//class 3.適当なゲームオブジェクトから呼び出す。 async void Start() { Debug.Log(await gameObject.GetVKey()); }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

T4テンプレートでらくらくソースコード自動生成(Excel設計書からの動的出力編)

設計書から自動実装した~い! 皆さんはDBやAPIの設計書をどのように管理されていますか?残念ながら弊社ではExcel方眼紙で管理しています。 Excelで管理するということは、Excelを見ながらテーブル定義やら通信処理やらを実装しないといけないということ・・・とても面倒くさいですよね。 何が面倒くさいっていうと、 設計書から作るコードなんてだいたい定形(ボイラープレートコード)なので、手実装だとコピペが多発する→コピペミスで大惨事に 修正やら拡張やらのたびにソースコードだけ直して設計書を直さない馬鹿野郎人が出てきて実装と設計が乖離する VBAで楽しようとしても開発しにくいしソース管理での差分も取りにくい。最終的に修正前後をコメントアウトしてModify start yyyy/MM/ddとかやってしまう セキュリティの都合でマクロ付きブックをお客様に送付できなかったりする 正直に言って設計書に従った実装なんてものは開発の本質部分ではないので、こんなものに労力を費やしたくないわけですね。そこで、T4テンプレートを使って動的にソースコードを作ろう!というのが本稿の目的となります。 用意するもの 書き方がルール決めされているExcelの設計書 Visual Studio 2017 / 2019 (本稿では2019で説明しますが、2017でも大差ありません) 当たり前ですが、Excelの設計書はどんなルールでもよいので、どの列/シートになんの値が入っているのか統制してください。そうでないと、設計内容の解釈のしようがありません。 自動生成プログラム実装手順 生成プログラムのプロジェクトを作る コンソールプログラムでもWinFormsでもなんでもよいです。 作ったプログラムをVBAやらVisual Studio拡張やらにしたい場合はコンソールプログラム 実際に使う人がとっつきやすいようにしたいならWinFormsやWPFなどのGUI 私の場合、設計書が内部資料かお客様にも渡すものかで決めています。例えば前者ならプログラムをブックのVBAからキックしたいのでコンソール、後者ならお客様が自動生成できる必要はないのでGUIにしています。 ClosedXMLをインストール パッケージマネージャ コンソールで以下のコマンドを実行し、ClosedXMLをプロジェクトにインストールします。ClosedXMLはMITライセンスです。 Install-Package ClosedXML ようはExcelブックが読めればいいのでCOMオブジェクト経由でもいいのですが、そうするとプログラムの動作が実行者のPCにインストールされたExcelのバージョンに依存しますので、ClosedXML等のライブラリを使用するほうがよいでしょう。 ブックから設計内容を読み込む Excel設計書のルールに従って設計内容を読み込みます。以下の例は1行1列からデータを読み取っていくサンプルコードです。戻り値がIEnumerable<string>になっていますが、適当な構造体やrecordを定義してそれを返してやればよいでしょう。 Book.cs using System.Collections.Generic; using ClosedXML.Excel; namespace T4RuntimeSample { public class Book { public IEnumerable<string> Load(string bookPath, string sheetName) { // ブックをオープンする 別のプロセスから開いてたりするとException using (var workbook = new XLWorkbook(bookPath)) { // シートをオープンする var sheet = workbook.Worksheet(sheetName); // 行、列のインデックスは1始まり int row = 1; int col = 1; // 列は "A","B"などの文字列指定でもOK while (true) { // セルから文字列を読む yield return sheet.Cell(row++, col++).GetString().Trim(); } } } } } T4テンプレートを作る いよいよ本題のテンプレート作成です。プロジェクトを右クリックし、「新しい項目の追加」からランタイム テキスト テンプレートを選択します。 他に「テキスト テンプレート」というものがありますが、これはデザイン時コード生成という静的にコードを作成するテンプレートです。こちらの活用方法は本稿では説明しません。 追加すると以下のファイルが追加されます。 RuntimeTextTemplate1.tt <#@ template language="C#" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> ランタイムテキストテンプレートについて ランタイムテキストテンプレートは簡単に説明すると、デザインファイル(.tt)に則って文字列を出力するクラスを作ってくれるテンプレートエンジンです。つまり、実際のテキストを出力するには作られたクラスをnewして文字列生成メソッド(TransformText())を実行する必要があります。 「ランタイム」のついていない方はクラスを作るのでなくテキストファイルをそのまま出力します。イメージとしてはWinFormsやWPFでデザイナをいじると.designer.csや.xamlが勝手に変更されていくイメージに近いです(T4のデザイナをいじるとコードもかわるのでデザイン時コード生成)。 Excel設計書の内容をT4のデザイナに書くのではなく、設計書をロードした内容を使って動的にコード生成したいからランタイムテキストテンプレートを使用するというわけです。 しかし、どういうわけかランタイムテキストテンプレート(TextTemplatingFilePreprocessor)を追加してもデザイン時コード生成(TextTemplatingFileGenerator)扱いでプロジェクトに追加されるようです。そのため、.csprojを以下のように手修正する必要があります。 変更前.csproj <ItemGroup> <None Update="RuntimeTextTemplate1.tt"> <Generator>TextTemplatingFileGenerator</Generator> <!-- この行を --> <LastGenOutput>RuntimeTextTemplate1.cs</LastGenOutput> </None> </ItemGroup> 変更後.csproj <ItemGroup> <None Update="RuntimeTextTemplate1.tt"> <Generator>TextTemplatingFilePreprocessor</Generator> <!-- これに変える --> <LastGenOutput>RuntimeTextTemplate1.cs</LastGenOutput> </None> </ItemGroup> .csprojを変更して保存すると、以下のように.ttファイルの下に.csファイルが作られます。ファイル名と同名のpartialクラスが展開されており、TransformText()メソッドがいるのがわかると思います。 テンプレートをいじる前の準備 ここで、上図のオレンジ色部分を注目してください。ここにはなんと開発者の環境での.ttファイルのフルパスが記載されています。こんなものをソース管理にpushするわけにはいかないので、フルパスを出力しないように1行目にlinePragmas設定を追加します。 RuntimeTextTemplate1.tt <#@ template language="C#" linePragmas="false" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> また、ロードした設計書内容をテンプレートで使うためのクラスの定義が必要です。前の図の通り、T4テンプレートが作る文字列生成クラスはpartialクラスなので、別ファイルにpartialクラスを定義することで機能を拡張することが可能です。 間違ってもT4テンプレートが作ったクラスを直接編集しないでください。当たり前ですが、T4のデザイナを変更すると編集内容が消えます。 RuntimeTextTemplate1_partial.cs namespace T4RuntimeSample { public partial class RuntimeTextTemplate1 { public ExcelData Data { get; } // ExcelDataは適当な構造体 // コンストラクタを生やしたりpublicなsetter経由でデータを渡してやる public RuntimeTextTemplate1(ExcelData data) { Data = data; } // 設計内容をコードに変換する処理を書いたりする public string HogeConvert(ExcelData data) { return $"public {data.Type} {data.Name} {{ get; set; }}"; } } } デザインを編集する あとは生成したいコードができるように.ttファイルを編集するだけです。基本的には.ttファイルに記述した通りに文字列が出力されるほか、以下の2つの制御記号でループしたり変数の内容を出力したりすることができます。注意点として、forなどの制御を書くときはインデントをしないことをおすすめします。インデント部分が空白文字として出力されてしまうためです。 記述法 内容 <# 制御 {#> ~ <#} #> forやforeachなどのループ、ifによる条件分岐を行います。必ず { } でくくる必要があります。 <#= 変数名 #> 変数名の内容を出力します。 以下のコードは実際に作った.ttファイルです。このファイルの目的は「CsvHelperで読み込むCSVファイルのデータ構造を設計書からロードして自動生成する」でした。partialクラスには設計書のデータを保持するプロパティContextを実装しています。 MyTemplate.tt <#@ template language="C#" linePragmas="false" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> using System.Collections.Generic; using CsvHelper.Configuration.Attributes; namespace MyImport.DataStructure { /// <summary> /// <#= Context.ClassXmlComment #> /// </summary> public class <#= Context.ClassName #> : IImportable { /// <summary>データの列数</summary> public int ColumnCount { get => <#= Context.Def.Count() #>; } /// <summary>コンストラクタ</summary> public <#= Context.ClassName #>() { } /// <summary>エラー出力に使用するデータの行番号(0始まり)を取得または設定します。</summary> [Ignore] public int RowIndex { get; set; } <# foreach(var def in Context.Def) {#> /// <summary><#= def.VarJpName #> <# foreach(var s in def.Summary.Split(new string[] { "\r", "\n", "\r\n" }, StringSplitOptions.None)) { #> /// <para><#= s #></para> <#}#> /// </summary> [Index(<#= def.Idx#>)] public string <#= def.VarName #> { get; set; } <# } #> } } 実際にできあがるのは以下のようなコードです。 MyImport.cs using System.Collections.Generic; using CsvHelper.Configuration.Attributes; namespace MyImport.DataStructure { /// <summary> /// CsvHelperで取り込んだデータを保持します。 /// </summary> public class MyImport : IImportable { /// <summary>データの列数</summary> public int ColumnCount { get => 15; } /// <summary>コンストラクタ</summary> public MyImport() { } /// <summary>エラー出力に使用するデータの行番号(0始まり)を取得または設定します。</summary> [Ignore] public int RowIndex { get; set; } /// <summary>データ1 /// <para>データ1かもね</para> /// </summary> [Index(0)] public string Data1 { get; set; } /// <summary>データ2 /// <para>データ2だよ</para> /// </summary> [Index(1)] public string Data2 { get; set; } /// <summary>データ3 /// <para>データ3だよ</para> /// </summary> [Index(2)] public string Data3 { get; set; } /// <summary>データ4 /// <para>データ4だよ このデータは注意してね</para> /// </summary> [Index(3)] public string Data4 { get; set; } } } また、ランタイムテキストテンプレートは文字列生成クラスの生成なので、ソースコード以外の文字列も生成可能です。以下に、私が実際に作ったDIコンテナUnityの設定ファイルを出力するテンプレートを記載します。 UnitySetting.tt <#@ template language="C#" linePragmas="false" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> <configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/> </configSections> <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <# foreach (var asm in Context.GetAssemblies()) { #> <assembly name="<#=asm#>" /> <#}#> <# foreach (var ns in Context.GetNameSpaces()) { #> <namespace name="<#=ns#>" /> <#}#> <# foreach (var c in Context.Settings) {#> <alias alias="I<#=c.ClassName#>" type="<#=c.InterfaceNameSpace#>.I<#=c.ClassName#>, DbLogicDefinitions" /> <alias alias="<#=c.ClassName#>" type="<#=c.LogicNameSpace#>.<#=c.ClassName#>, <#=c.AssemblyName#>" /> <#}#> <container> <# foreach (var context in Context.Settings) { #> <register type="I<#= context.ClassName#>" mapTo="<#= context.ClassName#>" /> <#}#> </container> </unity> </configuration> ソースコードを出力しよう 何度も繰り返しになりますが、ランタイムテキストテンプレートは文字列生成処理を行うクラスを生成するエンジンです。テンプレートに従った文字列を出力する処理と、その文字列をファイル等に保存する処理は自分で実装する必要があります。 コンソールアプリなら出力先パスを実行時引数で受け取り、GUIアプリなら画面から設定できるようにすればよいでしょう。 MyExport.cs public void Export(ExcelData data, string path) { // 文字列生成処理をnewして var template = new RuntimeTextTemplate1(data); // 文字列を出力して var text = template.TransformText(); // ファイル出力する using (var sw = new StreamWriter(path, true, Encoding.UTF8)) { sw.Write(text); } } まとめ Excel設計書からソースコードを自動生成するには以下手順で行えます。 Excel設計書を作る ClosedXMLでブックを読み取って、適当な構造体なりrecordなりに設計内容を保持する T4テンプレートの「ランタイム テキスト テンプレート」で出力内容をデザインする T4テンプレートから文字列を作ってファイルに出力する処理を実装する もし設計書の仕様もゼロから作る場合、設計書のルールをすべて決められるとするならば、私の経験則としては3日程度かかる見込みです。内訳としては、 設計書を適当にデザインして 自動実装するコードをなんとなく決めて T4テンプレートをふんわりデザインして 設計書に項目が足りないことがわかって最初からやり直したり 開発者が使いにくそうなので実装されるコードを練り直したり T4にデザインしたコードが文法上間違っててコンパイルエラーになるので直したり という作業を何度もやり直しながら完成形を作るためです。 ただ、設計書からのソースコード作成って、本当に何度でもやります。それこそ設計書の定義が変わったりしなければ5年くらい使いまわしたりするのではないでしょうか。そう考えると、最初に自動生成プログラムを作っておくことで後がすごい楽になるわけですよね。しかも、 機械的に作るから品質が一定! 出力は一瞬でできる! ちゃんとルールを下々に守らせることで設計書とコードが乖離しない! と、当たり前ですがすごいメリットを享受できるわけです。みなさんもExcelをどんどんT4テンプレートに食わせていきましょう! よいT4テンプレートライフを! おまけ VBAからコンソールアプリをキックするにはこんな感じにするとよいです。 Output.vba Sub 出力ボタン_Clicked() Dim arg1 As String arg1 = ThisWorkbook.FullName Dim path As String path = ActiveWorkbook.path & "\出力PG\Export.exe" ' 出力PGへのフルパス Dim obj As New IWshRuntimeLibrary.WshShell Call obj.Run("""" & path & """ """ & arg1 & """", 1, True) MsgBox "処理完了しました。" End Sub デザイン時テンプレートの活用の記事を書きました(宣伝)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Gtk3アプリのTreeViewの表示の簡略化 Part3

Gtk3 TreeViewの表示の簡略化 Part3 gtk-Sharpチュートリアルに書かれているサンプルを簡略化します 前回からの改良点 TreeView上のCell内で値を編集できるようにした using System; using System.Collections.Generic; using Gtk; using UI = Gtk.Builder.ObjectAttribute; namespace treeView3GtkApplication { class MainWindow : Window { [UI] private TreeView _treeView1 = null; List<Song> songs; public MainWindow() : this(new Builder("MainWindow.glade")) { } private MainWindow(Builder builder) : base(builder.GetRawOwnedObject("MainWindow")) { builder.Autoconnect(this); _mkTreeView(); } void _mkTreeView() { songs = new List<Song>(); songs.Add (new Song ("Dancing DJs vs. Roxette", "Fading Like a Flower")); songs.Add (new Song ("Xaiver", "Give me the night")); songs.Add (new Song ("Daft Punk", "Technologic")); Gtk.TreeViewColumnEx artistColumn = new Gtk.TreeViewColumnEx (); artistColumn.Title = "Artist"; //CellRenderの生成 artistColumn._mkCellRendererText(_treeView1 , "",100); //モデルのプロパティを指定する artistColumn.bindingPropertyName = "Artist"; Gtk.TreeViewColumnEx songColumn = new Gtk.TreeViewColumnEx (); songColumn.Title = "Song Title"; songColumn._mkCellRendererText(_treeView1 , "",100); songColumn.bindingPropertyName = "Title"; Gtk.ListStore musicListStore = new Gtk.ListStore (typeof (Song)); foreach (Song song in songs) { musicListStore.AppendValues (song); } _treeView1.Model = musicListStore; _treeView1._mkBinding(); } } public class Song { public Song (string artist, string title) { this.Artist = artist; this.Title = title; } //リフレクションを有効にするためgetとsetを書く public string Artist { get; set; } public string Title { get; set; } } } TreeView拡張クラス namespace Gtk { static class GtkExtensions { public static void _mkBinding(this TreeView treeView) { foreach (TreeViewColumnEx column in treeView.Columns) { if (!(column is TreeViewColumnEx)) { return; } TreeViewColumnEx columnt1 = (column as TreeViewColumnEx); columnt1._mkBinding(); } } } } TreeViewColumnEx 派生クラス using System; using System.Reflection; using Gtk; using Gdk; public static class objectExtensions { public static object _performSelector_Property(this object obj, string propertyName) { try { Type magicType = obj.GetType(); PropertyInfo pi = magicType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); MethodInfo getMethod = pi.GetGetMethod(); object result = getMethod.Invoke(obj, null); return result; } catch (Exception e) { Console.WriteLine(e.Message); } } public static void _setSelector_Property(this object obj, string propertyName ,dynamic value) { try { Type t = obj.GetType(); PropertyInfo pi = t.GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); MethodInfo setMethod = pi.GetSetMethod(); setMethod.Invoke(obj, new Object[1] { value }); }catch (Exception e) { Console.WriteLine(e.Message); } } } namespace Gtk { public class TreeViewColumnEx : TreeViewColumn { public String bindingPropertyName = ""; private Gtk.ListStore listStore1 = null; public CellRendererText _mkCellRendererText(TreeView treeView , string title = "" , int width = 0 , bool isEditable = true, bool isExpand = false, bool isPackStart = true) { if (title != "") { this.Title = title; } Gtk.CellRendererTextEx CellRendererText1 = new Gtk.CellRendererTextEx(); if (width != 0) { this.MinWidth = width; } this.Expand = isExpand; this.Sizing = TreeViewColumnSizing.Autosize; this.PackStart(CellRendererText1, isPackStart); listStore1 = (ListStore)treeView.Model; if (isEditable) { CellRendererText1.Editable = true; CellRendererText1.Edited += delegate(object o, EditedArgs args) { Gtk.CellRendererTextEx o1 = (Gtk.CellRendererTextEx)o; TreePath treePath1 = new TreePath (args.Path); TreeIter iter; if (listStore1 != null) { listStore1.GetIter (out iter, treePath1); object testModel1 = (object)listStore1.GetValue(iter, 0); _setModelData(testModel1, bindingPropertyName, args.NewText); } }; } treeView.AppendColumn(this); return CellRendererText1; } public CellRendererPixbuf _mkCellRendererPixbuf(TreeView treeView , string title = "" ,int width = 0 , bool isExpand = false ,bool isPackStart = true) { if (title != "") { this.Title = title; } Gtk.CellRendererPixbuf CellRendererPixbuf1 = new Gtk.CellRendererPixbuf(); if (width != 0) { this.MinWidth = width; } this.Expand = isExpand; this.Sizing = TreeViewColumnSizing.Autosize; listStore1 = (ListStore)treeView.Model; this.PackStart(CellRendererPixbuf1, isPackStart); //this.AddAttribute (CellRendererPixbuf1, "pixbuf", 0); treeView.AppendColumn(this); return CellRendererPixbuf1; } public CellRendererToggle _mkCellRendererToggle(TreeView treeView , string title = "",int width = 0 , bool isToggled = false ,bool isExpand = false ,bool isPackStart = true) { if (title != "") { this.Title = title; } Gtk.CellRendererToggle CellRendererToggle1 = new Gtk.CellRendererToggle(); if (width != 0) { this.MinWidth = width; } this.Expand = isExpand; this.Sizing = TreeViewColumnSizing.Autosize; listStore1 = (ListStore)treeView.Model; if (isToggled) { CellRendererToggle1.Toggled += delegate(object o, ToggledArgs args) { TreeIter iter; if (listStore1.GetIterFromString(out iter, args.Path)) { object object1 = (object)listStore1.GetValue(iter, 0); object value = object1._performSelector_Property(bindingPropertyName); String val = Convert.ToBoolean(value) == true ? "false" : "true"; _setModelData(object1, bindingPropertyName, val); } }; } this.PackStart(CellRendererToggle1, isPackStart); treeView.AppendColumn(this); return CellRendererToggle1; } public CellRendererProgress _mkCellRendererProgress(TreeView treeView , string title = "", int width = 0 , bool isExpand = false ,bool isPackStart = true) { if (title != "") { this.Title = title; } Gtk.CellRendererProgress CellRendererProgress1 = new Gtk.CellRendererProgress(); if (width != 0) { this.MinWidth = width; } this.Expand = isExpand; this.Sizing = TreeViewColumnSizing.Autosize; listStore1 = (ListStore)treeView.Model; this.PackStart(CellRendererProgress1, isPackStart); treeView.AppendColumn(this); return CellRendererProgress1; } public void _mkBinding() { if(this.Cells.Length > 0) { this.SetCellDataFunc(this.Cells[0], new Gtk.TreeCellDataFunc(_RenderCellDo)); } } private void _RenderCellDo(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter) { if(!(column is TreeViewColumnEx)) { return; } TreeViewColumnEx column1 = (column as TreeViewColumnEx); if(column1.bindingPropertyName == "" || column1.bindingPropertyName == null) { Console.WriteLine("PropertyNameがない"); return; } object modelData = (object)model.GetValue(iter, 0); object value = modelData._performSelector_Property(column1.bindingPropertyName); _setCellData(value, cell); } private void _setCellData(object value ,Gtk.CellRenderer cell) { if (value != null && cell is Gtk.CellRendererText && (value is String)) { (cell as Gtk.CellRendererText).Text = value as String; }else if (value != null && cell is Gtk.CellRendererText && (value is int)) { (cell as Gtk.CellRendererText).Text = ((int)value).ToString(); }else if (value != null && cell is Gtk.CellRendererText && (value is long)) { (cell as Gtk.CellRendererText).Text = ((long)value).ToString(); }else if(value != null && cell is Gtk.CellRendererText && (value is DateTime)) { (cell as Gtk.CellRendererText).Text = ((DateTime)value).ToString(); } else if(value != null && cell is Gtk.CellRendererPixbuf && (value is String)) { (cell as Gtk.CellRendererPixbuf).Pixbuf = new Pixbuf(null, (value as String)); } else if(value != null && cell is Gtk.CellRendererToggle && (value is String)) { (cell as Gtk.CellRendererToggle).Active = Convert.ToBoolean((value is String)); } else if(value != null && cell is Gtk.CellRendererProgress && (value is String)) { (cell as Gtk.CellRendererProgress).Value = Convert.ToInt32((value is String)); } else if(value != null && cell is Gtk.CellRendererPixbuf && (value is byte[])) { (cell as Gtk.CellRendererPixbuf).Pixbuf = new Pixbuf((byte[])value); } else if(value != null && cell is Gtk.CellRendererToggle && (value is Boolean)) { (cell as Gtk.CellRendererToggle).Active = (Boolean)value; } else if(value != null && cell is Gtk.CellRendererProgress && (value is int)) { (cell as Gtk.CellRendererProgress).Value = (int)value; } } private void _setModelData(object modelData1 , String bindingPropertyName1 , String value ) { Type t = modelData1._getKata(bindingPropertyName1); if (value != null && t.Equals(typeof(String))) { modelData1._setSelector_Property(bindingPropertyName1, Convert.ToString(value)); }else if (value != null && t.Equals(typeof(int))) { modelData1._setSelector_Property(bindingPropertyName1, Convert.ToInt32(value)); }else if (value != null && t.Equals( typeof(double))) { modelData1._setSelector_Property(bindingPropertyName1, Convert.ToDouble(value)); }else if (value != null && t.Equals(typeof(long))) { modelData1._setSelector_Property(bindingPropertyName1, Convert.ToInt64(value)); }else if (value != null && t.Equals( typeof(Boolean))) { modelData1._setSelector_Property(bindingPropertyName1,Convert.ToBoolean(value)); }else if (value != null && t.Equals( typeof(bool))) { modelData1._setSelector_Property(bindingPropertyName1,Convert.ToBoolean(value)); }else if (value != null && t.Equals( typeof(DateTime))) { modelData1._setSelector_Property(bindingPropertyName1, Convert.ToDateTime(value)); }else if (value != null && t.Equals( typeof(decimal))) { modelData1._setSelector_Property(bindingPropertyName1, Convert.ToDecimal(value)); }else if (value != null && t.Equals( typeof(char))) { modelData1._setSelector_Property(bindingPropertyName1, Convert.ToChar(value)); }else if (value != null && t.Equals( typeof(byte))) { modelData1._setSelector_Property(bindingPropertyName1, Convert.ToByte(value)); } } } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む