Mam powiązanie WPF ListBox
z ObservableCollection
. Gdy elementy zostaną dodane do kolekcji, pozycja przewijania przesuwa się o wielkość dodanych wpisów. Chciałbym móc zachować pozycję przewijania, tak aby pozycje dodawane do listy nie poruszały się. Czy istnieje sposób, aby to osiągnąć?Konserwacja zwiniętej pozycji przewijania ListBox WPF po zmianie kolekcji
Odpowiedz
Nie jestem pewien, czy jest to przesłonięcie, ale wątpię w to.
W razie wątpliwości użyj wiązania ręcznego? : -} Poważnie, domyślne zachowanie wiązania będzie - dobrze - domyślne, więc jeśli potrzebujesz specjalnego zachowania, ręczne wiązanie jest lepszym wyborem. Dzięki ręcznemu powiązaniu można zapisać pozycję przewijania i zresetować ją po dodaniu elementów.
Co prowadzi do oczywistego pytania - jak określić aktualną pozycję przewijania? –
Utwórz kolekcjęViewView. Spróbuj tego:
private ObservableCollection<int> m_Values;
private CollectionView m_View;
private void Bind()
{
m_Values = new ObservableCollection<int>();
m_View = new CollectionView(m_Values);
MyListBox.ItemsSource = m_View;
}
private void MyListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Debug.WriteLine(m_View.CurrentItem);
Debug.WriteLine(m_View.CurrentPosition);
}
Proszę wyjaśnić dalej. Ta odpowiedź nie rozwiązuje problemu - po prostu raportuje aktualny przedmiot i pozycję. Mam ten sam problem, używając ListBox z zestawem ItemsPanel do VirtualizingStackPanel. Problemem, jaki widzę, jest to, że elementy z pola listy nadal się poruszają w miarę dodawania nowych elementów do kolekcji Observable. Chociaż możliwe jest przeniesienie elementów do miejsca, w którym znajdowały się po dodaniu nowego elementu (np. Za pomocą SelectedIndex), powstaje gwałtowny ruch. Potrzebny jest sposób, aby zapobiec zmianie pozycji przewijania w pierwszej kolejności po dodaniu nowych elementów. – CyberMonk
Mam ten sam problem, ale twoje rozwiązanie zakłada, że wybrano coś. Ale co, jeśli użytkownik nie chce niczego wybierać? Po prostu przewiń gdzieś i zostaw to. – EvAlex
Czy można kontrolować, kiedy rzeczy są dodawane? Mam na myśli, czy masz jeden lub dwa zdefiniowane punkty, w których dane się zmieniają? Jeśli tak, jednym prostym rozwiązaniem (być może nie eleganckim) byłaby lokalna zmienna int do przechowywania bieżącego obiektu ListBox.SelectedIndex. Tuż przed zmianą danych zapisz selectedIndex na tę zmienną i po dodaniu danych ustaw SelectedIndex listbox na wartość tej zmiennej.
Najpierw znajdź bieżącą pozycję według ListBox.SelectedIndex, a następnie użyj ListBox.ScrollIntoView (/ * Bieżący indeks * /). Nawet jeśli nowe pozycje zostaną dodane do listy, twoja obecna pozycja i widok będą takie same.
Miałem ten sam problem i jeszcze jedno ograniczenie: użytkownik nie wybiera przedmiotów, a jedynie zwojów. Dlatego metoda ScrollIntoView()
jest bezużyteczna. Oto moje rozwiązanie.
Najpierw stworzyłem klasę ScrollPreserver
wyprowadzania go z DependencyObject, z dołączonym właściwość zależność PreserveScroll
typu bool:
public class ScrollPreserver : DependencyObject
{
public static readonly DependencyProperty PreserveScrollProperty =
DependencyProperty.RegisterAttached("PreserveScroll",
typeof(bool),
typeof(ScrollPreserver),
new PropertyMetadata(new PropertyChangedCallback(OnScrollGroupChanged)));
public static bool GetPreserveScroll(DependencyObject invoker)
{
return (bool)invoker.GetValue(PreserveScrollProperty);
}
public static void SetPreserveScroll(DependencyObject invoker, bool value)
{
invoker.SetValue(PreserveScrollProperty, value);
}
...
}
nieruchomości zmienił zwrotna zakłada, że nieruchomość jest ustalana przez ScrollViewer. Metoda zwrotna dodaje tę ScrollViewer do prywatnego słownika i dodaje ScrollChanged obsługi zdarzeń do niego:
private static Dictionary<ScrollViewer, bool> scrollViewers_States =
new Dictionary<ScrollViewer, bool>();
private static void OnScrollGroupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ScrollViewer scrollViewer = d as ScrollViewer;
if (scrollViewer != null && (bool)e.NewValue == true)
{
if (!scrollViewers_States.ContainsKey(scrollViewer))
{
scrollViewer.ScrollChanged += new ScrollChangedEventHandler(scrollViewer_ScrollChanged);
scrollViewers_States.Add(scrollViewer, false);
}
}
}
Słownik ten będzie posiadać odnośniki do wszystkich ScrollViewers w aplikacji, które korzystają z tej klasy. W moim przypadku przedmioty są dodawane na początku kolekcji. Problem polega na tym, że położenie rzutni się nie zmienia. Jest dobrze, gdy pozycja wynosi 0: pierwszy element w rzutni zawsze będzie pierwszym elementem. Ale gdy pierwszy element w rzutni ma inny indeks niż 0 i dodawane są nowe elementy - wskaźnik tego elementu rośnie, więc przewijany jest w dół. Więc wartość bool wskazuje, czy przesunięcie ScrollViewer na pionowy nie jest 0. Jeśli jest 0, nie ma potrzeby robić nic, a jeśli to nie jest 0, konieczne jest zachowanie jego położenia względem pozycji w rzutni:
static void scrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
if (scrollViewers_States[sender as ScrollViewer])
(sender as ScrollViewer).ScrollToVerticalOffset(e.VerticalOffset + e.ExtentHeightChange);
scrollViewers_States[sender as ScrollViewer] = e.VerticalOffset != 0;
}
ExtentHeightChange służy tutaj do wskazania ilości dodanych elementów. W moim przypadku elementy są dodawane tylko na początku kolekcji, więc wszystko, co musiałem zrobić, to zwiększyć VerticalOffset ScrollViewera o tę wartość. I ostatnia rzecz: użycie. Oto przykład ListBox:
<Listbox ...>
<ListBox.Resourses>
<Style TargetType="ScrollViewer">
<Setter Property="local:ScrollPreserver.PreserveScroll" Value="True" />
</Style>
</ListBox.Resourses>
</ListBox>
Ta-da!Działa miło :)
Czy nie wycieka ona z pamięci ze względu na słownik w polu statycznym? – TcKs
DependencyProperties są wszystkie statyczne. Możesz przeczytać o tym na przykład tutaj: http://stackoverflow.com/questions/2989431/why-are-dependency-properties-static – EvAlex
Wiem. Ale pole "scrollViewers_States" nie jest skrótem dla właściwości dependency. Przechowuje wystąpienia programu ScrollViewer. Czy masz jakiś kod, który usuwa stare instancje ze słownika? – TcKs
- 1. Aktualizacja listy WPF po zmianie pozycji
- 2. Ustawianie pozycji paska przewijania ListBox
- 3. WPF: Combobox utrata wybranego indeksu po związanym zmianie kolekcji ItemSource
- 4. listbox; liczba wybranych pozycji
- 5. Przywracanie pozycji kursora po zmianie contenteditable
- 6. Filtr WPF ListBox
- 7. Orientacja pozycji listbox na poziomą
- 8. WPF: wielokolumnowy listbox/listview?
- 9. Listbox Databinding w WPF
- 10. Zmiana pozycji paska przewijania
- 11. WPF ListBox - Pierwsze UIElement zamiast z selectedItem
- 12. Jak kontrolować pozycję przewijania ListBox w aplikacji WPV MVVM
- 13. Wirtualizacja WPF Listbox tworzy DisconnectedItems
- 14. WPF DataGrid - zachowaj pozycję przewijania po odświeżeniu
- 15. Suma pozycji w kolekcji
- 16. Uzyskaj wartość pozycji przewijania
- 17. WPF: Ustaw właściwość wiązania dla wiązania ListBox
- 18. Wykrywanie przewijania przez rodzica WPF
- 19. WPF ListBox wyłączyć efekt hover
- 20. Prawidłowy sposób unieważnienia układu widoku kolekcji po zmianie rozmiaru
- 21. Przejście CSS nie działa w przeglądarce Firefox po zmianie pozycji
- 22. Nie można przeciągnąć UITableViewCell z aktualnej pozycji po zmianie
- 23. Uzyskaj wartość pozycji listbox według indeksu
- 24. Animacja slajdów ListBox na nowej pozycji Dodano
- 25. Zapobieganie wyświetlaniu pionowego paska przewijania Silverlight ListBox
- 26. ReactNative ListView ustawienie początkowej pozycji przewijania po załadowaniu danych
- 27. Jak zapobiec resetowaniu pozycji przewijania strony po manipulacji DOM?
- 28. Blokowanie pozycji przewijania w FlatList (i ScrollView)
- 29. jak kliknąć prawym przyciskiem myszy na pozycji z Listbox i otworzyć menu na WPF
- 30. Usunąć elementy z ListBox w WPF?
Po prostu zrobiłem naprawdę proste wpf do datbinding do listbox i kiedy dodaję przedmioty, które były w widoku pozostały w widoku ... Co jeszcze robisz? – TheCodeMonk
Spróbuj dodać nowe elementy do początku kolekcji. Przedmioty, które przeglądasz, zaczynają się przemieszczać poza obszar wyświetlania, gdy dodawane są nowe elementy. Dodajesz 1 pozycję - rzutnia pozostaje na tej samej pozycji (opartej na indeksie), co oznacza, że 1 element wprowadził widok i 1 element opuścił go. – EvAlex