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

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

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

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

Q&A

解決済

2回答

6070閲覧

ListViewで選択したセルの内容を書き換えたい

otaota

総合スコア30

Xamarin

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

0グッド

0クリップ

投稿2017/06/09 01:55

編集2017/06/09 08:07

###前提・実現したいこと
ListViewで選択したセルの内容を後から書き換えたいと思っているのですが、書き換えたいLabelへのアクセス方法がわからず困っています。アドバイスお願いします。

たとえば、Item1と書いてるセルを選択すると表示しているラベルの頭に1文字追加(@Item1)され、さらに選択するとさらにもう1文字(@@Item1)追加されるということをしたいです。

###該当のソースコード

using System; using System.Diagnostics; using System.Collections.Generic; using Xamarin.Forms; namespace XaCurry { public class Test2Page : ContentPage { public Label label; public Test2Page() { var ar = new List<MyCell>(); for (var i = 0; i < 5; i++) { ar.Add(new MyCell { No = i, Text = "Item" + i, }); } var listItems = new ListView { ItemsSource = ar, }; listItems.ItemTemplate = new DataTemplate(() => { var no = new Label(); no.SetBinding(Label.TextProperty, "No"); var text = new Label(); text.SetBinding(Label.TextProperty, "Text"); return new ViewCell { View = new StackLayout { Padding = new Thickness(20, 10, 20, 10), Spacing = 10, Orientation = StackOrientation.Horizontal, Children = { no, text, }, }, }; }); listItems.ItemSelected += async (sender, e) => { bool flag = await DisplayAlert("Alert Title", e.SelectedItem + " is selected.", "OK", "Cancel"); if (flag) { // ここで選択したセル内のラベルを書き換えたい } }; label = new Label { Text = "Label", }; var button = new Button { Text = "Button", }; button.Clicked += (sender, e) => { Navigation.PushAsync(new Test3Page(this)); }; Content = new StackLayout { Children = { listItems, label, button, } }; } } public class MyCell { public int No { get; set; } public string Text { get; set; } } public class Test3Page : ContentPage { public Test3Page(Test2Page test2) { var button = new Button { Text = "change", }; button.Clicked += (sender, e) => { test2.label.Text = "change"; }; Content = new StackLayout { Children = { button, } }; } } }

###試したこと
おそらく、listItems.ItemSelected時の処理の中で
sender または e または listItemsあたりからたどれそうな気はするのですが、自力ではわかりませんでした。

実際は、button, label, Test3Pageでやっているようにbuttonを押すと次のページへ遷移し、遷移したページの操作によって、親のページの内容が変わっているということをしたいのですが、上記のアクセス方法がわかればそこは解決できると思っています。

###補足情報(言語/FW/ツール等のバージョンなど)
Xamarin 6.3(build 864)
Mac Note Pro
OS X Yosemite(10.10.5)

###追記コード

using System; using System.Diagnostics; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using Xamarin.Forms; namespace XaCurry { public class Test2Page : ContentPage { public Test2Page() { var ar = new List<MyCell>(); for (var i = 0; i < 5; i++) { ar.Add(new MyCell { No = i, Text = "Item" + i, }); } MakePage(ar); } public void MakePage( List<MyCell> ar ) { var listItems = new ListView { ItemsSource = ar, }; listItems.ItemTemplate = new DataTemplate(() => { var no = new Label(); no.SetBinding(Label.TextProperty, "No"); var text = new Label(); text.SetBinding(Label.TextProperty, "Text"); return new ViewCell { View = new StackLayout { Padding = new Thickness(20, 10, 20, 10), Spacing = 10, Orientation = StackOrientation.Horizontal, Children = { no, text, }, }, }; }); listItems.ItemSelected += async(sender, e) => { bool flag = await DisplayAlert("Alert Title", e.SelectedItem + " is selected.", "OK", "Cancel"); if (flag) { // ここで選択したセル内のラベルを書き換えたい var i = ar.IndexOf(((MyCell)e.SelectedItem)); ar[i].Text = "@" + ar[i].Text; MakePage(ar); } }; Content = new StackLayout { Children = { listItems, } }; } } public class MyCell { public int No { get; set; } public string Text { get; set; } } }

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

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

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

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

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

guest

回答2

0

ベストアンサー

リストのアイテムのクラス MyCell にインターフェイス INotifyPropertyChanged を実装すれば MyCell.Text の変更がラベルのテキストまで伝わるのではないでしょうか。

c#

1public class MyCell : INotifyPropertyChanged 2{ 3 private string _text; 4 public string Text 5 { 6 get { return _text; } 7 set 8 { 9 if (_text != value) 10 { 11 _text = value; 12 OnPropertyChanged("Text"); 13 } 14 } 15 } 16 17 public event PropertyChangedEventHandler PropertyChanged; 18 19 protected void OnPropertyChanged(string propertyName) 20 { 21 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 22 } 23 //...

c#

1listView.ItemSelected += async (sender, e) => 2{ 3 var item = (MyCell)e.SelectedItem; 4 var flag = await DisplayAlert("Alert Title", item.Text + " is selected.", "OK", "Cancel"); 5 if (flag) 6 { 7 item.Text = "@" + item.Text; 8 } 9};

投稿2017/06/11 05:17

NakamuraYoichi

総合スコア374

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

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

otaota

2017/06/12 03:36

(コメント書いたつもりがうまく登録されていないのでもう一度書きます) 回答ありがとうございます。 勉強不足で何をしているのかが100%理解できるわけではないですが、 試してみたところ、やりたいことが実現できました。 とくに、この方法だとリストやページを作り直すわけではないので、スクロール位置がリセットされないのがいいですね。 C/C++の延長でC#を使っている私には、 PropertyChanged?.Invoke の部分が文法的に???だったので、調べてみたところ、もう少し簡単な書き方もできることが分かったので念のため添付しておきます。 ``` public class MyCell : INotifyPropertyChanged { private string text; public int No { get; set; } public string Text { get { return text; } set { if (text != value) { text = value; PropertyChanged(this, new PropertyChangedEventArgs("Text")); } } } public event PropertyChangedEventHandler PropertyChanged = delegate { }; } ```
guest

0

こんにちは。

e.SelectedItemはセルに指定したクラスのオブジェクトが取れるので、
((MyCell)e.SelectedItem).Name みたいにキャストしてプロパティを取ってこれたはずです。

コメントを見て、回答を以下にアップデートします。


ListViewからではなく、ItemsSourceに指定しているコレクションarを直接操作することになるかと思います。

List<MyCell> ar をフィールドにして、該当のメソッド内で

csharp

1var i = ar.IndexOf(((MyCell)e.SelectedItem)); 2ar[i].Text = "changed";

とすると取り敢えずプロパティを書き換えることはできるんですが、ListView自体の書き換えが必要になってしまいます。Xamarin.FormsのListViewにはCollectionChangedを受け取って自動で表示を更新する機能があります。そのため、通常はList<T>の代わりに内容が変わるとCollectionChangedを発火してくれるObservabaleCollection<T>を使用します。

ところが、今回やっているのはプロパティの変更なので、CollectionChangedではなく、PropertyChangedが発火してしまい、CollectionChangedが発火しません。

これらを回避して簡単そうな方法だと、

  1. フィールドObservableCollection<MyCell> ar;を作成
  2. コレクションを一時的なコレクションに格納して
  3. インデックスを指定して値を書きかえ
  4. 元のコレクションをクリアして(←この時点でCollectionChangedが発火(するはず))
  5. 一時的なコレクションから全データを元のコレクションに流し込む(←この時点でもCollectionChangedが発火)

という感じになるかと思います。

csharp

1var tempList = ar.Select(x => x).ToList(); 2var i = tempList.IndexOf(((MyCell)e.SelectedItem)); 3tempList[i].Text = "changed"; 4ar.Clear(); 5foreach (var item in tempList) 6{ 7 ar.Add(new MyCell { No = item.No, Text = item.Text }); 8}

他にもステキな書き方があるかと思いますので、他の方からの回答を待っても良いかと。


投稿2017/06/09 03:25

編集2017/06/09 07:16
ytabuchi

総合スコア335

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

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

otaota

2017/06/09 03:32

回答ありがとうございます。 値を取得するだけならばそれで大丈夫なのですが、表示を変えるにはおそらくLabelクラスのTextを書き換える必要があり、そのLabelクラスへのたどり着き方のところで詰まってしまっています。
ytabuchi

2017/06/09 07:09

ListViewからではなく、ItemsSourceに指定しているコレクションarを直接操作することになるかと思います。 `List<MyCell> ar` をフィールドにして、該当のメソッド内で ```csharp var i = ar.IndexOf(((MyCell)e.SelectedItem)); ar[i].Text = "changed"; ``` とすると取り敢えずプロパティを書き換えることはできるんですが、ListView自体の書き換えが必要になってしまいます。Xamarin.Formsの`ListView`には`CollectionChanged`を受け取って自動で表示を更新する機能があります。そのため、通常は`List<T>`の代わりに内容が変わると`CollectionChanged`を発火してくれる`ObservabaleCollection<T>`を使用します。 ところが、今回やっているのはプロパティの変更なので、`CollectionChanged`ではなく、`PropertyChanged`が発火してしまい、`CollectionChanged`が発火しません。 これらを回避して簡単そうな方法だと、 1. フィールド`ObservableCollection<MyCell> ar;`を作成 1. コレクションを一時的なコレクションに格納して 1. インデックスを指定して値を書きかえ 1. 元のコレクションをクリアして(←この時点でCollectionChangedが発火(するはず)) 1. 一時的なコレクションから全データを元のコレクションに流し込む(←この時点でもCollectionChangedが発火) という感じになるかと思います。 ```csharp var tempList = ar.Select(x => x).ToList(); var i = ar.IndexOf(((MyCell)e.SelectedItem)); tempList[i].Text = "changed"; ar.Clear(); foreach (var item in tempList) { ar.Add(new MyCell { No = item.No, Text = item.Text }); } ``` 他にもステキな書き方があるかと思いますので、他の方からの回答を待っても良いかと。
ytabuchi

2017/06/09 07:09

あれー?コメントではMarkdown使えないのか。 元の回答に追記しますね。
otaota

2017/06/09 08:13

再度回答ありがとうございました。 内部のイベントがいつ発火するか理解していないと難しいんですね。 とりあえず頂いたコードで選択したセルの表示がかわることを確認しました。 リスト全体を作り直す感じなのですね。もっと簡単な話だと思っていました。 回答を見て、昔リストを作り直さなければならなかったケースを思い出したので、 それを元に自分なりにもひとつ答えを出してみました。(元の質問のところの追記コード) Content自体を再設定しているのですが、これだと力技すぎますでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

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

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

質問する

関連した質問