ScrollIntoView для WPF DataGrid (MVVM) - программирование
Подтвердить что ты не робот

ScrollIntoView для WPF DataGrid (MVVM)

Я использую шаблон MVVM, и я создал привязку в XAML для SelectedItem DataGrid. Я программно устанавливаю SelectedItem, однако, когда я это делаю, DataGrid не просматривает выделение. Можно ли каким-либо образом добиться этого без полного разрушения шаблона MVVM?

Я нашел следующее решение, но получаю сообщение об ошибке при попытке реализовать класс Behavior, хотя я установил Blend SDK: http://www.codeproject.com/Tips/125583/ScrollIntoView-for-a-DataGrid-when-using-MVVM

4b9b3361

Ответ 1

Это должно сработать. Идея заключается в том, что у вас есть это прикрепленное свойство, которое вы присоедините к DataGrid. В xaml, где вы его прикрепляете, вы привяжете его к свойству на ViewModel. Всякий раз, когда вы хотите программно присвоить значение SelectedItem, вы также устанавливаете значение для этого свойства, к которому привязано связанное свойство.

Я сделал тип прикрепленного типа таким, какой бы тип SelectedItem не был, но, честно говоря, не имеет значения, какой тип до тех пор, пока вы установите его на нечто иное, чем то, что было раньше. Это прикрепленное свойство просто используется как средство для выполнения некоторого кода в элементе управления представлением (в данном случае a DataGrid) в режиме MVVM.

Итак, вот здесь код для прикрепленного свойства:

namespace MyAttachedProperties
{
    public class SelectingItemAttachedProperty
    {
        public static readonly DependencyProperty SelectingItemProperty = DependencyProperty.RegisterAttached(
            "SelectingItem",
            typeof(MySelectionType),
            typeof(SelectingItemAttachedProperty),
            new PropertyMetadata(default(MySelectionType), OnSelectingItemChanged));

        public static MySelectionType GetSelectingItem(DependencyObject target)
        {
            return (MySelectionType)target.GetValue(SelectingItemProperty);
        }

        public static void SetSelectingItem(DependencyObject target, MySelectionType value)
        {
            target.SetValue(SelectingItemProperty, value);
        }

        static void OnSelectingItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var grid = sender as DataGrid;
            if (grid == null || grid.SelectedItem == null)
                return;

            // Works with .Net 4.5
            grid.Dispatcher.InvokeAsync(() => 
            {
                grid.UpdateLayout();
                grid.ScrollIntoView(grid.SelectedItem, null);
            });

            // Works with .Net 4.0
            grid.Dispatcher.BeginInvoke((Action)(() =>
            {
                grid.UpdateLayout();
                grid.ScrollIntoView(grid.SelectedItem, null);
            }));
        }
    }
}

И вот фрагмент xaml:

<Window ...
        xmlns:attachedProperties="clr-namespace:MyAttachedProperties">
    ...
        <DataGrid 
            attachedProperties:SelectingItemAttachedProperty.SelectingItem="{Binding MyViewModel.SelectingItem}">
            ...
        </DataGrid>
    </Grid>

Ответ 2

Я новичок в MVVM. Я понимаю идею MVVM и стараюсь реализовать все правильно. У меня была аналогичная проблема выше, и я закончил с 1 строкой в ​​XAML и 1 строкой в ​​коде. Остальная часть кода находится в виртуальной машине. Я сделал следующее в XAML

<ListBox DockPanel.Dock="Top"
    Name="Selection1List" 
    ItemsSource="{Binding SelectedList1ItemsSource}" 
    SelectedItem="{Binding SelectedList1Item}"
    SelectedIndex="{Binding SelectedList1SelectedIndex}"
    SelectionChanged="Selection1List_SelectionChanged">

И это в коде позади:

private void Selection1List_SelectionChanged(object sender, SelectionChangedEventArgs e) {
    Selection1List.ScrollIntoView(Selection1List.SelectedItem);
}

и это отлично работает.

Я знаю, что некоторые люди не хотят даже одной строки кода в коде за окном. Но я думаю, что эта 1 строка предназначена только для представления. Он не имеет ничего общего с данными или с логикой данных. Поэтому я думаю, что это не является нарушением принципа MVVM - и намного проще реализовать.

Любые комментарии приветствуются.