2

問題はMVVMCrossでプログラミングしないのと同じですが、「クロスプラットフォーム」ソリューションがあるのではないかと思います。

MvxBindableListView(またはListView)でImageButtonを使用する場合、このボタンでアクションを使用するには、いくつかのオプションを設定する必要があります。

        <ImageButton
            ...
            android:focusable="false"
            android:clickable="true" 
            ...
            local:MvxBind="'Click':{'Path':'Command1'}}"
          />

これらのパラメータを使用すると、ボタンは「Command1」に反応します。ただし、問題は、ListViewの「ビジュアルセレクター」が変更されていないことです。

例を挙げましょう:

ListViewに5つの行があり、最初の行が選択されている場合。3行目のImageButtonをタッチすると、「Command1」は(ListViewの3番目の項目と)反応しますが、セレクターは最初の行に留まります。

したがって、Androidでは、次のようなコードを配置する必要があります。

_imagebutton.Click += (object sender, EventArgs eventsArgs) =>
    {
        View v = ...
        MvxBindableListView l = ...
        int p = l.GetPositionForView(...);
        l.PerformItemClick(..., p, p); 
     };

このコードを使用すると、適切なアイテムが選択され、動作が正しくなります(ItemClickで実際のイベントを発生させたくない場合)。しかし、このソリューションは「Androidの方法」であり、実際にはクロスプラットフォームではありません(そして、すべてのものを初期化するための恐ろしいコードを想像させてください)

誰かがより良い解決策を持っていますか?

ヒューゴ

4

1 に答える 1

1

部分的には、これは単なる「UI の見栄え」であり、「ビューの懸念事項」の領域に該当するため、mvvmcross が通常クロス プラットフォームを作成しようとするものではないように感じます。

しかし…方法はあると思います。

ViewModel 内のコマンド ハンドラーが ViewModel に CurrentSelectedPosition 整数も設定する場合、各 UI は ViewModel からの SelectedItemPosition を各 UI の各リストにバインドできます。これにより、UI は選択をネイティブに更新します。

私はそれがうまくいくと思います...しかし、Androidではいくつかのバインディングが必要になります:

public class MvxAdapterViewSelectedItemPositionTargetB-inging : MvxBaseAndroidTargetBinding
{
    private readonly AdapterView _adapterView;

    public MvxAdapterViewSelectedItemPositionTargetBinging(AdapterView adapterView)
    {
        _adapterView = adapterView;
        _adapterView.ItemSelected += AdapterViewOnItemSelected;
    }

    public override void SetValue(object value)
    {
        _adapterView.SetSelection((int)value);
    }

    private void AdapterViewOnItemSelected(object sender, AdapterView.ItemSelectedEventArgs itemSelectedEventArgs)
    {
        FireValueChanged(itemSelectedEventArgs.Position);
    }

    public override MvxBindingMode DefaultMode
    {
        get
        {
            return MvxBindingMode.TwoWay;
        }
    }

    public override Type TargetType
    {
        get
        {
            return typeof(Int32);
        }
    }

    protected override void Dispose(bool isDisposing)
    {
        if (isDisposing)
        {
            if (_adapterView != null)
            {
                _adapterView.ItemSelected -= AdapterViewOnItemSelected;
            }
        }
        base.Dispose(isDisposing);
    }
}

以下を使用して登録:

        registry.RegisterFactory(new MvxCustomBindingFactory<AdapterView>("SelectedItemPosition", adapterView => new MvxAdapterViewSelectedItemPositionTargetBinging(adapterView)));

axml で UI にバインドされます。たとえば、次のようになります。

<Mvx.MvxBindableListView
    android:id="@android:id/list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    local:MvxBind="{'ItemsSource':{'Path':'Emails'},'SelectedItemPosition':{'Path':'CurrentSelectedPosition'}}"
    local:MvxItemTemplate="@layout/listitem_email"
/>

ViewModel のリスト アイテムが次のようなメーリング リストを使用して、このアイデアをテストしました。

    public class SimpleEmail
    {
        public EmailViewModel Parent { get; set; }
        public string From { get; set; }    
        public string Header { get; set; }    
        public string Message { get; set; }    
        public ICommand Command1
        {
            get
            {
                return new MvxRelayCommand(() => Parent.CurrentSelectedPosition = Parent.Emails.IndexOf(this));
            }
        }
    }
  • しかし、明らかにこれは単なるデモです...

注: 上記のコードでは、選択されたオブジェクトではなく、選択された位置を使用しています。使用しているリストが非常に長いことがわかっているためです。


Android 専用のコードに別のアプローチを検討したい場合は、Mvx.MvxBindableListView (およびおそらくリスト項目も) から継承し、それらのクラスを使用して選択をより簡単な方法で更新することで、それを行うことができると思います。 .

于 2012-10-05T07:51:56.263 に答える