雷って幻想的だよね?

宗教:C#、ラノベ好きの戯言です。

Xamarin.Androidで更新されたテキストを内部データに連携する方法(外部のMVVMなどを利用しない方法)

Xamarin.Androidで更新されたテキストを内部データに連携する方法
で、かなり詰まったので、同じ人がいないようにとの願いのメモです。

初心者なので、ご指摘あればいただけるとうれしいです。

最後に、クラス全体を載せていますので、説明が不要な方はそちらをご覧ください。

【手順】

  1. BeforeTextChangedでテキスト変更開始を検知
  2. TextChangedで変更することを確定させる
  3. AfterTextChangedで上記を満たした場合に、変更とみて更新を行う
    ※ただし、複数回流れることがあります。
  4. 保存時の動作
    1. フォーカスがある場合のみの保存とする(しないとなんかすごく更新がかかる。恐らくなんか実装が変)
    2. GetViewで保存した、EditTextに紐づけたタグ情報を元に対象のデータを特定
    3. 更新する。
    4. isEdittingはActivityで、保存ボタンを押したときにこのフラグを基準に1度のみ保存動作をさせるため指定

動作したAdapterのまとめです。

public class ListItemDetailAdapter : BaseAdapter<ViewArticleItem>
{
#region メンバ変数
private Activity _activity;
private List<ViewArticleItem> _items;
private DbContext dbContext;
/// <summary>
/// EditTextを変更したかどうか
/// </summary>
private bool isEditting = false;
#endregion

#region 必須処理

public ListItemDetailAdapter(Activity activity, List<ViewArticleItem> items)
{
this._activity = activity;
this._items = items;
dbContext = Common.ConnectDB.GetDBContext();
}

public override long GetItemId(int position) => position;


public override View GetView(int position, View convertView, ViewGroup parent)
{
View view = convertView ?? _activity.LayoutInflater.Inflate(Resource.Layout.ListItemDetailLayout, null);

//対応するプロパティの割り当て
EditText editText = view.FindViewById<EditText>(Resource.Id.editText);
ViewArticleItem item = _items[position];
editText.Text = item.Text;
setTagItemId(editText, item.ItemId);
SetEditEvent(editText);

return view;
}

public override int Count => _items.Count;
public override ViewArticleItem this[int position] => throw new NotImplementedException();

#endregion

#region タグ:ItemIdを設定する

private void setTagItemId(EditText editText, int itemId)
{
editText.SetTag(Resource.Id.editText, itemId);
}

private int getTagItemId(EditText editText)
{
return (int)editText.GetTag(Resource.Id.editText);
}

#endregion

#region イベント処理

private void SetEditEvent(EditText editText)
{
//重複しないようにイベント削除
editText.TextChanged -= EditTextOnTextChanged;
editText.BeforeTextChanged -= EditTextOnBeforeTextChanged;
editText.AfterTextChanged -= TextViewOnAfterTextChanged;
editText.FocusChange -= EditTextOnFocusChange;

//イベント再登録
editText.TextChanged += EditTextOnTextChanged;
editText.BeforeTextChanged += EditTextOnBeforeTextChanged;
editText.AfterTextChanged += TextViewOnAfterTextChanged;
editText.FocusChange += EditTextOnFocusChange;
}

/// <summary>
/// フォーカスが変わった場合
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void EditTextOnFocusChange(object sender, View.FocusChangeEventArgs e)
{
if (isEditting)
{
//変更時にデータを保存する
dbContext.SaveViewArticleItems(GetArticleItems());
DebugMessage.ShowDebugToastShort(Application.Context, "Itemsを保存しました");

isEditting = false;
}
}

private bool isChange = false;
private bool isChanging = false;
private void EditTextOnBeforeTextChanged(object sender, TextChangedEventArgs e)
{
if (isChange == false)isChange = true;
}


private void EditTextOnTextChanged(object sender, TextChangedEventArgs e)
{
if (isChange && e.BeforeCount != e.AfterCount)isChanging = true;
}

/// <summary>
/// 文字変更入力後処理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TextViewOnAfterTextChanged(object sender, AfterTextChangedEventArgs e)
{
if (false == (isChange && isChanging))return;

//描画中の文字に更新文字を設定する
SaveChangeText((EditText)sender);

isChange = false;
isChanging = false;

}

#endregion

#region 外部利用処理

public List<ViewArticleItem> GetArticleItems()
{
return _items;
}

#endregion

#region 内部処理

/// <summary>
/// 変更を保持データに反映する
/// </summary>
/// <param name="editText">変更データを持つEditText</param>
private void SaveChangeText(EditText editText)
{
if (editText.HasFocus == false) return;//これがないと、アクション時などに、一覧表が更新されてしまう

//更新対象を特定するために、ItemIdを取得する
var itemId = getTagItemId(editText);

//データに反映する
var item = _items.First(x => x.ItemId == itemId);
item.Text = editText.Text;
isEditting = true;
}

#endregion

}