オリジナルコントロールを作成する
Xamarinでオリジナルコントロールを作成する場合、
ContentViewを継承して作成します。
例えば以下のように実装すると、オリジナルコントロールを作成できます。
MyEntry.xaml
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinSample.Views.Controls.MyEntry">
<ContentView.Content>
<StackLayout>
<Label x:Name="label"
HorizontalOptions="FillAndExpand" />
<Entry x:Name="entry"
HorizontalOptions="FillAndExpand" />
</StackLayout>
</ContentView.Content>
</ContentView>
MyEntry.xaml.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MyEntry : ContentView
{
public MyEntry()
{
InitializeComponent();
}
}
作成したコントロールを独自クラスからしようする場合は、
xmlnsを指定して実装したクラスを記載するだけ。
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
xmlns:cont="clr-namespace:XamarinSample.Views.Controls"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="XamarinSample.Views.MainPage"
Title="MainPage">
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<cont:MyEntry />
</StackLayout>
</ContentPage>
ViewModelからBindingできるようにする
作成したコントロールにBindingPropertyを追加すると、ViewModelで変更が通知されるようになります。
MyEntry.xaml.cs
/// <summary>
/// Text
/// </summary>
public static readonly BindableProperty ValueProperty =
BindableProperty.Create(
nameof(Value),
typeof(string),
typeof(MyEntry),
string.Empty,
propertyChanged: (bindable, oldValue, newValue) => {
((MyEntry)bindable).Value = (string)newValue;
},
defaultBindingMode: BindingMode.TwoWay
);
public string Value
{
get { return (string)GetValue(ValueProperty); }
set
{
SetValue(ValueProperty, value);
entry.Text = (string)GetValue(ValueProperty);
label.Text = (string)GetValue(ValueProperty);
}
}
MainPageViewModel.cs
public class MainPageViewModel : BindableBase, INavigationAware
{
private string _title;
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
private string _value;
public string Value
{
get { return _value; }
set { SetProperty(ref _value, value); }
}
public MainPageViewModel()
{
Value = "First";
}
}
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
xmlns:cont="clr-namespace:XamarinSample.Views.Controls"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="XamarinSample.Views.MainPage"
Title="MainPage">
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<cont:MyEntry Value="{Binding Value}"/>
</StackLayout>
</ContentPage>
実行してみると、ViewModelから、Viewへのバンディングは成功している。
しかし入力ボックスを変更してみると。。。
テキスト部分しか変わらず、バインディングがうまくいっていない。。。
以下を参考にすると、どうやらオリジナルコントロールのViewとViewModelもバインディングする必要があるらしい。
そこで参考に独自コントロールを編集する。
MainPage.xaml
<?xml version="1.0" encoding="UTF-8"?>
<ContentView x:Name="this"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinSample.Views.Controls.MyEntry">
<ContentView.Content>
<StackLayout>
<Label x:Name="label"
Text="{Binding Source={x:Reference this},Path=Value}"
HorizontalOptions="FillAndExpand" />
<Entry x:Name="entry"
Text="{Binding Source={x:Reference this},Path=Value}"
HorizontalOptions="FillAndExpand" />
</StackLayout>
</ContentView.Content>
</ContentView>
MyEntry.xaml.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MyEntry : ContentView
{
#region Binding Propterty
/// <summary>
/// Text
/// </summary>
public static readonly BindableProperty ValueProperty =
BindableProperty.Create(
nameof(Value),
typeof(string),
typeof(MyEntry),
string.Empty,
propertyChanged: (bindable, oldValue, newValue) => {
((MyEntry)bindable).Value = (string)newValue;
},
defaultBindingMode: BindingMode.TwoWay
);
public string Value
{
get
{
return (string)GetValue(ValueProperty);
}
set
{
SetValue(ValueProperty, value);
}
}
#endregion
public MyEntry()
{
InitializeComponent();
}
}
きちんとView側からViewModelに通知されていることがわかる。
これを解決するのに、何時間かかったことなのか。。。