MVVMパターンを使用しており、DataGridのSelectedItemのバインディングをXAMLで作成しました。プログラムでSelectedItemを設定しましたが、設定すると、DataGridが選択範囲までスクロールしません。 MVVMパターンを完全に壊すことなくこれを達成できる方法はありますか?
次の解決策を見つけましたが、Blend SDKをインストールしたにもかかわらず、Behavior
クラスを実装しようとするとエラーが発生します: http://www.codeproject.com/Tips/125583/ScrollIntoView-for-a-DataGrid-when-using-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行もコードを入れたくない人もいることを私は知っています。しかし、この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"/>
上下にスクロールするたびに、選択変更イベントがコンボボックスに対して呼び出され、選択したアイテムをビューの外に移動することができなくなりました。