source

[ WPF ListBox ]를 [Selected]으로 스크롤합니다.뷰 모델의 코드에 설정된 항목

lovecheck 2023. 4. 12. 22:30
반응형

[ WPF ListBox ]를 [Selected]으로 스크롤합니다.뷰 모델의 코드에 설정된 항목

목록 상자가 있는 XAML 뷰가 있습니다.

<control:ListBoxScroll ItemSource="{Binding Path=FooCollection}"
                       SelectedItem="{Binding SelectedFoo, Mode=TwoWay}"
                       ScrollSelectedItem="{Binding SelectedFoo}">
    <!-- data templates, etc. -->
</control:ListBoxScroll>

선택한 항목은 내 보기에 속성에 바인딩되어 있습니다.사용자가 목록 상자에서 항목을 선택하면 뷰 모델의 SelectedFoo 속성이 업데이트됩니다.뷰 모델에서 SelectedFoo 속성을 설정하면 목록 상자에서 올바른 항목이 선택됩니다.

Foo가 되지 않는 Selected Foo를 입니다.ScrollIntoView목록 상자에 있습니다.List Box list list 、 list list list list 、 list list list...나는 그것을 할 수 있는 편리한 방법을 찾을 수 없었다.리스트 박스 스크롤

class ListBoxScroll : ListBox
{
    public static readonly DependencyProperty ScrollSelectedItemProperty = DependencyProperty.Register(
        "ScrollSelectedItem",
        typeof(object),
        typeof(ListBoxScroll),
        new FrameworkPropertyMetadata(
            null,
            FrameworkPropertyMetadataOptions.AffectsRender, 
            new PropertyChangedCallback(onScrollSelectedChanged)));
    public object ScrollSelectedItem
    {
        get { return (object)GetValue(ScrollSelectedItemProperty); }
        set { SetValue(ScrollSelectedItemProperty, value); }
    }

    private static void onScrollSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var listbox = d as ListBoxScroll;
        listbox.ScrollIntoView(e.NewValue);
    }
}

속성을 합니다.ScrollSelectedItem는 그것을 내내 에 묶는다.SelectedFoo뷰 모델에 속성을 표시합니다.그런 다음 종속 속성의 변경된 속성 콜백에 연결하고 새로 선택한 항목을 보기로 스크롤합니다.

뷰 모델을 기반으로 한 XAML 뷰에서 사용자 컨트롤에 대한 함수를 호출하는 더 쉬운 방법을 알고 있는 사람이 있습니까?다음 작업을 수행하기에는 다소 번거롭습니다.

  1. 종속 속성을 생성하다
  2. 속성 변경 콜백에 콜백 추가
  3. 스태틱 콜백 내의 함수 호출 처리

'이론'에 것 요.ScrollSelectedItem { set {그러나 종속 프레임워크는 실제로 전화를 받지 않고 작업하는 것 없이 작업하는 것 같다.메서드는 의존관계 프레임워크가 실제로 호출하지 않고 슬쩍 돌아다니는 것처럼 보입니다.

동작을 사용해 본 적이 있습니까?다음은 Scroll In View Behavior 입니다.ListView 및 DataGrid에 사용하고 있습니다.ListBox에서 작동해야 할 것 같은데...

You have to add a reference to 참조를 추가해야 합니다.System.Windows.Interactivity to use 사용하다Behavior<T> class

행동

public class ScrollIntoViewForListBox : Behavior<ListBox>
{
    /// <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 ListBox)
        {
            ListBox listBox = (sender as ListBox);
            if (listBox .SelectedItem != null)
            {
                listBox.Dispatcher.BeginInvoke(
                    (Action) (() =>
                                  {
                                      listBox.UpdateLayout();
                                      if (listBox.SelectedItem !=
                                          null)
                                          listBox.ScrollIntoView(
                                              listBox.SelectedItem);
                                  }));
            }
        }
    }
    /// <summary>
    /// When behavior is detached
    /// </summary>
    protected override void OnDetaching()
    {
        base.OnDetaching();
        this.AssociatedObject.SelectionChanged -=
            AssociatedObject_SelectionChanged;

    }
}

사용.

Add alias to 에 별칭 추가XAML as ~하듯이xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

then in your 그럼 네 안에Control

        <ListBox ItemsSource="{Binding Path=MyList}"
                  SelectedItem="{Binding Path=MyItem,
                                         Mode=TwoWay}"
                  SelectionMode="Single">
            <i:Interaction.Behaviors>
                <Behaviors:ScrollIntoViewForListBox />
            </i:Interaction.Behaviors>
        </ListBox>

이제 "내 항목" 속성은 "내 항목" 정 우 된 이 성 now when is " " ever경설my속 property in setmy"item" 내 항목" 속성) 속성) 속성"로 설정ViewModel변경 내용이 선택되면 목록이 스크롤됩니다.

답변을 검토한 후 ListBox의 SelectionChanged 이벤트를 청취하는 외부 클래스가 공통의 테마를 제시했습니다.그 결과 의존적인 자산 접근법이 너무 지나쳤다는 것을 깨달았습니다.그리고 서브클래스가 자기 의견을 듣게 할 수 있었습니다.

class ListBoxScroll : ListBox
{
    public ListBoxScroll() : base()
    {
        SelectionChanged += new SelectionChangedEventHandler(ListBoxScroll_SelectionChanged);
    }

    void ListBoxScroll_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        ScrollIntoView(SelectedItem);
    }
}

이것이 내가 원하는 것을 할 수 있는 가장 간단한 해결책이라고 생각한다.

명예로운 언급은 행동을 제기한 adcool2007에 돌아간다.다음은 관심 있는 사용자를 위한 몇 가지 기사입니다.

http://blogs.msdn.com/b/johngossman/archive/2008/05/07/the-attached-behavior-pattern.aspx
http://www.codeproject.com/KB/WPF/AttachedBehaviors.aspx

몇 가지 다른 사용자 컨트롤에 추가되는 일반적인 행동(예: 클릭 동작, 드래그 동작, 애니메이션 동작 등)의 경우 부가적인 행동이 매우 타당하다고 생각합니다.이되어 있기 입니다.ScrollIntoView에 대해 할 수 .) ListBox는 ListBox 이외의 컨트롤에 대해 발생할 수 있습니다.

이는 보기 문제이기 때문에 이 목적을 위해 보기 뒤에 있는 코드에 이벤트 핸들러를 사용하지 못할 이유가 없습니다.를 들어주세요.ListBox.SelectionChanged새로 선택한 항목을 보기로 스크롤할 때 사용합니다.

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ((ListBox)sender).ScrollIntoView(e.AddedItems[0]);
}

된 것은 ListBox이 일을 하기 위해서., 이이 필요할 때 사용하세요.ListBox.SelectedItem값이 변경되면(원래 질문에서 설명한 대로), 위의 핸들러가 실행되고 항목이 보기로 스크롤됩니다.

    <ListBox
        ItemsSource="{Binding Path=FooCollection}"
        SelectedItem="{Binding Path=SelectedFoo}"
        SelectionChanged="ListBox_SelectionChanged"
        />

하나의 은 '를 '부속하다'로 '하다'를 입니다.ICollectionView.CurrentChanged를 호출합니다.ListBox.ScrollIntoView현재 새 항목에 대한 것입니다.여러 목록 상자에 이 기능이 필요한 경우 이 방법은 더 "재사용 가능한" 방법입니다.시작하기 위한 좋은 예를 여기서 찾을 수 있습니다.http://michlg.wordpress.com/2010/01/16/listbox-automatically-scroll-currentitem-into-view/

나는 이것을 (내 의견으로는) 명료하고 쉬운 해결책을 사용하고 있다

listView.SelectionChanged += (s, e) => 
    listView.ScrollIntoView(listView.SelectedItem);

서 ''는listView is of of of of 의 이름ListView xaml),SelectedItemxaml.cs 파일의 컨스트럭터에 코드가 삽입되어 있습니다.

