【问题标题】:WPF Datagrid, how to access validation errors from a ControlTemplateWPF Datagrid,如何从 ControlTemplate 访问验证错误
【发布时间】:2020-02-10 00:31:32
【问题描述】:

在 WPF DataGrid 中,我想在单元格内的一个小框中显示验证结果。
我通过绑定到Validation.Errors 数据结构(请参见下面的代码)设法为单个列做到这一点。
这就是我得到的,它非常接近预期的结果;现在我想为所有列实现它。

问题

为了使解决方案可在多个列上重复使用,我尝试将其移动到 ControlTemplate 中。我找不到从控件模板内部再次建立Validation.Errors 绑定的方法(请参见下面的代码)。结果,红色标签始终为空。

有效的单列解决方案

工作解决方案基于以下代码:

<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”绑定到我的示例数据上下文的名称属性来工作。

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

然后,错误标签依次绑定到前一个标签(通过其名称)并获取Validation.Errors 信息(为了清楚起见,此处删除了图形格式)。

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

这证明结果是可以实现的,但是这个方案不能在多列上重复使用,而不是一遍遍地重复。

包装尝试

为了有一个可重复使用的模板,我尝试将我所有的单元格控件(标签 x 和带有 x 错误的标签)包装到 ControlTemplate 中;它将被一个标签组件使用,这是我在网格上实际拥有的。
包装代码是这样的(下面是完整的代码):

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

关于“我的控制”

我不得不换行:

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

到这里:

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

但专用于错误的标签不再起作用(图形配置已删除):

我可以猜测它不起作用,因为只有 content 属性从模板标签转移到内部标签 x;内容而不是属性的整个“状态”,包括验证错误集合。 但是我怎样才能访问这些错误

代码

<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>

数据上下文

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";
    }
}

【问题讨论】:

    标签: c# wpf datagrid controltemplate


    【解决方案1】:

    可以参考 TemplatedParent 的 Validation.Errors,即主标签,而不是绑定到标签“x”的 Validation.Errors。 我能够将 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>
    

    【讨论】:

      猜你喜欢
      • 2011-06-29
      • 2019-06-17
      • 2011-07-03
      • 1970-01-01
      • 1970-01-01
      • 2014-08-08
      • 1970-01-01
      • 2011-05-16
      • 2021-08-13
      相关资源
      最近更新 更多