我正在尝试创建一个WPF自定义滑块控件,它充当Listview的滚动条。我这样做是通过将listview的名称放在我的自定义滑块的Tag属性中,然后使用滑块的OnValueChange事件来滚动列表视图。这很好用,但是当我使用鼠标滚轮滚动列表视图时,滑块不会移动。我需要的是一种在我的自定义滑块初始化时将方法附加到listview的MouseWheel事件的方法。这是我尝试过的:
自定义滑块类:
public class LabeledScrollbar : Slider
{
public override void EndInit()
{
var listbox = (ListBox)this.FindName(this.Tag.ToString());
if (listbox != null)
{
listbox.MouseWheel += new MouseWheelEventHandler(this.OnMouseWheel);
}
base.EndInit();
}
protected void OnMouseWheel(object sender, MouseWheelEventArgs e)
{
this.Value += 5;
}
protected override void OnValueChanged(double oldValue, double newValue)
{
var listBox = (ListBox)this.FindName(this.Tag.ToString());
var collection = (CollectionView)CollectionViewSource.GetDefaultView(listBox.ItemsSource);
if (newValue == this.Maximum)
{
if (VisualTreeHelper.GetChildrenCount(listBox) > 0)
{
var chrome = VisualTreeHelper.GetChild(listBox, 0);
var scrollView = (ScrollViewer)VisualTreeHelper.GetChild(chrome, 0);
scrollView.ScrollToTop();
}
}
else
{
var index = (collection.Count - 1) - (int)Math.Floor(newValue);
var selectedItem = collection.GetItemAt(index);
listBox.ScrollIntoView(selectedItem);
}
}
}
XAML:
<ListView x:Name="listViewCategories">
...
</ListView>
<local:LabeledScrollbar x:Name="categoryScrollbar" Orientation="Vertical" TickPlacement="BottomRight" Tag="listViewCategories"></local:LabeledScrollbar>
虽然我在列表视图中滚动时似乎会触发OnMouseWheel,但它没有发生,我无法找到任何其他尝试。有没有办法在WPF中做我想做的事情?我知道我可以在我的视图后面的代码中放置一个方法来使listview的MouseScroll事件移动滑块,但我希望尽可能多地封装滑块类中滑块的逻辑。
答案 0 :(得分:0)
所以似乎诀窍是使用PreviewMouseWheel而不是MouseWheel。以下是我目前的课程:
/// <summary>
/// This class creates a custom control that can be used as a scrollbar for a listbox that displays the current
/// group visible in the listbox on a small label next to the slider thumb.
///
/// To use it, set the Tag value to the name of the listbox the scollbar will be controlling.
/// </summary>
public class LabeledScrollbar : Slider
{
//Tracks control initialization to ensure it only gets loaded once
private bool initialized = false;
//The listview this slider will control
private ListView listView;
public LabeledScrollbar(): base()
{
this.Loaded += LabeledScrollbar_Loaded;
}
void LabeledScrollbar_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
//The tag must be set to the name of a listbox
listView = (ListView)this.FindName(this.Tag.ToString());
if (listView != null && !this.initialized)
{
//Make sure that the mouse wheel event in the linked listbox is handled
listView.PreviewMouseWheel += (s, ev) =>
{
if (ev.Delta > 0)
this.Value += 3;
else
this.Value -= 3;
};
//Move scrollbar and list to the top if the collection changes
((INotifyCollectionChanged)listView.Items).CollectionChanged += (s, ev) =>
{
this.Maximum = ((ItemCollection)listView.Items).Count - 1;
this.Value = this.Maximum;
};
//Get the max value of the slider by checking the tag value and looking up the associated listbox
this.Maximum = ((ItemCollection)listView.Items).Count - 1;
this.Value = this.Maximum;
this.initialized = true;
}
}
protected override void OnValueChanged(double oldValue, double newValue)
{
//Refresh the tickbar so that it will render for a new value
InvalidateTickbar();
//Scroll the list box to the correct location
ScrollToIndex(newValue);
}
private void ScrollToIndex(double newValue)
{
if (newValue == this.Maximum)
{
//ScrollIntoView method does not scroll to the top so
//we need to access the scrollview to move the slider to the top
if (VisualTreeHelper.GetChildrenCount(listView) > 0)
{
var chrome = VisualTreeHelper.GetChild(listView, 0);
var scrollView = (ScrollViewer)VisualTreeHelper.GetChild(chrome, 0);
scrollView.ScrollToTop();
}
}
else
{
var collection = (CollectionView)CollectionViewSource.GetDefaultView(listView.ItemsSource);
var index = (collection.Count - 1) - (int)Math.Floor(newValue);
var selectedItem = collection.GetItemAt(index);
listView.ScrollIntoView(selectedItem);
}
}
private void InvalidateTickbar()
{
//update the tickbar for the new position
if (VisualTreeHelper.GetChildrenCount(this) > 0)
{
var firstChild = VisualTreeHelper.GetChild(this, 0);
if (VisualTreeHelper.GetChildrenCount(firstChild) > 0)
{
var secondChild = (CustomTickBar)VisualTreeHelper.GetChild(firstChild, 0);
secondChild.InvalidateVisual();
}
}
}
}