Reputation: 31
I'm using a listbox to display a list of numeric values where the selected value get applied to an object and is saved. I had the idea to set the height on on the listbox to be just enough to display a single row. Of course this causes the vertical scollbar to appear, and without a scroll body, which is exactly what I was looking for.
When I click the up/down arrow on the list box scrollbar, it scrolls the next item into view correctly. However, the item is not selected. I immediately had problems with the actual selected value being saved and not the value that is in view. This is because it requires a click on the number after the scrollbar button to actually select the value, which is not very intuitive.
So, after some intel-sense hunting, I began search for possible ways to increment the selected value with clicks on the listbox scrollbar buttons, but I can't find anything that actually uses them.
I have found posts that describe actions when clicking on the scroll bar body, and still others that use designer added buttons to perform the index change on the listbox. However, the scroll bar body is not visible do to the short height of the list box and it seems silly to add more buttons when I already have those two available and doing most of the work.
I have also found a post that described something similar, but using a listview. But, I would hate to have to swap the control out at this point for one feature I really think should be available somewhere on the control I'm currently using.
So, I guess what I'm looking for is a way to address the click event handler of the vertical scrollbar buttons on a listbox control.
Any help would be greatly appreciated. (Thanks all, for the 1000 other things I didn't have to post to solve here!)
Upvotes: 0
Views: 2213
Reputation: 31
I had heard about that Phil, and your right. I'm doing a replacement for the numeric up-down.
I just figured that there was probably a viable alternative, since that specific control was not originally part of the framework. I had also gotten much of it working and really like the results, and the way it picked up the theme.
Since the core of this application will become a start point for future applications, I wanted to include this functionality and was prepared to do a little work for it.
What I ended up doing was a little complicated that it was worth, but made easy with a useful helper function. I needed to search the 'Visual Tree' for my target type. From there I was able to access enough functionality to finish up.
First: Using a helper function I found here (Thanks Bruno) I was able to add this to my Loaded event:
private Double currentVerticalOffset;
private void Page_Loaded_1(object sender, RoutedEventArgs e)
{
ScrollViewer sv = Helpers.ViewHelpers.ListBoxHelper.FindVisualChild<ScrollViewer>(listbox);
sv.ScrollChanged += HandleRankScrollChange;
currentVerticalOffset = sv.VerticalOffset;
}
Then, I handle the scroll changed event:
private void HandleRankScrollChange(object sender, ScrollChangedEventArgs e)
{
ScrollViewer sv = Helpers.ViewHelpers.ListBoxHelper.FindVisualChild<ScrollViewer>(listbox);
if (sv.VerticalOffset > currentVerticalOffset)
{
Helpers.ViewHelpers.ListBoxHelper.SelectNextItem(listbox);
}
if (sv.VerticalOffset < currentVerticalOffset)
{
Helpers.ViewHelpers.ListBoxHelper.SelectPreviousItem(listbox);
}
currentVerticalOffset = sv.VerticalOffset;
}
The helpers I call here are pretty simple, but again, this will become a foundation kit, so having the methods will probably come in handy again.
public static void SelectNextItem(ListBox lb)
{
if (lb.SelectedIndex < lb.Items.Count)
{
lb.SelectedIndex++;
}
}
public static void SelectPreviousItem(ListBox lb)
{
if (lb.SelectedIndex > 0)
{
lb.SelectedIndex--;
}
}
Bruno's helper function
public static childItem FindVisualChild<childItem>(DependencyObject obj) where childItem : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is childItem)
{
return (childItem)child;
}
else
{
childItem childOfChild = FindVisualChild<childItem>(child);
if (childOfChild != null)
{
return childOfChild;
}
}
}
return null;
}
Thanks again.
Upvotes: 0