質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.51%
Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

Q&A

1回答

4790閲覧

XamarinFormsのデータバインディングがうまく反映されません

kamingout

総合スコア44

Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

0グッド

0クリップ

投稿2017/06/09 16:39

編集2022/01/12 10:55

XamarinFormsのデータバインディングがうまくいきません。

下記のリンク先の情報をもとにXamarinFormsにてデータバインディングをしようとしています。
こちら

以下のようにINotifyPropertyChangedを派生したクラスを生成しました。

lang

1public class CClass : INotifyPropertyChanged 2 { 3 // INotifyPropertyChangedインターフェイスの実装 4 public event PropertyChangedEventHandler PropertyChanged = delegate { }; 5 6 // Fields 7 int count; 8 9 // コンストラクタ 10 public CClass() 11 { 12 count = 0; 13 time = 0; 14 } 15 16 // Properties 17 public int Counter 18 { 19 get 20 { 21 return this.count; 22 } 23 set 24 { 25 if (this.count != value) 26 { 27 this.count = value; 28 PropertyChanged(this, new PropertyChangedEventArgs("Counter")); 29 //OnPropertyChanged("Counter"); 30 31 } 32 } 33 } 34 35 // プロパティ値の変更を通知します 36 protected virtual void OnPropertyChanged(string propertyName) 37 { 38 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 39 } 40 }' 41 42

次に、xamlにて、データバインディングされるようにラベルを以下のように定義しました。

lang

1 <Label Text="{Binding Counter, Mode = TwoWay, StringFormat='{0}'}" 2 x:name="CountLabel" 3 BackgroundColor="Aqua" 4 HorizontalTextAlignment="Start" 5 VerticalTextAlignment="Center"/>

ボタンが押された後にCounterプロパティを1秒ごとにインクリメントするようなコードにしているのですが
画面のLabel値が更新されません。

デバッグでソースを追ったところ、Counterの値は更新されていますし、描画の更新には
Device.BeginInvokeOnMainThreadを使用しているので問題ありません。
※コード上でCountLabel.Textの値を更新した場合は反映されていました。

何が原因と考えられますでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

こんにちは

提示されているコードを見る限りではLabelの表示は更新されるかと思います。

原因は提示されているコード以外の部分にあるように思えるのですが、如何でしょうか。
(例えば、1秒毎にインクリメントしているのがフィールド変数のcountだったりとか…)

cs

1 public class CClass : INotifyPropertyChanged 2 { 3 public ICommand StartTimerCommand { get; } 4 5 public event PropertyChangedEventHandler PropertyChanged = delegate { }; 6 7 int count; 8 9 public CClass() 10 { 11 StartTimerCommand = new Command(() => 12 { 13 Device.StartTimer( 14 TimeSpan.FromSeconds(1), 15 () => { Counter++; return true; }); 16 }); 17 } 18 19 public int Counter 20 { 21 get 22 { 23 return this.count; 24 } 25 set 26 { 27 if (this.count != value) 28 { 29 this.count = value; 30 OnPropertyChanged("Counter"); 31 } 32 } 33 } 34 35 protected virtual void OnPropertyChanged(string propertyName) 36 { 37 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 38 } 39 }

xaml

1<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 2 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 3 xmlns:local="clr-namespace:App1" 4 x:Class="App1.MainPage"> 5 <ContentPage.BindingContext> 6 <local:CClass /> 7 </ContentPage.BindingContext> 8 9 <StackLayout VerticalOptions="Center"> 10 <Label Text="{Binding Counter, Mode = TwoWay, StringFormat='{0}'}" 11 x:name="CountLabel" 12 BackgroundColor="Aqua" 13 HorizontalTextAlignment="Center" 14 VerticalTextAlignment="Center"/> 15 16 <Button Text="Start" 17 Command="{Binding StartTimerCommand}" 18 VerticalOptions="Center" 19 HorizontalOptions="Center" /> 20 </StackLayout> 21 22</ContentPage>

投稿2017/06/09 18:02

編集2017/06/10 02:03
yamamo

総合スコア37

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kamingout

2017/06/09 23:39

Counterプロパティをインクリメントすることで、 フィールド変数のcountをインクリメントしていますが、何か問題はありますか?
yamamo

2017/06/10 02:01

Counter++ で問題ありません。 実際に動かしてみたコードを追記しておきますね。
kamingout

2017/06/11 09:31

御回答ありがとうございます。 上記のコードと自分のコードの異なる点は、StartTimerCommand内でCounter++しているか、Button押下後に別スレッドを立ち上げてそのスレッドないでループを回しているかの違いだけな気がするのですが、、、 yamamoさんのxamlには、 x:name="CountLabel"という名前付けがされているのですが、これはデータバインディングに必要なのでしょうか?
kamingout

2017/06/11 09:40

あと、以下のようにメインスレッドでCClassをcreateし、そのクラス上のプロパティをインクリメントしているのですが、それに原因があるとは考えられますか? CClass cClass; public MainPage() { InitializeComponent(); } private void OnClicked(object sender, EventArgs e) { cClass = new CClass(); var task = Task.Run(() => { DoWork(); }); } public void DoWork() { int i = 0; while (i < 100000) { cClass.Counter++; Device.BeginInvokeOnMainThread(() => { cClass.Counter++; }); i++; } }
yamamo

2017/06/11 10:03

CClassのインスタンスとMainPage(もしくはLabel)をバインドしてないのではないでしょうか? cClass = new CClass(); this.BindingContext = cClass; ←これ 今のプログラムの構造を変えずに簡単に解決するのであれば、上記の1行を加えるだけで動くと思われます。
kamingout

2017/06/11 17:55

ご返信ありがとうございます。 そして上記の1行を加えたらうまくいきました。 クラス定義時点でINotifyPropertyChangedを派生しているため、CounterはBindingプロパティとなっていると思うのですが、なぜこの1行は必要なのでしょうか?
yamamo

2017/06/11 18:50

「Text="{Binding Counter}"」は見ての通りCounterプロパティを指定しているだけなので、Labelは誰のCounterプロパティの値を取得するか分かりませんよね。 クラスやインスタンスについてもう少し理解を深めてみては如何でしょうか。
kamingout

2017/06/12 14:15

ご返信ありがとうございます。 なぜ上記の1行が必要なのかわかりました。大変参考になりました。 もう少し自分でいろいろ調べて理解を深めようと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問