23

我正在使用 MVVM 模式,并且在 XAML 中为 DataGrid 的 SelectedItem 创建了一个绑定。我以编程方式设置 SelectedItem,但是当我这样做时,DataGrid 不会滚动到选择。有什么方法可以在不完全破坏 MVVM 模式的情况下实现这一目标?

我找到了以下解决方案,但是当我尝试实现Behavior该类时出现错误,即使我已经安装了 Blend SDK: http: //www.codeproject.com/Tips/125583/ScrollIntoView-for-a-DataGrid-when -使用-MVVM

4

4 回答 4

38

这应该有效。这个想法是你有这个附加属性,你将附加到DataGrid. 在附加它的 xaml 中,您会将其绑定到ViewModel. 每当您想以编程方式为 分配一个值时SelectedItem,您还可以为此属性设置一个值,附加属性绑定到该属性。

我已经将附加的属性类型设置为任何SelectedItem类型,但老实说,只要将其设置为与以前不同的类型,类型是什么并不重要。这个附加的属性只是被用作以DataGridMVVM 友好的方式在视图控件(在本例中为 a )上执行某些代码的一种方式。

所以,也就是说,这是附加属性的代码:

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>
于 2013-08-03T03:04:18.740 回答
22

我是 MVVM 的新手。我理解 MVVM 的想法并尝试正确地实现一切。我遇到了与上面类似的问题,最后我在 XAML 中有 1 行,在后面的代码中有 1 行。其余代码在 VM 中。我在 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 原则——而且更容易实现。

欢迎任何意见。

于 2017-04-15T10:39:13.610 回答
1

这是我开始ScrollIntoView工作的解决方案。我在LayoutUpdated()事件中执行操作

public void ManipulateData()
{
    // Add a new record or what else is needed;
    myItemsSourceCollection.Add(...); 

    // Not needed when the ItemsSource is a ObervableCollectin 
    // with correct Binding (ItemsSource="{ Binding myItemsSourceElement }")
    myDataGrid.Items.Refresh();

    // Goto last Item or where ever
    myDataGrid.SelectedIndex = this.myDataGrid.Items.Count - 1;
}

// The LayoutUpdated event for the DataGrid
private void myDataGrid_LayoutUpdated(object sender, EventArgs e)
{
    if (myDataGrid.SelectedItem == null)
        return;
    //<----------

    // may become improved to check first if the `ScrollIntoView()` is really needed

    // To prevent hanging here the ItemsSource must be 
    // a) an ObervableCollection with a correct working binding or
    // b) myDataGrid.Items.Refresh(); must be called after changing
    // the data
    myDataGrid.ScrollIntoView(myDataGrid.SelectedItem, null);
}
于 2020-05-22T05:30:35.473 回答
1

@Edgar 的解决方案工作正常,但在我的应用程序中,我还必须检查 SelectionChangedEventArgs 的 OriginalSource。

private void OperatorQualificationsTable_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if ((OperatorQualificationsTable.SelectedItem != null) && (e.OriginalSource?.Equals(OperatorQualificationsTable) ?? false))
    {
        OperatorQualificationsTable.ScrollIntoView(OperatorQualificationsTable.SelectedItem);
    }
}

我的数据网格包含以下 ComboBoxColumn

<dgx:EnhancedDataGridComboBoxColumn 
    DisplayMemberPath="DescriptionNL"
    Header="{x:Static nl:Strings.Label_Qualification}"
    ItemsSource="{Binding Path=QualificationKeysView, Source={StaticResource ViewModel}}"
    SelectedValueBinding="{Binding ActivityQualification.QualificationKey}"
    SelectedValuePath="QualificationKey"/>

每次我向上或向下滚动时,都会为组合框调用选择更改事件,并且不再可能将所选项目移出视图。

于 2019-03-13T17:13:01.207 回答