【问题标题】:WPF DataGrid ContentPresenter Binding ErrorsWPF DataGrid ContentPresenter 绑定错误
【发布时间】:2015-07-25 07:50:07
【问题描述】:

我正在使用带有 DataGridTemplateColumns 的 WPF 数据网格,每个单元格中都有组合框。启动时,输出窗口会重复以下消息并延迟启动约 10 秒。未设置与 ContentPresenter 和 DataContext 相关的内容 (DataItem=null)。如果可以的话请帮忙。这是错误消息:

System.Windows.Data 信息:10:无法使用绑定检索值,并且不存在有效的备用值;改用默认值。 BindingExpression:(无路径);数据项=空;目标元素是'ContentPresenter'(名称='');目标属性是“内容”(类型“对象”)

从技术上讲,这不是一个错误,但它仍然会延迟启动。这是 xaml 的一个子集:

<DataGrid x:Name="grid"  
          AutoGenerateColumns="False" 
          CanUserAddRows="True" 
          IsEnabled="True" Grid.Row="1" Grid.Column="0" 
          EnableRowVirtualization="False"
          HorizontalAlignment="Left"
          VerticalAlignment="Center"
          ScrollViewer.CanContentScroll="True"
          GridLinesVisibility="Vertical" 
          AreRowDetailsFrozen="True"
          HorizontalScrollBarVisibility="Visible"
          VerticalScrollBarVisibility="Visible"
          SelectionMode="Extended"
          HeadersVisibility="All"
          Height="750"
          VirtualizingStackPanel.VirtualizationMode="Standard"
          VirtualizingStackPanel.IsVirtualizing="True"
          DataContext="{StaticResource vm}"
          ItemsSource="{Binding Source={StaticResource vm}, Path=CorpActionAutoPostConfigs, Mode=TwoWay, IsAsync=False}">

         <DataGrid.Columns>
            <!-- selecteditembinding: source:enum, dest:JournalType -->
            <DataGridTemplateColumn  Header="JournalType" x:Name="colJournalType">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ComboBox x:Name="cbJournalTypes"
                                    ItemsSource="{Binding Source={StaticResource vm}, Path=JournalTypes, IsAsync=False}" 
                                    ItemTemplate="{StaticResource GenericDataTemplate}"
                                    SelectedItem="{Binding Path=JournalTypeCode, Mode=TwoWay, Converter={StaticResource JournalTypeConverter}, IsAsync=False}">
                            <ComboBox.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <VirtualizingStackPanel />
                                </ItemsPanelTemplate>
                            </ComboBox.ItemsPanel>
                        </ComboBox>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

...更多类似的列如下。我觉得我需要设置 Style 或 ControlTemplate 或其他东西,但不确定如何继续。

如果我使用 ListView/GridView 结构,则不会发生这些“错误”并且启动速度要快得多。但我更喜欢使用 DataGrid。

一个线索是,我似乎对生成的每个可见单元格都收到了该错误。所以我尝试为 DataGridCell 定义一个样式,它为每个单元格设置控件模板,并包含一个带有后备值的 ContentPresenter 绑定。没有解决错误。

        <Style TargetType="{x:Type DataGridCell}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="DataGridCell" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
                        <Border BorderThickness="{TemplateBinding Border.BorderThickness}" 
                        BorderBrush="{TemplateBinding Border.BorderBrush}" 
                        Background="{TemplateBinding Panel.Background}" 
                        SnapsToDevicePixels="True">
                        <ContentPresenter x:Name="DataGridCellContentPresenter"
Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content, FallbackValue=null}"
                        ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
                        ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" 
                        SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

编辑:

查看可视化树,我在 ControlTemplate 中定义的 ContentPresenter 似乎包含另一个 ContentPresenter。 ContentPresenter 是无名的,我怀疑是绑定错误的根源。该 ContentPresenter 的父级是 Border。有谁知道如何在 ControlTemplate 中定义这个 ContentPresenter 以便我可以添加一个后备值?

我还不能添加可视化树的屏幕截图,但它看起来是这样的:

  • 数据网格单元格
    • ContentPresenter(名称=DataGridCellPresenter)
      • ContentPresenter(未命名,Border 是父级)

【问题讨论】:

  • 出于好奇,当您使用ListView 展示此收藏时,您是否允许用户添加新内容?我有类似的问题,问题是CanUserAddRows="True"。尝试禁用此选项,看看是否有帮助。如果是这样,那么您必须为您的绑定提供 Fallback 值。 HTH
  • 是的,我已经看到了由 CanUserAddRows="True" 引起的绑定错误(关于 NewItemPlaceholder 什么的)。我遇到的绑定错误不是那个。构建 DataGrid 时似乎未设置 DataContext。后备值可能会解决此问题,但它不是我的 xaml 中的任何绑定。
  • 看来ContentPresenter 中的Content 上的绑定失败尝试删除内容绑定并在没有绑定的情况下使用它,但保留其余绑定,即&lt;ContentPresenter ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" /&gt; 我使用过ControlTemplateExpander 并且不指定 Content 属性也没问题。 HTH
  • 感谢您的建议。我删除了内容绑定,错误仍然存​​在。这很奇怪,如果每个 DataGridCell 都使用没有内容绑定的控件模板,我不太明白我是如何收到内容绑定错误的。

标签: wpf xaml datagrid


【解决方案1】:

聚会有点晚了,但我设法解决了这个问题 - 如果从 DataGridTemplateColumn 派生您自己的自定义类,您可以显式设置绑定的 FallbackValue。

显然你必须通过 XAML 并替换所需的元素。

    public sealed class DataGridTemplateColumnEx : DataGridTemplateColumn
    {
        protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
        {
            return LoadTemplateContent(false, dataItem, cell);
        }

        protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
        {
            return LoadTemplateContent(true, dataItem, cell);
        }

        private void ChooseCellTemplateAndSelector(bool isEditing, out DataTemplate template, out DataTemplateSelector templateSelector)
        {
            template = null;
            templateSelector = null;

            if (isEditing)
            {
                template = CellEditingTemplate;
                templateSelector = CellEditingTemplateSelector;
            }

            if (template == null && templateSelector == null)
            {
                template = CellTemplate;
                templateSelector = CellTemplateSelector;
            }
        }

        private FrameworkElement LoadTemplateContent(bool isEditing, object dataItem, DataGridCell cell)
        {
            ChooseCellTemplateAndSelector(isEditing, out var template, out var templateSelector);
            if (template != null || templateSelector != null)
            {
                var contentPresenter = new ContentPresenter();

                var binding = new Binding
                {
                    // Explicitly setting this to NULL, stops the binding FallbackValue messages, and therefore improves perf...
                    FallbackValue = null
                };

                BindingOperations.SetBinding(contentPresenter, ContentPresenter.ContentProperty, binding);
                contentPresenter.ContentTemplate = template;
                contentPresenter.ContentTemplateSelector = templateSelector;
                return contentPresenter;
            }

            return null;
        }
    }

【讨论】:

    猜你喜欢
    • 2011-09-18
    • 2016-07-16
    • 2014-08-08
    • 1970-01-01
    • 2015-07-02
    • 1970-01-01
    • 2016-09-22
    • 2014-08-23
    • 1970-01-01
    相关资源
    最近更新 更多