4

モデル-ビュー-ビューモデル デザイン パターンの記事 を使用した WPF アプリに(ほとんどの部分で) 似た wpf ユーザー コントロール プロジェクトをセットアップしました。基本的に、タブ コントロールを格納するヘッダー付きのコンテンツ コントロールがあります。最初のタブには検索結果が表示され、検索結果のアイテムをクリックして追加のタブを開くと、そのアイテムのより詳細なビューが表示されます。

私の主な問題は、誰かが検索条件を入力して検索コマンドを実行するたびに、検索結果タブを再利用することです。検索結果のコレクションが再作成されたとき (ユーザーがリストを下にスクロールした場合)、scrollviewer は一番上までスクロールしません。

もともと、CollectionChanged イベントを発生させる方法で、検索結果アイテム コレクションを再作成していました。次に、添付プロパティを使用して一番上までスクロールできるようにすることを調べたところ、コレクション全体を置き換える方法があるように見えました (ItemsControl は ICollectionNotifyChanged インターフェイスを実装していないため)。

それで私は変更を加えました、そしてすべてがうまく見えました。新しい検索を実行すると、検索結果項目のコレクションが置き換えられ、添付プロパティが起動され、リストビューが一番上にスクロールされました。ただし、アイテムの詳細ビューを表示するために別のタブに移動するたびに、添付されたプロパティが起動し、最初のタブの検索結果が一番上にスクロールするという問題があります。この状況に対処する方法がわかりません。

public static class ScrollToTopBehavior
{
    public static readonly DependencyProperty ScrollToTopProperty =
        DependencyProperty.RegisterAttached
            (
                "ScrollToTop",
                typeof (bool),
                typeof (ScrollToTopBehavior),
                new UIPropertyMetadata(false, OnScrollToTopPropertyChanged)
            );

    public static bool GetScrollToTop(DependencyObject obj)
    {
        return (bool) obj.GetValue(ScrollToTopProperty);
    }

    public static void SetScrollToTop(DependencyObject obj, bool value)
    {
        obj.SetValue(ScrollToTopProperty, value);
    }

    private static void OnScrollToTopPropertyChanged(DependencyObject dpo,
                                                     DependencyPropertyChangedEventArgs e)
    {
        var itemsControl = dpo as ItemsControl;
        if (itemsControl == null) return;

        DependencyPropertyDescriptor dependencyPropertyDescriptor =
            DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, typeof (ItemsControl));
        if (dependencyPropertyDescriptor == null) return;
        if ((bool) e.NewValue)
        {
            dependencyPropertyDescriptor.AddValueChanged(itemsControl, ItemsSourceChanged);
        }
        else
        {
            dependencyPropertyDescriptor.RemoveValueChanged(itemsControl, ItemsSourceChanged);
        }
    }

    private static void ItemsSourceChanged(object sender, EventArgs e)
    {
        var itemsControl = sender as ItemsControl;
        EventHandler eventHandler = null;
        eventHandler = delegate
            {
                if (itemsControl != null &&
                    itemsControl.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
                {
                    var scrollViewer = VisualTreeHelpers.FindChild<ScrollViewer>(itemsControl);
                    scrollViewer.ScrollToTop();
                    itemsControl.ItemContainerGenerator.StatusChanged -= eventHandler;
                }
            };
        if (itemsControl != null) itemsControl.ItemContainerGenerator.StatusChanged += eventHandler;
    }
}

このプロパティを次のように検索結果ユーザー コントロールにアタッチしました。

<ListView ...some properties left out for brevity...
              DataContext="{StaticResource SearchResultsViewSource}"
              IsSynchronizedWithCurrentItem="True"
              ItemsSource="{Binding}"
              SelectionMode="Single"
              behaviours:ScrollToTopBehavior.ScrollToTop="True">
...etc...

検索結果コントロールは、ヘッダー付きコンテンツ コントロールを使用している別のユーザー コントロール内に格納されています (必要に応じて詳細を提供します)。

4

1 に答える 1

1

これはハックであり、実際の問題は解決しませんが、症状は解決します。
イベントで動作を切り離すことができるtabControl.Selectingので、開始または検索結果タブに移動するときに動作/プロパティを添付し、他のタブに移動すると動作を切り離す/登録解除します。

次のようになります。

yourTab.SelecnionChanged+= new TabControlCancelEventHandler(tabControl_Selecting);

void tabControl_SelecnionChange(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    var current = (sender as TabControl).SelectedValue;

    //check if current is search tab then
    {
      ScrollToTopBehavior.SetScrollToTop(yourList,true);
    }
    else
    {
      ScrollToTopBehavior.SetScrollToTop(yourList,false);
    }

}
于 2013-07-30T11:52:56.753 に答える