できるの? どうやるの?
対象環境
- 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でイベント駆動だったらやり方がすぐにわかるのに。