WPF の DataGrid コントロールにおいて、入力された値の検証を行った場合、検証エラーを示す赤枠がずれて表示される

現象
WPF アプリケーションでは、DataGrid コントロールに入力された値の検証を行うことが可能です。
入力された値で検証エラーが発生すると、エラーを示す赤枠が DataGrid 上に表示されます。
この時、全てのセルに対して BindingExpression.UpdateSource を実行して、一括で検証処理を行った場合に、検証エラーを示す赤枠がずれて表示されることがあります。
この現象は、以下のような場合に発生することがあります。
  • 検証エラーの表示後に DataGrid コントロール内のデータをスクロールさせた場合
  • 144 箇所以上の検証エラーが見つかった場合

原因
DataGrid コントロールで検証エラーが発生すると、赤枠を表示するために AdornerLayer コントロールが作成されます。
しかし、AdornerLayer コントロール、および、それらを管理する AdornerDecorator コントロールの動作に問題があり、スクロール時に赤枠がずれて表示されることがあります。
また、144 個以上の AdornerLayer コントロールが作成されると、AdornerDecorator コントロールの管理情報に問題が発生する場合があり、赤枠がずれて表示されることがあります。
状況
マイクロソフトでは、この問題をこの資料の対象製品として記載されているマイクロソフト製品の問題として認識しています。
詳細
この問題を再現する手順
  1. Visual Studio から新しいWPFアプリケーションを作成します。
  2. MainWindow.xaml に次のコードを追加します。
    <Window x:Class="WindowsAppliation1.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        xmlns:local="clr-namespace:WindowsAppliation1"        Title="MainWindow" Height="450" Width="600">    <Grid>        <DataGrid Name="dataGrid1" AutoGenerateColumns="False" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,30,0,0">            <DataGrid.Columns>                <DataGridTextColumn Header="ID">                    <DataGridTextColumn.Binding>                        <Binding Path="id" Mode="TwoWay">                            <Binding.ValidationRules>                                <local:NullCheckValidationRule />                            </Binding.ValidationRules>                        </Binding>                    </DataGridTextColumn.Binding>                </DataGridTextColumn>                <DataGridTextColumn Header="NAME">                    <DataGridTextColumn.Binding>                        <Binding Path="name" UpdateSourceTrigger="Explicit" Mode="TwoWay" ValidatesOnDataErrors="True">                            <Binding.ValidationRules>                                <local:NullCheckValidationRule />                            </Binding.ValidationRules>                        </Binding>                    </DataGridTextColumn.Binding>                </DataGridTextColumn>                <DataGridTextColumn Header="ADDRESS">                    <DataGridTextColumn.Binding>                        <Binding Path="address" UpdateSourceTrigger="Explicit" Mode="TwoWay" ValidatesOnDataErrors="True">                            <Binding.ValidationRules >                                <local:NullCheckValidationRule />                            </Binding.ValidationRules>                        </Binding>                    </DataGridTextColumn.Binding>                </DataGridTextColumn>            </DataGrid.Columns>        </DataGrid>        <Button Name="button1" Content="TEST" HorizontalAlignment="Left" VerticalAlignment="Top" Click="button1_Click" />    </Grid></Window>
  3. MainWindow.xaml.cs に次のコードを追加します。
    namespace WindowsAppliation1{    public partial class MainWindow : Window    {        private DataTable dt;        public MainWindow()        {            InitializeComponent();            dt = new DataTable();            dt.Columns.Add(new DataColumn("id"));            dt.Columns.Add(new DataColumn("name"));            dt.Columns.Add(new DataColumn("address"));            for (int i = 0; i <= 100; i++)            {                if (i % 5 == 0)                    dt.Rows.Add(i.ToString(), "name" + i.ToString(), "address" + i.ToString());                else                    dt.Rows.Add(i.ToString(), "name" + i.ToString(), DBNull.Value);            }            dt.AcceptChanges();            dataGrid1.ItemsSource = dt.DefaultView;            dataGrid1.EnableRowVirtualization = false;            dataGrid1.EnableColumnVirtualization = false;        }        private void button1_Click(object sender, RoutedEventArgs e)        {            for (int rowIndex = 0; rowIndex < dataGrid1.Items.Count; rowIndex++)            {                DataGridRow rowContainer = (DataGridRow)dataGrid1.ItemContainerGenerator.ContainerFromIndex(rowIndex);                DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);                for (int columnIndex = 0; columnIndex < dataGrid1.Columns.Count; columnIndex++)                {                    DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex);                    BindingExpression expression = BindingOperations.GetBindingExpression(GetVisualChild<TextBlock>(cell), TextBlock.TextProperty);                    expression.UpdateSource();                }            }        }        public static T GetVisualChild<T>(Visual parent) where T : Visual        {            T child = default(T);            int numVisuals = VisualTreeHelper.GetChildrenCount(parent);            for (int i = 0; i < numVisuals; i++)            {                Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);                child = v as T;                if (child == null)                    child = GetVisualChild<T>(v);                else                    break;            }            return child;        }    }    public class NullCheckValidationRule : ValidationRule    {        public override ValidationResult Validate(object value, CultureInfo cultureInfo)        {            string str = value as string;            if (String.IsNullOrEmpty(str))                return new ValidationResult(false, "error");            else                return new ValidationResult(true, null);        }    }}
  4. アプリケーションを実行します。
  5. Button コントロールをクリックします


結果

Button コントロールをクリックすると DataGrid コントロールの値の検証が行われ、検証エラーの位置に赤枠が表示されます。

この後 DataGrid コントロールをスクロールすると、赤枠がずれる現象が発生します。

なお、本問題が発生したとしても、実際のデータには影響はありません。




回避策
問題が発生した場合には、Alt キーを押下することにより表示が正常になります。
これは、Alt キーが押下された際の WPF の内部処理で AdornerLayer コントロールが再作成されるためです。


注意 : これは、マイクロソフトのサポート組織内で直接作成された "緊急公開" の資料です。 この資料には、確認中の問題に関する現状ベースの情報が記載されています。 情報提供のスピードを優先するため、資料には誤植が含まれる可能性があり、予告なしに随時改定される場合があります。 その他の考慮事項については、使用条件を参照してください。
プロパティ

文書番号:2784772 - 最終更新日: 09/29/2016 14:44:00 - リビジョン: 3.0

Microsoft .NET Framework 4.0, Microsoft .NET Framework 4.5

  • kbnofix kbexpertiseadvanced KB2784772
フィードバック