WPF Datagrid, как получить доступ к ошибкам проверки из ControlTemplate - PullRequest
1 голос
/ 10 февраля 2020

В WPF DataGrid я хочу показать результат проверки в небольшом поле внутри ячейки.
Мне удалось сделать это для одного столбца, связавшись со структурой данных Validation.Errors (см. Код ниже) .
Это то, что я получил, и это довольно близко к желаемому результату; Теперь я хочу реализовать это для всех столбцов.

Small validation message as a box in the cell

Проблема

Чтобы сделать решение многократно используемым по нескольким столбцам, я попытался переместить его в ControlTemplate. Я не смог найти способ установить sh привязку Validation.Errors снова из шаблона управления (см. Код ниже). В результате красная метка всегда пуста.

Empty error box: doesn't work

Рабочее одноколоночное решение

Рабочее решение основано на следующем коде:

<DataGrid ItemsSource="{Binding People}" AutoGenerateColumns="False" CanUserAddRows="False">
    <DataGrid.Columns>

        <DataGridTemplateColumn Header="Name">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Grid>
                        <Label x:Name="x" Content="{Binding Name}"/>
                        <Label Padding="2" HorizontalAlignment="Right" VerticalAlignment="Top" Height="15" Width="44" FontSize="8" Foreground="White" Background="Red"
                        Content="{Binding ElementName='x', Path='(Validation.Errors)[0].ErrorContent'}"/>
                    </Grid>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

    </DataGrid.Columns>
</DataGrid>

Нет необходимости читать все это: вот соответствующие части

Он работает, привязывая метку "x" к свойству Name моего примера datacontext.

<Label x:Name="x" Content="{Binding Name}"/>

Затем метка ошибки в свою очередь связывается с предыдущей меткой (через свое имя) и получает информацию Validation.Errors (графические форматы здесь удалены для ясности).

<Label Content="{Binding ElementName='x', Path='(Validation.Errors)[0].ErrorContent'}"/>

Это доказывает, что результат достижим, но это решение нельзя использовать повторно для нескольких столбцов, не повторяя его снова и снова.

Попытка обтекания

Чтобы получить шаблон многократного использования, я попытался обернуть все мои контуры ячеек (метка x и метка с ошибками x) в ControlTemplate; он будет использоваться компонентом Label, который фактически будет у меня в сетке.
Код переноса таков (ниже приведен полный код):

<Label Content="{Binding Name}">
    <Label.Template>
       <ControlTemplate TargetType="Label">
          //my controls
       </ControlTemplate>
    </Label.Template>
</Label>

About "мои элементы управления "

Мне пришлось изменить строку:

<Label x:Name="x" Content="{Binding Name}"/>

на эту:

<Label x:Name="x" Content="{TemplateBinding Content}"/>

Но ярлык, посвященный ошибкам, больше не работает (конфигурация графики удалена) :

Empty error box: doesn't work

Я могу догадаться, что это не работает, потому что только свойство содержимого передается из шаблонной метки в внутренняя метка х; содержание, а не все «состояние» свойства, включая коллекцию ошибок проверки. Но как я могу получить доступ к этим ошибкам тогда ?

Код

<Window.DataContext>
    <local:ViewModel/>
</Window.DataContext>

<DataGrid ItemsSource="{Binding People}" AutoGenerateColumns="False" CanUserAddRows="False">
    <DataGrid.Columns>

        <DataGridTemplateColumn Header="Name">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>

                    <Label Content="{Binding Name}">

                        <Label.Template>
                            <ControlTemplate TargetType="Label">
                                <Grid>
                                    <Label x:Name="x" Content="{TemplateBinding Content}"/>
                                    <Label Padding="2" HorizontalAlignment="Right" VerticalAlignment="Top" Height="15" Width="44" FontSize="8" Foreground="White" Background="Red"
                                Content="{Binding ElementName='x', Path='(Validation.Errors)[0].ErrorContent'}"/>
                                </Grid>
                            </ControlTemplate>
                        </Label.Template>

                    </Label>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

    </DataGrid.Columns>
</DataGrid>

DataContext

public class ViewModel
{
    public ObservableCollection<Person> People { get; } = new ObservableCollection<Person>() { new Person { Name = "Alan" } };
}

public class Person: INotifyDataErrorInfo
{
    public string Name { get; set; }

    public bool HasErrors => true;

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    public IEnumerable GetErrors(string propertyName)
    {
        yield return "Some error";
    }
}

1 Ответ

1 голос
/ 10 февраля 2020

Вместо привязки к проверке. Ошибки метки «x» можно ссылаться на валидацию. Ошибки шаблона TemplatedParent, то есть основной метки. Мне удалось извлечь ControlTemplate в ресурс окна и использовать этот ресурс в качестве шаблона метки, чтобы мы могли повторно использовать этот шаблон.

<Window.Resources>
    <ControlTemplate TargetType="Label" x:Key="Lbl">
        <Grid>
            <Label x:Name="x" Content="{TemplateBinding Content}"/>
            <Label Padding="2" HorizontalAlignment="Right" VerticalAlignment="Top" Height="15" Width="44" FontSize="8" Foreground="White" Background="Red"
                   Content="{Binding (Validation.Errors)[0].ErrorContent, RelativeSource={RelativeSource TemplatedParent}}"/>
        </Grid>
    </ControlTemplate>
</Window.Resources>

<DataGrid ItemsSource="{Binding People}" AutoGenerateColumns="False" CanUserAddRows="False">
    <DataGrid.Columns>

        <DataGridTemplateColumn Header="Name">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>

                    <Label Content="{Binding Name}"
                           Template="{StaticResource Lbl}">

                    </Label>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

    </DataGrid.Columns>
</DataGrid>
...