簡體   English   中英

WPF DataGrid (MVVM) 的 ScrollIntoView

[英]ScrollIntoView for WPF DataGrid (MVVM)

我正在使用 MVVM 模式,並且在 XAML 中為 DataGrid 的 SelectedItem 創建了一個綁定。 我以編程方式設置 SelectedItem,但是當我這樣做時,DataGrid 不會滾動到選擇。 有什么方法可以在不完全破壞 MVVM 模式的情況下實現這一目標?

我找到了以下解決方案,但是當我嘗試實現Behavior類時出現錯誤,即使我已經安裝了 Blend SDK:http: //www.codeproject.com/Tips/125583/ScrollIntoView-for-a-DataGrid-使用時-MVVM

這應該有效。 這個想法是你有這個附加屬性,你將附加到DataGrid 在附加它的 xaml 中,您會將其綁定到ViewModel上的屬性。 每當您想以編程方式為SelectedItem分配一個值時,您還可以為此屬性設置一個值,附加屬性綁定到該屬性。

我已將附加屬性類型設置為SelectedItem類型,但老實說,只要您將其設置為與以前不同的類型,該類型是什么並不重要。 這個附加的屬性只是被用作以 MVVM 友好的方式在視圖控件(在本例中為DataGrid )上執行一些代碼的一種方式。

所以,也就是說,這是附加屬性的代碼:

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>

我是 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 原則——而且更容易實現。

歡迎任何意見。

@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"/>

每次我向上或向下滾動時,都會為組合框調用選擇更改事件,並且不再可能將所選項目移出視圖。

這是我讓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);
}

這對我有用:

public class ScrollingDataGrid : DataGrid
{
    protected override void OnSelectionChanged(SelectionChangedEventArgs e)
    {
        var grid = e.Source as DataGrid;

        if(grid.SelectedItem != null)
        {
            grid.UpdateLayout();
            grid.ScrollIntoView(grid.SelectedItem, null);
        }

        base.OnSelectionChanged(e);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM