문제

WPF Browserlike 앱입니다.
나는 하나의 포함하는 페이지 ListView.를 호출한 후 PageFunction 내가 줄을 추가하 ListView,와 스크롤하려는 새로운 라인으로 view:

  ListViewItem item = ItemContainerGenerator.ContainerFromIndex(index) as ListViewItem;
  if (item != null)
    ScrollIntoView(item);

이 작동합니다.으로 새로운 라인이 보기에 라인에 포커스를 받을 다음과 같습니다.

문제는 것이 작동하지 않는 경우 라인은 보이지 않습니다.
는 경우 라인이 표시되지 않은 없 ListViewItem 라인에 대해 생성되는,그래서 ItemContainerGenerator.ContainerFromIndex null 을 반환합니다.

하지만 항목이 없는 어떻게 나는 스크롤라인으로 보?수 있는 방법은 없는지 스크롤하고 마지막 라인(또는)이 필요하지 않 ListViewItem?

도움이 되었습니까?

해결책

여기서 문제는 라인이 보이지 않으면 ListViewItem이 아직 생성되지 않았다는 것입니다. WPF는 가시적 인 주문형을 만듭니다.

그래서이 경우에 당신은 아마 얻을 수 있습니다 null 항목을 위해, 당신은? (귀하의 의견에 따라, 당신은 그렇습니다)

나는 찾았다 ScrollViewer에 직접 액세스 권한을 제안하는 MSDN 포럼의 링크 스크롤하기 위해. 나에게 제시된 해결책은 해킹과 매우 흡사하지만 스스로 결정할 수 있습니다.

다음은 다음과 같습니다 위의 링크:

VirtualizingStackPanel vsp =  
  (VirtualizingStackPanel)typeof(ItemsControl).InvokeMember("_itemsHost",
   BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic, null, 
   _listView, null);

double scrollHeight = vsp.ScrollOwner.ScrollableHeight;

// itemIndex_ is index of the item which we want to show in the middle of the view
double offset = scrollHeight * itemIndex_ / _listView.Items.Count;

vsp.SetVerticalOffset(offset);

다른 팁

누군가 나에게 특정 라인으로 스크롤하는 더 나은 방법을 나에게 말했는데, 이는 쉽고 매력처럼 작동합니다.
요컨대 :

public void ScrollToLastItem()
{
  lv.SelectedItem = lv.Items.GetItemAt(rows.Count - 1);
  lv.ScrollIntoView(lv.SelectedItem);
  ListViewItem item = lv.ItemContainerGenerator.ContainerFromItem(lv.SelectedItem) as ListViewItem;
  item.Focus();
}

더 긴 버전 MSDN 포럼:

나는 샘의 대답을 약간 변경했다. 마지막 줄로 스크롤하고 싶었습니다. 불행히도 ListView SomeEms는 마지막 줄을 표시했습니다 (예 : 100 줄이있을 때에도).

    public void ScrollToLastItem()
    {
        if (_mainViewModel.DisplayedList.Count > 0)
        {
            var listView = myListView;
            listView.SelectedItem = listView.Items.GetItemAt(_mainViewModel.DisplayedList.Count - 1);
            listView.ScrollIntoView(listView.Items[0]);
            listView.ScrollIntoView(listView.SelectedItem);
            //item.Focus();
        }
    }

건배

이에 대한 한 가지 해결 방법은 ListView의 ItemSpanel을 변경하는 것입니다. 기본 패널은 VirtualizingStackPanel이며 처음으로 볼 때만 ListBoxItem 만 생성합니다. 목록에 항목이 너무 많지 않으면 문제가되지 않아야합니다.

<ListView>
   ...
   <ListView.ItemsPanel>
      <ItemsPanelTemplate>
         <StackPanel/>
      </ItemsPanelTemplate>
   </ListView.ItemsPanel>
</ListView>

마지막 팁 Sam에 감사드립니다. 대화 상자가 열렸습니다. 즉, 대화 상자가 닫힐 때마다 그리드가 초점을 잃었습니다. 나는 이것을 사용한다 :

if(currentRow >= 0 && currentRow < lstGrid.Items.Count) {
    lstGrid.SelectedIndex = currentRow;
    lstGrid.ScrollIntoView(lstGrid.SelectedItem);
    if(shouldFocusGrid) {
        ListViewItem item = lstGrid.ItemContainerGenerator.ContainerFromItem(lstGrid.SelectedItem) as ListViewItem;
        item.Focus();
    }
} else if(shouldFocusGrid) {
    lstGrid.Focus();
}

이 시도

private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ScrollViewer scrollViewer = GetScrollViewer(lstVw) as ScrollViewer;
            scrollViewer.ScrollToHorizontalOffset(dataRowToFocus.RowIndex);
            if (dataRowToFocus.RowIndex < 2)
                lstVw.ScrollIntoView((Entity)lstVw.Items[0]);
            else
                lstVw.ScrollIntoView(e.AddedItems[0]);
        } 

 public static DependencyObject GetScrollViewer(DependencyObject o)
        {
            if (o is ScrollViewer)
            { return o; }

            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
            {
                var child = VisualTreeHelper.GetChild(o, i);

                var result = GetScrollViewer(child);
                if (result == null)
                {
                    continue;
                }
                else
                {
                    return result;
                }
            }
            return null;
        } 

private void Focus()
{
 lstVw.SelectedIndex = dataRowToFocus.RowIndex;
 lstVw.SelectedItem = (Entity)dataRowToFocus.Row;

 ListViewItem lvi = (ListViewItem)lstVw.ItemContainerGenerator.ContainerFromItem(lstVw.SelectedItem);
ContentPresenter contentPresenter = FindVisualChild<ContentPresenter>(lvi);
contentPresenter.Focus();
contentPresenter.BringIntoView();

}

새 데이터 항목을 작성한 후 마지막 항목을 보여주고 집중하려면이 방법이 더 나을 수 있습니다. Scrollintoview와 비교하여 ScrollViewer의 ScrollToend가 내 테스트에 더 신뢰할 수 있습니다. 위의 Scrollintoview 메소드를 사용한 일부 테스트에서는 위의 목록보기가 실패했으며 이유를 모릅니다. 그러나 ScrollViewer를 사용하여 스크롤을 사용하면 마지막으로 작동 할 수 있습니다.

void FocusLastOne(ListView lsv)
{
   ObservableCollection<object> items= sender as ObservableCollection<object>;

   Decorator d = VisualTreeHelper.GetChild(lsv, 0) as Decorator;
   ScrollViewer v = d.Child as ScrollViewer;
   v.ScrollToEnd();

   lsv.SelectedItem = lsv.Items.GetItemAt(items.Count - 1);
   ListViewItem lvi = lsv.ItemContainerGenerator.ContainerFromIndex(items.Count - 1) as ListViewItem;
   lvi.Focus();
}

Itemcontainergenerator.containerfromitem () 및 itemcontainergenerator.containerfromindex ()와 동일한 문제가 발생했습니다. DeCasteljau는 옳았지만 그가 의미하는 바를 정확히 파악하기 위해 파는 것이 필요했습니다. 다음은 다음 남자/gal을 저장하기위한 고장입니다.

간단히 말해서, ListBoxItems는보기에 있지 않으면 파괴됩니다. 결과적으로 ContainerFromItem () 및 ContainerFromIndex () return null listboxItems가 존재하지 않기 때문에 null return null. 이것은 분명히 여기에 자세히 설명 된 메모리/성능 저장 기능입니다. http://blogs.msdn.com/b/oren/archive/2010/11/08/wp7-silverlight-perf-demo-1-virtualizingstackpanel-vs-stackpanel-as-a-listbox-itemspanel.aspx

<ListBox.ItemsPanel> 코드는 가상화를 끄는 것입니다. 나에게 문제를 해결 한 샘플 코드 :

데이터 템플릿 :

<phone:PhoneApplicationPage.Resources>
    <DataTemplate x:Key="StoryViewModelTemplate">
        <StackPanel>
          <your datatemplated stuff here/>
        </StackPanel>
    </DataTemplate>
</phone:PhoneApplicationPage.Resources>

본체:

<Grid x:Name="ContentPanel">
    <ListBox Name="lbResults" ItemsSource="{Binding SearchResults}" ItemTemplate="{StaticResource StoryViewModelTemplate}">
        <ListBox.ItemsPanel>
             <ItemsPanelTemplate>
                 <StackPanel>
                 </StackPanel>
             </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
</Grid>

가상화 문제를 극복하지만 여전히 사용합니다 ScrollIntoView ListView의 내장에서 해킹하지 않으면 ViewModel 객체를 사용하여 선택한 내용을 결정할 수도 있습니다. 목록에 뷰 모델 객체가 있다고 가정하면 IsSelected 재산. 다음과 같이 XAML의 ListView에 항목을 링크합니다.

<ListView Name="PersonsListView" ItemsSource="{Binding PersonVMs}">
  <ListView.ItemContainerStyle>
    <Style TargetType="{x:Type ListViewItem}">
      <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
    </Style>
  </ListView.ItemContainerStyle>
</ListView>

그런 다음 Code-Behind 메소드가 다음과 같이 선택한 첫 번째 항목으로 스크롤 할 수 있습니다.

var firstSelected = PersonsListView.Items
    .OfType<TreeViewItemViewModel>().FirstOrDefault(x => x.IsSelected);
if (firstSelected != null)
    CoObjectsListView.ScrollIntoView(firstSelected);

선택한 항목이 잘 보이지 않는 경우에도 작동합니다. 내 실험에서 PersonsListView.SelectedItem 재산은 null, 그러나 물론 당신의 뷰 모델 IsSelected 재산은 항상 있습니다. 모든 바인딩 및 하중이 완료된 후이 방법을 호출하십시오 (오른쪽으로 DispatcherPriority).

사용 관점 패턴, 뷰 모델 코드는 다음과 같습니다.

PersonVMs.ForEach(vm => vm.IsSelected = false);
PersonVMs.Add(newPersonVM);
newPersonVM.IsSelected = true;
ViewCommandManager.InvokeLoaded("ScrollToSelectedPerson");

내 프로젝트에서 선택한 색인 라인을 ListView에서 사용자에게 표시하여 선택한 항목을 ListView Control에 할당해야합니다. 이 코드는 스크롤 바를 스크롤하고 선택한 항목을 표시합니다.

booleanListView.Scrollintoview (booleanListView.SelectedItem);

또는

var listview = booleanListView; listView.SelectedItem = listView.Items.getItemat (booleanListView.SelectedIndex); ListView.scrollintoview (ListView.Items [0]); ListView.scrollintoview (ListView.SelectedItem);

가 확실하지 않는 경우는 이 방법이 이동하지만 이것은 현재 사용하여 나를 위해 WPF 된 이 빛이,그리고.NET3.5

추가 SelectionChanged 이벤트에 대한 ListBox 라"lbPossibleError_SelectionChanged" I added the SelectionChanged event for ListBox

그 뒤에 이"lbPossibleError_SelectionChanged"이벤트,여기에 코드 enter image description here

적으로 작동합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top