WPF DataGrid (MVVM) 的 ScrollIntoView
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18019425/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ScrollIntoView for WPF DataGrid (MVVM)
提问by Andy
I'm using the MVVM pattern, and I've created a binding in XAML for the SelectedItem of a DataGrid. I programatically set the SelectedItem, however when I do so the DataGrid does not scroll to the selection. Is there any way I can achieve this without completely breaking the MVVM pattern?
我正在使用 MVVM 模式,并且我已经在 XAML 中为 DataGrid 的 SelectedItem 创建了一个绑定。我以编程方式设置了 SelectedItem,但是当我这样做时,DataGrid 不会滚动到选择。有什么方法可以在不完全破坏 MVVM 模式的情况下实现这一目标?
I found the following solution but I get an error when I try to implement the Behaviorclass, even though I've installed Blend SDK: http://www.codeproject.com/Tips/125583/ScrollIntoView-for-a-DataGrid-when-using-MVVM
我找到了以下解决方案,但是当我尝试实现Behavior该类时出现错误,即使我已经安装了 Blend SDK:http: //www.codeproject.com/Tips/125583/ScrollIntoView-for-a-DataGrid-when -使用-MVVM
回答by Gjeltema
This should work. The idea is you have this attached property that you will attach to the DataGrid. In the xaml where you attach it, you'll bind it to a property on your ViewModel. Whenever you want to programmatically assign a value to the SelectedItem, you also set a value to this property, which the attached property is bound to.
这应该有效。这个想法是你有这个附加的属性,你将附加到DataGrid. 在附加它的 xaml 中,您将它绑定到ViewModel. 每当您想以编程方式为 分配一个值时SelectedItem,您还要为此属性设置一个值,附加属性绑定到该属性。
I've made the attached property type to be whatever the SelectedItemtype is, but honestly it doesn't matter what the type is as long as you set it to something different than what it was before. This attached property is just being used as a means to execute some code on the view control (in this case, a DataGrid) in an MVVM friendly fashion.
我已经将附加属性类型设为任何SelectedItem类型,但老实说,只要您将其设置为与以前不同的类型,类型是什么并不重要。此附加属性仅用作DataGrid以 MVVM 友好方式在视图控件(在本例中为 a )上执行某些代码的一种方式。
So, that said, here's the code for the attached property:
所以,也就是说,这是附加属性的代码:
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);
}));
}
}
}
And here's the xaml snippet:
这是 xaml 片段:
<Window ...
xmlns:attachedProperties="clr-namespace:MyAttachedProperties">
...
<DataGrid
attachedProperties:SelectingItemAttachedProperty.SelectingItem="{Binding MyViewModel.SelectingItem}">
...
</DataGrid>
</Grid>
回答by Edgar
I am new to MVVM. I understand the idea of MVVM and try to implement everything correctly. I had a similar problem to above and I ended up with 1 line in XAML and 1 line in code behind. The rest of the code is in the VM. I did the following in XAML
我是 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">
And this in the code behind:
这在后面的代码中:
private void Selection1List_SelectionChanged(object sender, SelectionChangedEventArgs e) {
Selection1List.ScrollIntoView(Selection1List.SelectedItem);
}
and this works fine.
这很好用。
I know some people don't want even one line of code in the code behind the window. But I think this 1 line is just for the view. It has nothing to do with the data or with the logic of the data. So I would think this is no violation of the MVVM principle - and so much easier to implement.
我知道有些人甚至不想要窗口后面的代码中的一行代码。但我认为这 1 行只是为了查看。它与数据或数据的逻辑无关。所以我认为这并没有违反 MVVM 原则——而且更容易实现。
Any comments are welcome.
欢迎提出任何意见。
回答by AelanY
The solution of @Edgar works fine, but in my application I had to check the OriginalSource of the SelectionChangedEventArgs as well.
@Edgar 的解决方案工作正常,但在我的应用程序中,我还必须检查 SelectionChangedEventArgs 的 OriginalSource。
private void OperatorQualificationsTable_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if ((OperatorQualificationsTable.SelectedItem != null) && (e.OriginalSource?.Equals(OperatorQualificationsTable) ?? false))
{
OperatorQualificationsTable.ScrollIntoView(OperatorQualificationsTable.SelectedItem);
}
}
My datagrid contains following ComboBoxColumn
我的数据网格包含以下 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"/>
Everytime when I scrolled up or down the selction changed event was called for the Combobox and it was no longer possible to move the selected item out of the view.
每次当我向上或向下滚动时,组合框都会调用选择更改事件,并且不再可能将所选项目移出视图。
回答by marsh-wiggle
This is my solution to get ScrollIntoViewworking. I perform the operation in the LayoutUpdated()event
这是我开始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);
}

