5
votes

I have a view with two listboxes:

Listbox 1 elements: A, B, C. Listbox 2 elements: ..., A, ..., B, ..., C, ... (long list).

When the user selects an element in listbox 1, I want to scroll the same element into view (not select) also in listbox 2.

In my viewmodel I have a property bound to the SelectedItem of Listbox 2. But how can I scroll that element into view of listbox 2? Of course I cannot do listbox.ScrollIntoView(selectedItem) in my VM.

What's the best solution to solve this problem with the MVVM pattern?

1

1 Answers

8
votes

You can do this with a behavior, a simple solution wouldn't involve the VM at all:

public static class ScrollToSelectedBehavior
{
    public static readonly DependencyProperty SelectedValueProperty = DependencyProperty.RegisterAttached(
        "SelectedValue",
        typeof(object),
        typeof(ScrollToSelectedBehavior),
        new PropertyMetadata(null, OnSelectedValueChange));

    public static void SetSelectedValue(DependencyObject source, object value)
    {
        source.SetValue(SelectedValueProperty, value);
    }

    public static object GetSelectedValue(DependencyObject source)
    {
        return (object)source.GetValue(SelectedValueProperty);
    }

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

Which you would use like this:

<ListBox x:Name="lb1" ItemsSource="{Binding Items}" />
<ListBox x:Name="lb2" ItemsSource="{Binding Items}" behaviors:ScrollToSelectedBehavior.SelectedValue="{Binding ElementName=lb1, Path=SelectedValue}"/>

A slightly better solution would be to instead bind the behavior's DP to an object in the VM which raises an event whenever the selected value in listbox1 changes. That would expose this feature to the VM code and also allow for unit testing etc.