4

ListViewのビューに表示されるVMにObservableCollectionがあります。選択したアイテムが変更されると、SelectionChangedイベントが適切に発生します。以下は、ListViewを構成する方法です。

<ListView Grid.Row="3" Margin="5" AlternationCount="2" Name="_lvSettings" 
          IsSynchronizedWithCurrentItem="True"
          ItemsSource="{Binding Path=CollectionView}" 
          SelectedIndex="{Binding Path=SelectedSettingIndex}"
          SelectionChanged="OnSelectionChanged"  >
    <ListView.View>
        <GridView>
            <GridViewColumn Width="170" 
                            Header="{Binding Path=ShowAllDisplay}"
                            x:Name="_colSettings"  
                            DisplayMemberBinding="{Binding Path=Setting}"/>
            <GridViewColumn Header="Old Value" Width="150" 
                            DisplayMemberBinding="{Binding Path=OldVal}"/>
            <GridViewColumn Header="New Value" 
                            DisplayMemberBinding="{Binding Path=NewVal}" />
        </GridView>
    </ListView.View>
</ListView>

私が抱えている問題は、コレクションのフィルターを変更するときです。選択されたアイテムは同じままです。これは良いことですが、ListViewが最初のアイテムから表示されるように変更され、多くの場合、選択されたアイテムは表示されません(ただし、選択されたアイテムは表示されます)。

VMには、変更時にPropertyChangedイベントをスローするプロパティ「SelectedSettingIndex」があります。フィルタが変更されたときにVMから手動でイベント(base.OnPropertyChanged( "SelectedSettingIndex");)を発生させても、プロパティが実際には変更されていないため、イベントは実際には発生していないようです。このシナリオでは、ScrollIntoViewなどを呼び出す方法が必要ですが、正しいイベントまたはトリガーを見つけることができません。私が行方不明になっているのは何ですか?

編集

これが、私が懸念している問題の、うまくいけばより良い説明です。

1)VMで​​CollectionViewSourceを使用してデータをフィルタリングしています。

2)ユーザーがフィルターを切り替えるためのボタンがあります。

3)ListViewには、常に最大10個のアイテムを表示する余地があると仮定します。

4)ユーザーは、リストビューのインデックス50にあるフィルターされたビューでアイテム「A」を選択します。

5)次に、ユーザーはボタンをクリックしてフィルタリングをオフにします。

期待される結果:ListViewにはフィルター処理されていないリストが表示され、アイテム「A」は選択されたままになり、アイテム「A」が引き続き表示されるようにListViewが「スクロール」されます。

実際の結果:ListViewにはフィルタリングされていないリストが表示され、アイテム "A"が選択されたままになり、ListViewが一番上に「スクロール」され、最初の10個のアイテムが表示されます。アイテム「A」は表示されていません。

4

4 に答える 4

13

MVVM を使用している場合は、viewModel で選択したアイテムへのバインディングを設定していることを確認する必要がありますMode=TwoWay。また、選択をスクロールするには、ListView で動作を使用する必要があります (コード ビハインドを回避します)。

使用するには参照を追加する必要があり System.Windows.InteractivityますBehavior<T> class

行動

public class ScrollIntoViewForListView : Behavior<ListView>
{
    /// <summary>
    ///  When Beahvior is attached
    /// </summary>
    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;
    }

    /// <summary>
    /// On Selection Changed
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void AssociatedObject_SelectionChanged(object sender,
                                           SelectionChangedEventArgs e)
    {
        if (sender is ListView)
        {
            ListView listview = (sender as ListView);
            if (listview.SelectedItem != null)
            {
                listview.Dispatcher.BeginInvoke(
                    (Action) (() =>
                                  {
                                      listview.UpdateLayout();
                                      if (listview.SelectedItem !=
                                          null)
                                          listview.ScrollIntoView(
                                              listview.SelectedItem);
                                  }));
            }
        }
    }
    /// <summary>
    /// When behavior is detached
    /// </summary>
    protected override void OnDetaching()
    {
        base.OnDetaching();
        this.AssociatedObject.SelectionChanged -=
            AssociatedObject_SelectionChanged;

    }
}