오래된 질문인 것은 알지만, 최근 같은 문제를 찾아본 결과 이렇게 되었습니다. 어프로치를 「 SDK」에 의존해 「 SDK」라고 은 원하지 않았습니다.Behavior<T>이 기능을 사용하지 않는 솔루션은 다음과 같습니다.

public static class ListBoxBehavior
{
    public static bool GetScrollSelectedIntoView(ListBox listBox)
    {
        return (bool)listBox.GetValue(ScrollSelectedIntoViewProperty);
    }

    public static void SetScrollSelectedIntoView(ListBox listBox, bool value)
    {
        listBox.SetValue(ScrollSelectedIntoViewProperty, value);
    }

    public static readonly DependencyProperty ScrollSelectedIntoViewProperty =
        DependencyProperty.RegisterAttached("ScrollSelectedIntoView", typeof (bool), typeof (ListBoxBehavior),
                                            new UIPropertyMetadata(false, OnScrollSelectedIntoViewChanged));

    private static void OnScrollSelectedIntoViewChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var selector = d as Selector;
        if (selector == null) return;

        if (e.NewValue is bool == false)
            return;

        if ((bool) e.NewValue)
        {
            selector.AddHandler(Selector.SelectionChangedEvent, new RoutedEventHandler(ListBoxSelectionChangedHandler));
        }
        else
        {
            selector.RemoveHandler(Selector.SelectionChangedEvent, new RoutedEventHandler(ListBoxSelectionChangedHandler));
        }
    }

    private static void ListBoxSelectionChangedHandler(object sender, RoutedEventArgs e)
    {
        if (!(sender is ListBox)) return;

        var listBox = (sender as ListBox);
        if (listBox.SelectedItem != null)
        {
            listBox.Dispatcher.BeginInvoke(
                (Action)(() =>
                    {
                        listBox.UpdateLayout();
                        if (listBox.SelectedItem !=null)
                            listBox.ScrollIntoView(listBox.SelectedItem);
                    }));
        }
    }
}

그리고 용도는

<ListBox ItemsSource="{Binding Path=MyList}"
         SelectedItem="{Binding Path=MyItem, Mode=TwoWay}"
         SelectionMode="Single" 
         behaviors:ListBoxBehavior.ScrollSelectedIntoView="True">

이것을 시험해 보세요.

private void lstBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    lstBox.ScrollIntoView(lstBox.SelectedItem);
}

여러 가지 방법을 묶은 결과, 다음과 같은 것이 가장 간단하고 최선의 방법이라는 것을 알게 되었다.

lstbox.Items.MoveCurrentToLast();
lstbox.ScrollIntoView(lstbox.Items.CurrentItem);

나는 Ankesh의 답변을 받아 혼합 sdk에 의존하지 않도록 했다.제 솔루션의 단점은 앱의 모든 목록 상자에 적용된다는 것입니다.단, 커스텀 클래스가 필요 없다는 장점이 있습니다.

앱 초기화 중...

    internal static void RegisterFrameworkExtensionEvents()
    {
        EventManager.RegisterClassHandler(typeof(ListBox), ListBox.SelectionChangedEvent, new RoutedEventHandler(ScrollToSelectedItem));
    }

    //avoid "async void" unless used in event handlers (or logical equivalent)
    private static async void ScrollToSelectedItem(object sender, RoutedEventArgs e)
    {
        if (sender is ListBox)
        {
            var lb = sender as ListBox;
            if (lb.SelectedItem != null)
            {
                await lb.Dispatcher.BeginInvoke((Action)delegate
                {
                    lb.UpdateLayout();
                    if (lb.SelectedItem != null)
                        lb.ScrollIntoView(lb.SelectedItem);
                });
            }
        }
    }

그러면 모든 목록 상자가 선택 항목(기본 동작으로 사용)으로 스크롤됩니다.

언급URL : https://stackoverflow.com/questions/8827489/scroll-wpf-listbox-to-the-selecteditem-set-in-code-in-a-view-model

반응형