- 投稿日:2020-04-14T19:52:26+09:00
[Unity初心者]マウスポインタの位置を取得
- 投稿日:2020-04-14T15:03:16+09:00
string配列をint配列に変換
string配列をint配列へできるだけスッキリと記述したかったので
ググった結果をメモメモ(~_~メ)string[] strArray = { "1", "10", "100", "1000", "10000" };
int[] intArray = new int[strArray.Length];
for (int i = 0; i < intArray.Length; i++)
intArray[i] = int.Parse(strArray[i]);上記をスッキリと。。。
・LINQで
int[] intArray = strArray
.Select(int.Parse)
.ToArray();・ArrayクラスのConvertAll()メソッドで
int[] intArray = Array.ConvertAll(strArray, int.Parse);・Listとfreachを使用して
var intList = new List(strArray.Length);
foreach(var s in strArray)
intList.Add(int.Parse(s));
var intArray = intList.ToArray();もっといい書き方があればぜひコメントへお願いいたします(^_^)
- 投稿日:2020-04-14T14:08:39+09:00
Panelなどコントロール(Control)上で右クリックをしてコンテキストメニューを開いた位置に新たにPictureBoxなどのコントロールを追加する(その2:追加したコントロールを削除する))
(その1)で紹介した「Panelなどコントロール(Control)上で右クリックをしてコンテキストメニューを開いた位置に新たにPictureBoxなどのコントロールを追加する」に引き続き、更に追加したコントロールを削除するソースコードを紹介する。
なお、削除の方法は、フォーム上にあるコントロールを、右クリックでコンテキストメニューを表示して、フォーム上から動的に削除する(その1)や(その2:削除したいコントロールが複数ある場合)で紹介したので、参照していただきたい。
// 1.コントロール(panel)上で左クリックしたときにコンテキストメニューを開き、コンテキストメニューを開いた時にあったマウスの先端に動的に新たにコントロールを作る。 // 2.新たに作ったコントロールは、左クリックによりコンテキストメニューを開き削除できる。 // 参考資料 // https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.contextmenustrip?view=netframework-4.8 // https://dobon.net/vb/dotnet/control/cmclickpoint.html using System; using System.Drawing; using System.Windows.Forms; using System.ComponentModel; namespace TestSourceControl { class Form3 : Form { public static void Main() { Application.Run(new Form3()); } private Panel panel; // panelを左クリックしたときのContextMenuStripコントロールの宣言 private ContextMenuStrip contextMenuStripOnPanel; private ContextMenuStrip contextMenuStripOnAdditionalControl; public Form3() { this.Size = new Size(800, 800); // panelのコンテキストメニューを宣言とコンテキストメニューを開いた時のイベントハンドラーの定義 contextMenuStripOnPanel = new ContextMenuStrip(); contextMenuStripOnPanel.Opening += new CancelEventHandler(cms_Opening); // 必ずForm3()で宣言する panel = new Panel(); panel.Location = new Point(100, 100); panel.Size = new Size(600, 600); panel.BorderStyle = BorderStyle.FixedSingle; panel.BackColor = Color.SkyBlue; panel.Parent = this; panel.ContextMenuStrip = contextMenuStripOnPanel; Label labelOnForm = new Label(); labelOnForm.Text = " 水色のパネルの上で、右クリックをして、" + "\r\n" + "コンテキストメニューからコントロールを選択すると、" + "\r\n" + "パネル上の右クリックした際のマウスポインタの先の位置に、選択したコントロールを追加できます。" + "\r\n" + " またその追加したコントロールの上で左クリックをすると削除できます。"; labelOnForm.AutoSize = true; ; labelOnForm.Location = new Point(0, 0); labelOnForm.Parent = this; contextMenuStripOnAdditionalControl = new ContextMenuStrip(); // 必ずForm3()で宣言する // 追加したコントロールを左クリックした時に表示するコンテキストメニュー(contextMenuStripOnAdditionalControlMenuItems()に記述したものと同じ。メニューの内容を共通にするなら以下のコメントアウトを外す //contextMenuStripOnAdditionalControl.Items.Clear(); //contextMenuStripOnAdditionalControl.Items.Add("削除"); //contextMenuStripOnAdditionalControl.Items.Add("追加コンソールのメニューアイテム2"); //contextMenuStripOnAdditionalControl.Items.Add("追加コンソールのメニューアイテム3"); //contextMenuStripOnAdditionalControl.Items[0].Click += AdditionalControlItems0_Click; //contextMenuStripOnAdditionalControl.Items[1].Click += AdditionalControlItems1_Click; //contextMenuStripOnAdditionalControl.Items[2].Click += AdditionalControlItems2_Click; // ここまで } private Point cp; void cms_Opening(object sender, CancelEventArgs e) { ContextMenuStrip menu = (ContextMenuStrip)sender; //マウスカーソルの位置を画面座標で取得 Point mp = MousePosition; //ContextMenuStripを表示しているコントロールのクライアント座標に変換 cp = menu.SourceControl.PointToClient(mp); //結果を表示 Console.WriteLine(cp); // コンテキストメニューの表示 contextMenuStripOnPanel.Items.Clear(); contextMenuStripOnPanel.Items.Add("ピクチャーボックスを追加"); contextMenuStripOnPanel.Items.Add("テキストボックスを追加"); contextMenuStripOnPanel.Items.Add("ラベルを追加"); contextMenuStripOnPanel.Items[0].Click += PanelMenuItems0_Click; contextMenuStripOnPanel.Items[1].Click += PanelMenuItems1_Click; contextMenuStripOnPanel.Items[2].Click += PanelMenuItems2_Click; // キャンセルをfalseに設定します。(イベントをキャンセルするかどうかの設定) // 空のエントリに基づいてtrueに最適化されます。 e.Cancel = false; //trueにするとコンテキスメニューが表示されない } // PictureBoxをつくるイベントハンドラ private void PanelMenuItems0_Click(object sender, EventArgs e) { PictureBox pictureBox = new PictureBox(); pictureBox.Location = cp; pictureBox.BackColor = Color.White; pictureBox.Size = new Size(50, 50); pictureBox.Image = Image.FromFile("testPicture.bmp"); pictureBox.Parent = panel; contextMenuStripOnAdditionalControlMenuItems(); // 追加したコントロールのコンテキストメニューのアイテムを作る pictureBox.ContextMenuStrip = contextMenuStripOnAdditionalControl; } // テキストボックスを作るイベントハンドラー private void PanelMenuItems1_Click(object sender, EventArgs e) { TextBox textBox = new TextBox(); textBox.Location = cp; textBox.BorderStyle = BorderStyle.FixedSingle; textBox.Text = "これはテキストボックスです。"; textBox.Multiline=true; textBox.Size = new Size(100, 100); textBox.BackColor = Color.Yellow; textBox.Parent = panel; contextMenuStripOnAdditionalControlMenuItems(); // 追加したコントロールのコンテキストメニューのアイテム textBox.ContextMenuStrip = contextMenuStripOnAdditionalControl; } // // ラベルを作るイベントハンドラー private void PanelMenuItems2_Click(object sender, EventArgs e) { Label label = new Label(); label.Location = cp; label.BorderStyle = BorderStyle.FixedSingle; label.BackColor = Color.Pink; label.Text = "これはラベルです。"; label.Parent = panel; contextMenuStripOnAdditionalControlMenuItems(); // 追加したコントロールのコンテキストメニューのアイテム label.ContextMenuStrip = contextMenuStripOnAdditionalControl; } // 追加したコントロールのコンテキストメニューのアイテム (メニューアイテムを分けたいときは、これをさんこうにして別のメソッドを作るといい) private void contextMenuStripOnAdditionalControlMenuItems() { contextMenuStripOnAdditionalControl.Items.Clear(); // 前回作ったアイテムを削除して作り直す。 contextMenuStripOnAdditionalControl.Items.Add("削除"); contextMenuStripOnAdditionalControl.Items.Add("追加コンソールのメニューアイテム2"); contextMenuStripOnAdditionalControl.Items.Add("追加コンソールのメニューアイテム3"); contextMenuStripOnAdditionalControl.Items[0].Click += AdditionalControlItems0_Click; contextMenuStripOnAdditionalControl.Items[1].Click += AdditionalControlItems1_Click; contextMenuStripOnAdditionalControl.Items[2].Click += AdditionalControlItems2_Click; } // 追加したコンソールのメニューアイテム0番(削除)を選択した時のイベントハンドラ private void AdditionalControlItems0_Click(object sender, EventArgs e) { if (contextMenuStripOnAdditionalControl.SourceControl == null) return; Control c = contextMenuStripOnAdditionalControl.SourceControl as Control; Console.WriteLine("SourceControl={0}", contextMenuStripOnAdditionalControl.SourceControl); //Console.WriteLine("Source:" + c.GetType().ToString()); Console.WriteLine(); if (c != null) { panel.Controls.Remove(c); // フォームに登録されたコントロールのオブジェクトを消す } else MessageBox.Show("これは削除できません!"); } // 追加したコンソールのメニューアイテム1番を選択した時のイベントハンドラ private void AdditionalControlItems1_Click(object sender, EventArgs e) { Console.WriteLine("items1_Click"); Console.WriteLine(); } // 追加したコンソールのメニューアイテム2番を選択した時のイベントハンドラ private void AdditionalControlItems2_Click(object sender, EventArgs e) { Console.WriteLine("items2_Click"); Console.WriteLine(); } } }
- 投稿日:2020-04-14T13:50:26+09:00
Panelなどコントロール(Control)上で右クリックをしてコンテキストメニューを開いた位置に新たにPictureBoxなどのコントロールを追加する
下の写真のように、水色のPanelの上で、コンテキストメニューを開き、その選択に応じて、新たにPictureBoxなどのコントロールを追加する。
ポイントは、コンテキストメニューを開くために、右クリックした位置を取得する点である。この点については、dobon.netを参考にした。
https://dobon.net/vb/dotnet/control/cmclickpoint.html// 1.コントロール(panel)上で左クリックしたときにコンテキストメニューを開き、コンテキストメニューを開いた時にあったマウスの先端に動的に新たにコントロールを作る。 // 参考資料 // https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.contextmenustrip?view=netframework-4.8 // https://dobon.net/vb/dotnet/control/cmclickpoint.html using System; using System.Drawing; using System.Windows.Forms; using System.ComponentModel; namespace TestSourceControl { class Form3 : Form { public static void Main() { Application.Run(new Form3()); } private Panel panel; // panelを左クリックしたときのContextMenuStripコントロールの宣言 private ContextMenuStrip contextMenuStripOnPanel; public Form3() { this.Size = new Size(800, 800); // panelのコンテキストメニューを宣言とコンテキストメニューを開いた時のイベントハンドラーの定義 contextMenuStripOnPanel = new ContextMenuStrip(); // panelの上で、右クリックをした時のコンテキストメニューを開くためのデリゲードへの登録 contextMenuStripOnPanel.Opening += new CancelEventHandler(cms_Opening); // 必ずForm3()で宣言する panel = new Panel(); panel.Location = new Point(100, 100); panel.Size = new Size(600, 600); panel.BorderStyle = BorderStyle.FixedSingle; panel.BackColor = Color.SkyBlue; panel.Parent = this; panel.ContextMenuStrip = contextMenuStripOnPanel; Label labelOnForm = new Label(); labelOnForm.Text = " 水色のパネルの上で、右クリックをして、" + "\r\n" + "コンテキストメニューからコントロールを選択すると、" + "\r\n" + "パネル上の右クリックした際のマウスポインタの先の位置に、選択したコントロールを追加できます。" ; labelOnForm.AutoSize![動作画像.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501068/536124cf-c683-c283-d14f-933326bd830f.png) = true; ; labelOnForm.Location = new Point(0, 0); labelOnForm.Parent = this; } private Point cp; // panel上で右クリックをした時の処理 void cms_Opening(object sender, CancelEventArgs e) { ContextMenuStrip menuOnPanel = (ContextMenuStrip)sender; // マウスカーソルの位置を画面座標で取得 Point mp = MousePosition; cp = menuOnPanel.SourceControl.PointToClient(mp); Console.WriteLine(cp); // コンテキストメニューの表示 contextMenuStripOnPanel.Items.Clear(); contextMenuStripOnPanel.Items.Add("ピクチャーボックスを追加"); contextMenuStripOnPanel.Items.Add("テキストボックスを追加"); contextMenuStripOnPanel.Items.Add("ラベルを追加"); contextMenuStripOnPanel.Items[0].Click += PanelMenuItems0_Click; contextMenuStripOnPanel.Items[1].Click += PanelMenuItems1_Click; contextMenuStripOnPanel.Items[2].Click += PanelMenuItems2_Click; // キャンセルをfalseに設定します。(イベントをキャンセルするかどうかの設定) // 空のエントリに基づいてtrueに最適化されます。 e.Cancel = false; //trueにするとコンテキスメニューが表示されない } // // PictureBoxをつくるイベントハンドラ private void PanelMenuItems0_Click(object sender, EventArgs e) { PictureBox pictureBox = new PictureBox(); pictureBox.Location = cp; pictureBox.BackColor = Color.White; pictureBox.Size = new Size(50, 50); pictureBox.Image = Image.FromFile("testPicture.bmp"); pictureBox.Parent = panel; } // // テキストボックスを作るイベントハンドラー private void PanelMenuItems1_Click(object sender, EventArgs e) { TextBox textBox = new TextBox(); textBox.Location = cp; textBox.BorderStyle = BorderStyle.FixedSingle; textBox.Text = "これはテキストボックスです。"; textBox.Multiline=true; textBox.Size = new Size(100, 100); textBox.BackColor = Color.Yellow; textBox.Parent = panel; } // // ラベルを作るイベントハンドラー private void PanelMenuItems2_Click(object sender, EventArgs e) { Label label = new Label(); label.Location = cp; label.BorderStyle = BorderStyle.FixedSingle; label.BackColor = Color.Pink; label.Text = "これはラベルです。"; label.Parent = panel; } } }この画像ファイルは、debugフォルダまたはbinフォルダに置いてください。
- 投稿日:2020-04-14T13:50:26+09:00
Panelなどコントロール(Control)上で右クリックをしてコンテキストメニューを開いた位置に新たにPictureBoxなどのコントロールを追加する(その1)
下の写真のように、水色のPanelの上で、コンテキストメニューを開き、その選択に応じて、新たにPictureBoxなどのコントロールを追加する。
ポイントは、コンテキストメニューを開くために、右クリックした位置を取得する点である。この点については、dobon.netを参考にした。
https://dobon.net/vb/dotnet/control/cmclickpoint.htmlなお、追加したコントロールを削除したい場合は、(その2:追加したコントロールを削除する)を参照してください。
// 1.コントロール(panel)上で左クリックしたときにコンテキストメニューを開き、コンテキストメニューを開いた時にあったマウスの先端に動的に新たにコントロールを作る。 // 参考資料 // https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.contextmenustrip?view=netframework-4.8 // https://dobon.net/vb/dotnet/control/cmclickpoint.html using System; using System.Drawing; using System.Windows.Forms; using System.ComponentModel; namespace TestSourceControl { class Form3 : Form { public static void Main() { Application.Run(new Form3()); } private Panel panel; // panelを左クリックしたときのContextMenuStripコントロールの宣言 private ContextMenuStrip contextMenuStripOnPanel; public Form3() { this.Size = new Size(800, 800); // panelのコンテキストメニューを宣言とコンテキストメニューを開いた時のイベントハンドラーの定義 contextMenuStripOnPanel = new ContextMenuStrip(); // panelの上で、右クリックをした時のコンテキストメニューを開くためのデリゲードへの登録 contextMenuStripOnPanel.Opening += new CancelEventHandler(cms_Opening); // 必ずForm3()で宣言する panel = new Panel(); panel.Location = new Point(100, 100); panel.Size = new Size(600, 600); panel.BorderStyle = BorderStyle.FixedSingle; panel.BackColor = Color.SkyBlue; panel.Parent = this; panel.ContextMenuStrip = contextMenuStripOnPanel; Label labelOnForm = new Label(); labelOnForm.Text = " 水色のパネルの上で、右クリックをして、" + "\r\n" + "コンテキストメニューからコントロールを選択すると、" + "\r\n" + "パネル上の右クリックした際のマウスポインタの先の位置に、選択したコントロールを追加できます。" ; labelOnForm.AutoSize = true; ; labelOnForm.Location = new Point(0, 0); labelOnForm.Parent = this; } private Point cp; // panel上で右クリックをした時の処理 void cms_Opening(object sender, CancelEventArgs e) { ContextMenuStrip menuOnPanel = (ContextMenuStrip)sender; // マウスカーソルの位置を画面座標で取得 Point mp = MousePosition; cp = menuOnPanel.SourceControl.PointToClient(mp); Console.WriteLine(cp); // コンテキストメニューの表示 contextMenuStripOnPanel.Items.Clear(); contextMenuStripOnPanel.Items.Add("ピクチャーボックスを追加"); contextMenuStripOnPanel.Items.Add("テキストボックスを追加"); contextMenuStripOnPanel.Items.Add("ラベルを追加"); contextMenuStripOnPanel.Items[0].Click += PanelMenuItems0_Click; contextMenuStripOnPanel.Items[1].Click += PanelMenuItems1_Click; contextMenuStripOnPanel.Items[2].Click += PanelMenuItems2_Click; // キャンセルをfalseに設定します。(イベントをキャンセルするかどうかの設定) // 空のエントリに基づいてtrueに最適化されます。 e.Cancel = false; //trueにするとコンテキスメニューが表示されない } // // PictureBoxをつくるイベントハンドラ private void PanelMenuItems0_Click(object sender, EventArgs e) { PictureBox pictureBox = new PictureBox(); pictureBox.Location = cp; pictureBox.BackColor = Color.White; pictureBox.Size = new Size(50, 50); pictureBox.Image = Image.FromFile("testPicture.bmp"); pictureBox.Parent = panel; } // // テキストボックスを作るイベントハンドラー private void PanelMenuItems1_Click(object sender, EventArgs e) { TextBox textBox = new TextBox(); textBox.Location = cp; textBox.BorderStyle = BorderStyle.FixedSingle; textBox.Text = "これはテキストボックスです。"; textBox.Multiline=true; textBox.Size = new Size(100, 100); textBox.BackColor = Color.Yellow; textBox.Parent = panel; } // // ラベルを作るイベントハンドラー private void PanelMenuItems2_Click(object sender, EventArgs e) { Label label = new Label(); label.Location = cp; label.BorderStyle = BorderStyle.FixedSingle; label.BackColor = Color.Pink; label.Text = "これはラベルです。"; label.Parent = panel; } } }この画像ファイルは、debugフォルダまたはbinフォルダに置いてください。
- 投稿日:2020-04-14T09:47:22+09:00
TextAssetに対応してない拡張子のファイルをInspectorで設定する
TextAssetは拡張子が特定のものじゃないと許容してくれない
上記によるとTextAssetは
- .txt
- .html
- .htm
- .xml
- .bytes
- .json
- .csv
- .yaml
- .fnt
をサポートしているそうで
今回xLuaというUnityでluaを扱うライブラリのサンプルをみているとluaのファイルの拡張子を.txtにしていた。テキストエディターで開いた際に設定をしなければハイライトなどが適応されないので.luaのままで設定できた方が楽じゃね?と思ったので作ってみました
そこで今回作ったのが.luaを許容するEditor拡張で上のgistで公開しています
xLuaのExample/02_U3DScriptingを変えて
- LuaBehaviour.csのLuaScript変数の型をTextAsset → LuaTextAsset
- LuaTestScript.lua.txt → LuaTestScript.lua
に変更させていますが正しく動いているのがわかります(実行が遅いのは低スペックmacなのでご愛嬌)
中身
LuaTextAsset.cs
LuaTextAsset.csusing System; using System.IO; using System.Text; using UnityEngine; using Object = UnityEngine.Object; #if UNITY_EDITOR using UnityEditor; #endif [Serializable] public class LuaTextAsset { public const string Extension = ".lua"; [SerializeField] private string path; [SerializeField] private string textString; [SerializeField] private string byteString; public string text => textString; public byte[] bytes => Encoding.ASCII.GetBytes(byteString); public static implicit operator TextAsset(LuaTextAsset textAsset) { return new TextAsset(textAsset.textString); } public static implicit operator LuaTextAsset(TextAsset textAsset) { return new LuaTextAsset { textString = textAsset.text }; } } #if UNITY_EDITOR [CustomPropertyDrawer(typeof(LuaTextAsset))] public class LuaInspectorEditor : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { var path = property.FindPropertyRelative("path").stringValue; var loaded = AssetDatabase.LoadAssetAtPath(path, typeof(Object)); var field = EditorGUI.ObjectField(position, label, loaded, typeof(Object), false); var loadPath = AssetDatabase.GetAssetPath(field); var fileExtension = Path.GetExtension(loadPath); if (field == null || fileExtension != LuaTextAsset.Extension) { property.Set("path", ""); property.Set("textString", ""); property.Set("byteString", ""); } else { var pathProperty = property.FindPropertyRelative("path"); property.Set("path", loadPath.Substring(loadPath.IndexOf("Assets", StringComparison.Ordinal))); property.Set("textString", File.ReadAllText(pathProperty.stringValue)); property.Set("byteString", Encoding.ASCII.GetString(File.ReadAllBytes(pathProperty.stringValue))); } } } public static class SerializedPropertyExtension { public static void Set(this SerializedProperty property, string name, string value) { var pathProperty = property.FindPropertyRelative(name); pathProperty.stringValue = value; } } #endif基本的にTextAssetと互換を保ちつつ、TextAssetと同じ変数名で扱えるように設定をしています。今回はluaに限定していますが少し変えれば好きな拡張子で設定が可能になると思います。
- 投稿日:2020-04-14T07:27:50+09:00
WPFのRichTextBoxにBindingする
概要
WPFで単純な文字列ではなく、複数の書式(文字色, Font, etc.)が入り混じった文字表示をしたい場合はRichTextBoxを使用します。
しかし、このRichTextBoxの中身Document
プロパティは依存関係プロパティではないので、そのままではBindingできず、ViewModelから変更できません。そこでこれを解決するためのいくつかの方法を紹介します。
解決方法
デモアプリ
解決方法の具体例として、以下のようなデモアプリを考えます。
1つのRichTextBox内に、文字色と内容が固定の文字列("FixText_")と、ViewModelから文字色と内容が変更される文字列があるとします。このデモアプリでは、各行ごとに以降の方法を使って、ViewModelからRichTextBoxの中身を書き換えています。
方法1 Run内のプロパティ単位でBindingする
そもそもRichTextBoxの中身全体をBindingするのではなくて、その一部だけをBindingしてしまう、という方法です。
Runのプロパティは依存関係プロパティなので、問題なくBindingできます。
表題とはずれますが、ViewModelから変更したい内容が、一部分の文字列だけとかであれば、これで十分でしょう。MainWindow.xaml(部分)<RichTextBox> <FlowDocument> <Paragraph> <Run Text="FixText_" /> <Run FontStyle="Italic" Foreground="{Binding TextColor}" Text="{Binding NormalText}" /> </Paragraph> </FlowDocument> </RichTextBox>MainWindowViewModel.cs(部分)private string _NormalText = "NormalText in VM"; public string NormalText { get => _NormalText; set { _NormalText = value; RaisePropertyChanged(); } }方法2 添付プロパティでFlowDocumentまるごとBindingする
もっと柔軟に、RichTextBoxの中身の
FlowDocument
をまるごと変更したいということであれば、この方法を使用します。
ただしViewModelにゴリゴリのView情報(RichTextBox)が入っているのでMVVM的にはイマイチです。Bindingできない
Document
プロパティにBindingするための添付プロパティを用意します。
この添付プロパティにFlowDocument
がBindingで渡されると、添付対象のRichTextBoxの本来のDocument
プロパティに対して、そのFlowDocument
が設定されます。
その際にFlowDocument
が複数のRichTextBoxに所属するとエラーしてしまうので、必要であればコピーを作成して設定します。public class RichTextBoxHelper : DependencyObject { public static FlowDocument GetDocument(DependencyObject obj) => (FlowDocument)obj.GetValue(DocumentProperty); public static void SetDocument(DependencyObject obj, FlowDocument value) => obj.SetValue(DocumentProperty, value); public static readonly DependencyProperty DocumentProperty = DependencyProperty.RegisterAttached( "Document", typeof(FlowDocument), typeof(RichTextBoxHelper), new FrameworkPropertyMetadata(null, Document_Changed)); private static void Document_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (!(d is RichTextBox richTextBox)) return; var attachedDocument = GetDocument(richTextBox); //FlowDocumentは1つのRichTextBoxにしか設定できない。 //すでに他のRichTextBoxに所属しているなら、コピーを作成・設定する richTextBox.Document = attachedDocument.Parent == null ? attachedDocument : CopyFlowDocument(attachedDocument); } private static FlowDocument CopyFlowDocument(FlowDocument sourceDoc) { //もとのFlowDocumentをMemoryStream上に一度Serializeする var sourceRange = new TextRange(sourceDoc.ContentStart, sourceDoc.ContentEnd); using var stream = new MemoryStream(); XamlWriter.Save(sourceRange, stream); sourceRange.Save(stream, DataFormats.XamlPackage); //新しくFlowDocumentを作成 var copyDoc = new FlowDocument(); var copyRange = new TextRange(copyDoc.ContentStart, copyDoc.ContentEnd); //MemoryStreamからDesirializeして書き込む copyRange.Load(stream, DataFormats.XamlPackage); return copyDoc; } }この添付プロパティをRichTextBoxに対して使用します。
MainWindow.xaml(部分)<RichTextBox local:RichTextBoxHelper.Document="{Binding Document}" />ViewModelではコードでFlowDocumentを組み立てます。
MainWindowViewModel.cs(部分)private FlowDocument _Document = CreateFlowDoc("FlowDocument in VM"); public FlowDocument Document { get => _Document; set { _Document = value; RaisePropertyChanged(); } } private static FlowDocument CreateFlowDoc(string innerText) { var paragraph = new Paragraph(); paragraph.Inlines.Add(new Run("FixText_")); paragraph.Inlines.Add(new Run(innerText) { Foreground = new SolidColorBrush(Colors.BlueViolet) }); return new FlowDocument(paragraph); }方法3 添付プロパティとConverterで柔軟にBindingする
柔軟に変更したいが、ViewModelにViewの情報を入れたくない・適度に抽象化したい、という場合はこの方法です。
まず、RichTextBoxの
Document
に対応するViewModelクラスを作成します。
ここでは色と文字列だけ変更するとします。public class RichTextViewModel { public string Text { get; set; } public Color Color { get; set; } }それをMainWindowViewModelではプロパティとして公開します。
MainWindowViewModel.cs(部分)private RichTextViewModel _RichVM = new RichTextViewModel() { Text = "Original Text in VM", Color = Colors.Indigo }; public RichTextViewModel RichVM { get => _RichVM; set { _RichVM = value; RaisePropertyChanged(); } }このプロパティをそのままBindingすることはできませんので、ViewModel→FlowDocumentへの変換のためのConverterを作成します。
public class RichTextVmToFlowDocumentConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (!(value is RichTextViewModel richVM)) return Binding.DoNothing; var paragraph = new Paragraph(); paragraph.Inlines.Add(new Run("FixText_")); paragraph.Inlines.Add(new Run() { Text = richVM.Text, Foreground = new SolidColorBrush(richVM.Color), FontStyle = FontStyles.Italic, }); return new FlowDocument(paragraph); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }このConverterと方法2の添付プロパティを使用して、ViewModelのプロパティとBindingします。
MainWindow.xaml(部分)<RichTextBox local:RichTextBoxHelper.Document="{Binding RichVM, Converter={StaticResource RichTextVmToFlowDocumentConverter}}" />デモアプリコード全体
デモアプリのコード全体はGithubにおいておきます。
https://github.com/soi013/RichTextBoxBinding
注意点
Viewからの変更をViewModelで取得するのは難しいです。基本的に
OneWay
のみ。
方法2で、内部でFlowDocument
がコピーされていなければViewModel側にも反映されていますが、Document
プロパティ自体は変更されていないので、変更通知などは発生しません。参考
https://stackoverflow.com/questions/343468/richtextbox-wpf-binding
https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.richtextbox?view=netframework-4.8
環境
VisualStudio2019
.NET Core 3.1
C#8
- 投稿日:2020-04-14T06:04:01+09:00
【Unity初心者】関数(メソッド)って何?
環境
Unity 2019.3.7f1
はじめに
メソッドは日本語でいうと関数
なかなか馴染みがない言葉ですよね。
今回は概略を説明していきます。関数(メソッド)とは?
関数とは処理をまとめたものです。
ざっくり図にするとこんな感じです。
そして、大きくわけると次の2つに分かれます。
・C#やUnity側であらかじめ処理内容が用意されている関数
・自分で処理内容を決める関数
さらに返り値の有無、引数の有無で細分化されていきます。
下図が関数の分類と使い方になります。(イベント関数は使い方が特殊なので別で書きました。)
全11種類です!(多いわ!)
1.用意されている関数-返り値有-引数必要
2.用意されている関数-返り値有-引数不要
3.用意されている関数-返り値無-イベント関数-引数必要
4.用意されている関数-返り値無-イベント関数-引数不要
5.用意されている関数-返り値無-引数必要
6.用意されている関数-返り値無-引数無-①
7.用意されている関数-返り値無-引数無-②
8.自作の関数-返り値有-引数有
9.自作の関数-返り値有-引数無
10.自作の関数-返り値無-引数有
11.自作の関数-返り値無-引数無関数を使うと具体的に何ができるの?
大分類2種類でそれぞれ説明
C#やUnity側であらかじめ処理内容が用意されている関数
スクリーンサイズを取得したり、変数の値をコンソールに表示したり様々なことができます。関数の種類については非常にたくさんありますので、
詳細はkimamaさんのサイトを参考にして下さい。↓
http://kimama-up.net/unity-functions-application/自分で処理内容を決める関数
if文や四則演算やfor文などの自分のやりたい処理をひとまとめにすることができます。
・何回も同じコードを書かなくて良い
・コードが見やすくなる
といったメリットがあります。使い方をちゃんと説明してよ
全11種類の関数の使い方、自作関数の作り方については今後記事作成していきます。
- 投稿日:2020-04-14T04:48:48+09:00
メモ:C#でregeditからコピーしたバイナリを受け取る
regeditからバイナリをコピーしてきてC#でデコードしたりするときに、クリップボードを経由できるとちょっと便利。
バイナリの編集画面からコピーすると"RegEdit_HexData"形式でクリップボードに入る。IDataObject経由で取り出して、GetFormatsでこのフォーマットが含まれているか確認して、GetDataで取り出す。取り出したデータはMemoryStreamなので、キャストしてバッファにコピーする。
今回は全体を取り出したが、バッファの先頭4バイトに32bitLEで長さが入っているらしいので、最初に4バイト取り出して長さを得る、もしくは最初の4バイトを読み捨てる、といった処理をやっても良さそう。const string format = "RegEdit_HexData"; IDataObject clipboardObj = Clipboard.GetDataObject(); if (!clipboardObj.GetFormats().Contains(format)) { throw new Exception("ひたいおうのけいしき!!"); } byte[] buff; using (MemoryStream ms = (MemoryStream)clipboardObj.GetData(format)) { buff = new byte[ms.Length]; ms.Read(buff, 0, buff.Length); } int length = BitConverter.ToInt32(buff, 0);そもそもMicrosoft.Win32.Registry使えって話なんだが(結局それ経由で取り出すようにしたのでClipboard経由は不要になったんだが、せっかく方法を調べたので捨てるにしのびなくメモ)。
- 投稿日:2020-04-14T02:13:33+09:00
InputSystemでPress Any Keyを作る
概要
PC向けのゲームを真面目に作ろうとすると、キーボード、ゲームパッド、マウス他の対応。
特に全部に対応したタイトル画面のPress Any Keyを作るのが面倒くさいですよね。
各デバイスごとの決定キーだけ対応させるっていう手抜きもありえますが、新しいInputSystemなら取得に必要なコードは実質1行!
おそらくゲームパッド上のメニューボタンなどにも反応してしまうので使う場合はお気をつけて環境
2019.3.6f1
ソース
public class TitleManager : MonoBehaviour { private InputAction _pressAnyKeyAction = new InputAction(type: InputActionType.PassThrough, binding: "*/<Button>", interactions: "Press"); private void OnEnable() => _pressAnyKeyAction.Enable(); private void OnDisable() => _pressAnyKeyAction.Disable(); void Update() { if(_pressAnyKeyAction.triggered) { //シーン読み込み、アニメーション読み込みなどなど } } }