質問者
DataGridコントロールのスクロールバーの動作がおかしい?

質問
-
お世話になります。Windows Server 2008 R2 Standard、VS2010、Silverlight4で開発をしています。
ObservableCollection、INotifyPropertyChangedを用いたデータとDataGridを連携させた、以下のようなアプリケーションを作りました。
このアプリにおいて10件くらいデータを入れた後、最後尾のデータを削除したり、Updateボタンで変更します。
すると、スクロールボックスを一番下から上にゆっくり動かしたときに、スクロールボックスが一瞬ジャンプするようになります。
その時、データグリッドのスクロールもジャンプしてしまいます。
また、スクロールボックスを一番上から下にゆっくり動かしたとき、スクロールボックスはジャンプしませんが、
データグリッドのスクロールは少しジャンプしてしまいます。
(最後尾でないデータでもたまにおかしくなる場合があるようですが、おかしくなったりならなかったりします。)
私のソースコードが悪いのか、Silverlightのバグなのか、判断がつかないので質問させて頂きました。
動作検証を含め、なにかヒントになることをご教示いただければ幸いです。
ソースコードは以下のとおりです。
MainPage.xaml
<UserControl x:Class="GridTest.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" Loaded="UserControl_Loaded"> <Grid x:Name="LayoutRoot" Background="White"> <Button Content="Add" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" /> <Button Content="Update" Height="23" HorizontalAlignment="Left" Margin="93,12,0,0" Name="button2" VerticalAlignment="Top" Width="75" Click="button2_Click" /> <Button Content="Delete" Height="23" HorizontalAlignment="Left" Margin="174,12,0,0" Name="button3" VerticalAlignment="Top" Width="75" Click="button3_Click" /> <TextBox Height="100" HorizontalAlignment="Left" Margin="12,41,0,0" Name="textBox1" VerticalAlignment="Top" Width="376" AcceptsReturn="True" /> <sdk:DataGrid AutoGenerateColumns="False" Height="141" HorizontalAlignment="Left" Margin="12,147,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="376" SelectionChanged="dataGrid1_SelectionChanged" /> </Grid> </UserControl>
MainPage.xaml.csusing System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.ComponentModel; namespace GridTest { public partial class MainPage : UserControl { System.Collections.ObjectModel.ObservableCollection<Datas> rows; public MainPage() { InitializeComponent(); } private void UserControl_Loaded(object sender, RoutedEventArgs e) { rows = new System.Collections.ObjectModel.ObservableCollection<Datas>(); dataGrid1.ItemsSource = rows; DataGridTextColumn dataColumn1; dataColumn1 = new DataGridTextColumn(); dataColumn1.Header = "String"; dataColumn1.IsReadOnly = true; dataColumn1.Binding = new System.Windows.Data.Binding("Str"); dataGrid1.Columns.Add(dataColumn1); } private void button1_Click(object sender, RoutedEventArgs e) { Datas a = new Datas(); a.Str = textBox1.Text; rows.Add(a); } private void button2_Click(object sender, RoutedEventArgs e) { if (dataGrid1.SelectedItem != null) { Datas a = new Datas(); a.Str = textBox1.Text; rows[dataGrid1.SelectedIndex] = a; } } private void button3_Click(object sender, RoutedEventArgs e) { if (dataGrid1.SelectedItem != null) { rows.Remove(dataGrid1.SelectedItem as Datas); } } private void dataGrid1_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (dataGrid1.SelectedItem != null) { textBox1.Text = ((Datas)dataGrid1.SelectedItem).Str; } } } public class Datas : INotifyPropertyChanged { private string _str; public string Str { get { return _str; } set { if (_str != value) { _str = value; OnPropertyChanged("Str"); } } } #region INotifyPropertyChanged メンバ /// <summary> /// プロパティ変更時のイベント /// </summary> public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { if (PropertyChanged != null) PropertyChanged(this, e); } protected virtual void OnPropertyChanged(string name) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(name)); } #endregion } }
- 編集済み monger_monger 2011年9月7日 5:26
2011年9月7日 2:54
すべての返信
-
勘なので検証も何もしてない回答で申し訳ないですが、たぶんDataGridの行が仮想化されてるため、非表示部分の追加や削除については、スクロールバーが正確に追随してないのでは?と思います。
ここらへんをとっかかりに何か調べられないでしょうか。私自身が調べる時間があまりないので、このような形の情報提供になってしまいもうしわけありません。
かずき Blog:http://d.hatena.ne.jp/okazuki/ VS 2010のデザイナでBlendのBehaviorをサポートするツール公開してます。 http://vsbehaviorsupport.codeplex.com/2011年9月7日 8:09 -
DataGridを継承したコントロールを作成していますが、スクロールがおかしくなるパターンは他にも色々とあるようです(開発中に何度も悩まされました)。
かずきさんが仰られているとおり、DataGridは行の仮想化の関係上、ContentPresenterとScrollBarが分離しています。このため、DataGridのスクロールの計算が、行の追加削除に正確に対応していないのではないのではないかと考えています。
特に確証がある情報は提供できませんが、monger_mongerさんのコードに問題は無いように思います。
対処療法ですが、DataGridの行高さはできるだけ、動的に変更しないほうが良いようです。
以上、ご参考まで。
2011年9月7日 9:08