使用法

XAMLas にエイリアスを追加xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

次に、Control DisplayMemberBinding="{Binding Path=Setting}"/> で

これで、リストに「MySelectedItem」プロパティが設定さViewModelれると、変更が反映されたときにスクロールされます。

変更通知

viewModel では、xaml にバインドしたプロパティのセッターで変更された INotifyProperty を呼び出して、viewModel の変更を View に反映できるようにする必要があります。

MVVM での SelectionChanged イベントの使用

EventToCommandまた、MVVM では、MySelectedItem プロパティの Setter で関数を呼び出すか、明示的なイベント呼び出しにクラスを使用できるため、「SelectionChnaged Event」を使用する必要はありません。

フィルタリング

並べ替え、フィルタリングなどの機能に対する Google の ColletionViewSource の使用法

それが役に立てば幸い...

于 2012-04-13T07:59:07.730 に答える
1

OK - うまくいく2つの解決策を見つけましたが、100%満足していません:

1) ViewModel の Mediator パターンを使用して、フィルターが変更されたことをビューに通知します。次に、ビューは現在選択されている項目で ScrollToView を呼び出します。VM から VM への通知用の Mediator は気に入っていますが、ViewModel とそれに対応する View の間で Mediator を使用するのはなんとなく面倒です。

2) ListView の LayoutUpdated イベントに対するハンドラー内で、現在選択されているアイテムの ScrollToView を呼び出します。手間がかかり、効率が悪い - ただ、これは好きではありません。

より良い解決策を期待して、これを回答済みとしてマークするつもりはありません。好奇心旺盛な人や、同様の問題を見ている可能性のある人のために、これをここに置くだけです.

于 2012-04-13T23:55:05.207 に答える
1

ListView の SelectedItem をプロパティに保持します。

public MyTypeOfObject SelectedItem { get; set; }

バインディングを XAML に割り当てます。

<ListView Name="MyListView" SelectedItem="{Binding SelectedItem}"...></ListView>

フィルターを変更するたびに、次のようにします。

if (SelectedItem != null)
    MyListView.ScrollIntoView(SelectedItem);

編集:

ユーザー コントロールでこれを行うには、ビュー モデルをコントロール参照 (ListView) からクリーンなままにするために、CollectionViewそこで標準イベントをキャッチするか、フィルターまたは他のジョブが発生した後に発生する独自のイベントを定義します。

于 2012-04-13T06:18:42.507 に答える
1

他のいくつかの投稿(Credit)から解決策を見つけ、添付プロパティを collectionview フィルターのカウントにバインドします。

添付プロパティ:

public class SelectingItemAttachedProperty
{
    public static readonly DependencyProperty SelectingItemProperty = DependencyProperty.RegisterAttached(
        "SelectingItem",
        typeof(int),
        typeof(SelectingItemAttachedProperty),
        new PropertyMetadata(default(int), OnSelectingItemChanged));

    public static int GetSelectingItem(DependencyObject target)
    {
        return (int)target.GetValue(SelectingItemProperty);
    }

    public static void SetSelectingItem(DependencyObject target, int value)
    {
        target.SetValue(SelectingItemProperty, value);
    }

    static void OnSelectingItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        var lb = sender as ListBox;
        if (lb?.SelectedItem == null)
            return;

        lb.Dispatcher.InvokeAsync(() =>
        {
            lb.UpdateLayout();
            lb.ScrollIntoView(lb.SelectedItem);
        });
    }
}

意見:

<Listbox
    design:SelectingItemAttachedProperty.SelectingItem="{Binding CollectionViewFromVM.Count}"
   ...>

これはほとんどの場合うまくいくようです =)

于 2017-03-15T20:49:19.307 に答える