できるの? どうやるの?
対象環境
- Raspbierry pi 3 Model B+
- Raspbian stretch(9.0) 2018-06-27
- Mono 5.16.0
- MonoDevelop 7.6 build 711
- Eto.Forms 2.4.1 拡張機能, NuGetパッケージ
前回
- http://ytyaru.hatenablog.com/entry/2020/01/29/000000
- http://ytyaru.hatenablog.com/entry/2020/01/28/000000
- http://ytyaru.hatenablog.com/entry/2020/01/27/000000
- http://ytyaru.hatenablog.com/entry/2020/01/26/000000
- http://ytyaru.hatenablog.com/entry/2020/01/25/000000
- http://ytyaru.hatenablog.com/entry/2020/01/24/000000
手順
- プロジェクト作成
- TextBox追加
- 実行
1. プロジェクト作成
- メニュー→
ファイル
→新しいソリューション
マルチプラットフォーム
→アプリ
→Eto Application
- 名前などを適当に入力し、
Xaml
を選択する
場所
を入力する
- プロジェクトが作成される
2. TextBox追加
- Xamlファイルを開く(MainForm.xeto)
<TextBox x:Name="textBox1" Text="https://www.google.co.jp" Width="800" KeyDown="HandleInputUrl" />
を追記する- csファイルを開く(MainForm.xeto.cs)
HandleInputUrl
メソッドを追加する
ソースコード抜粋
MainForm.xeto
空っぽにする。データバインディングはC#でしか実装できないので、それに引きづられてすべてC#で実装することになる。XAMLとは一体……。MVVMとは一体……。全然M,V,Cが分離できてなくね?
<?xml version="1.0" encoding="UTF-8"?> <Form xmlns="http://schema.picoe.ca/eto.forms" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="My Eto Form" ClientSize="800, 600" Padding="10"> <StackLayout> <!-- <TextBox x:Name="textBox1" Width="800" Text="{Binding Url}" /> <WebView Width="800" Height="600" Url="{Binding Url}" /> --> </StackLayout> </Form>
{Binding Url}
とすればバインディングできるようだが、今回は型が違うためか実行すると強制終了される。
- Text.Text: String型
- WebView.Url: Uri型
この型変換をする方法をどうやってXAMLで実装するのか。そもそもできるのか。公式にあるData-Bindingでは、一切XAMLが出てこなかった。仕方ないのでコードだけで書く。
UrlModel.cs
モデルクラス。前回はString型だったが、今回はWebView.Urlの型にあわせてUri型にした。
using System; using System.ComponentModel; // INotifyPropertyChanged using System.Runtime.CompilerServices; // CallerMemberName namespace HelloXamlBinding { public class UrlModel : INotifyPropertyChanged { //public string url; //public string Url { get { return url; } set { this.url = value; OnPropertyChanged(); } } Uri url; public Uri Url { get { return url; } set { this.url = value; OnPropertyChanged(); } } void OnPropertyChanged([CallerMemberName] string memberName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(memberName)); } public event PropertyChangedEventHandler PropertyChanged; } }
MainForm.xeto.cs
色々試してみたが、連動できなかった。モデルとTextBoxは連動したが、WebViewとは連動できず。どうやるのさ?
using System; using System.Collections.Generic; using Eto.Forms; using Eto.Drawing; using Eto.Serialization.Xaml; namespace HelloXamlBinding { public class MainForm : Form { public MainForm() { XamlReader.Load(this); Create(); //var model = new UrlModel { Url = new Uri("https://www.google.co.jp") }; //DataContext = model; //textBox1.TextBinding.BindDataContext( // Binding.Property((MyModel m) => m.MyEnum) // .Convert(r => r.ToString(), v => (MyEnum)Enum.Parse(typeof(MyEnum), v)) //); } private void Create() { Width = 800; Height = 600; var textBox = new TextBox() { Width = 800 }; var webView = new WebView() { Width = 800, Height = 600 }; //textBox.TextBinding.BindDataContext((UrlModel m) => m.Url.ToString()); Content = new StackLayout { Items = {textBox, webView} }; var model = new UrlModel { Url = new Uri("https://www.google.co.jp") }; textBox.TextBinding.BindDataContext( Binding.Property((UrlModel m) => m.Url) .Convert(r => r.ToString(), v => new Uri(v)) ); //webView.BindDataContext((UrlModel m) => m.Url, (UrlModel m) => m.Url); //webView.BindDataContext( // Binding.Property((UrlModel m) => m.Url) // .Convert(r => r.ToString(), v => new Uri(v)) //); //textBox.TextBinding.BindDataContext( // Binding.Property((UrlModel m) => m.Url) // .Convert(r => r.ToString(), v => new Uri(v)) // //.Convert(r => r.ToString(), v => new Uri(v)) //); //model.PropertyChanged += (object sender, System.ComponentModel.PropertyChangedEventArgs e) => //{ // webView.Url = (e as UrlModel).Url; //}; //webView.Bind(c => c.Enabled, model, m => m.Url); DataContext = model; } } }
3. 実行
- Ctrl+F5で実行
- 怒られた
- ファイルパスを辿ってexeファイルを直接叩くと実行できた
なお、値が変化したとき、URLでない文字列だと例外が発生して強制終了する。1文字でも変化すると発生してしまうので、一発で有効なURLを入力する必要がある。これを回避するためにはテキストボックスで全選択し、https://www.yahoo.co.jp
など有効なURLをペーストする。
所感
WPFならIValueConverterとか使うみたいだけど、Eto.Formsには無いっぽい。公式によるとConvert()
を使うっぽいが、どうやって今回の要件を実装するのかわからん。それっぽいコードは書いたつもりだけど、なんか間違ってる?
あとWebViewのバインドってどうやるの? XAMLならUrl="{BInding Url}"
とやれば書けるのだが、型変換を実装する方法がわからん。TextBoxにはTextBinding()
があったので、WebViewにはUrlBinding()
みたいのがあることを期待してたんだけど無い。Bind()
はbool
型じゃないとダメとか怒られるし。
もうEto.FormsでMVVMプログラミングできる気がしない。やりたいことをどうやるのか、情報が見つけられない。MVCでイベント駆動だったらやり方がすぐにわかるのに。