C# 未在控件模板中为datagrid设置依赖项属性
我需要定制datagrid,所以我创建了自己的datagrid扩展WPF datagrid。小相关代码贴在下面-C# 未在控件模板中为datagrid设置依赖项属性,c#,wpf,xaml,datagrid,wpfdatagrid,C#,Wpf,Xaml,Datagrid,Wpfdatagrid,我需要定制datagrid,所以我创建了自己的datagrid扩展WPF datagrid。小相关代码贴在下面- public class ExtendedDataGrid : DataGrid { public ExtendedDataGrid() { this.SelectionMode = DataGridSelectionMode.Extended; } } 我在一个窗口中创建了它的实例,并将SelectionMode设置为Single,这可以很
public class ExtendedDataGrid : DataGrid
{
public ExtendedDataGrid()
{
this.SelectionMode = DataGridSelectionMode.Extended;
}
}
我在一个窗口中创建了它的实例,并将SelectionMode
设置为Single
,这可以很好地工作,并且为dataGrid将属性设置为Single
。到目前为止一切都很好
但如果我将数据网格放在ControlTemplate中,SelectionMode
永远不会设置为Single
。SelectionMode只是一个例子,若我在DataGrid的构造函数中显式设置了该值,那个么就并没有通过XAML设置DP
小样本复制问题就在这里-
<Grid>
<Grid.Resources>
<ControlTemplate x:Key="MyTemplate">
<local:ExtendedDataGrid ItemsSource="{Binding Collection,
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType=Window}}"
SelectionMode="Single">
<local:ExtendedDataGrid.Columns>
<DataGridTextColumn Binding="{Binding}"/>
</local:ExtendedDataGrid.Columns>
</local:ExtendedDataGrid>
</ControlTemplate>
</Grid.Resources>
<ContentControl Template="{StaticResource MyTemplate}"/>
<local:ExtendedDataGrid ItemsSource="{Binding Collection,
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType=Window}}"
Grid.Row="1" SelectionMode="Single">
<local:ExtendedDataGrid.Columns>
<DataGridTextColumn Binding="{Binding}"/>
</local:ExtendedDataGrid.Columns>
</local:ExtendedDataGrid>
</Grid>
对于第二个DataGrid,其工作正常,但对于放置在ControlTemplate中的DataGrid不起作用为什么会有这种奇怪的行为?这是DataGrid代码中的错误吗?
注意-如果我对DataGrid中的行进行注释,它将正常工作
构造函数,其中我显式地将SelectionMode设置为
延长。我知道这是默认值,删除它之后
在这两种情况下都可以正常工作(还有很多方法可以设置默认值),但我想知道为什么它在一种情况下工作,而在另一种情况下不工作
很抱歉,我无法回答您的问题,即为什么在使用
ControlTemplate
时它不起作用,但我可以为您提供更好的方法,为扩展类中的继承属性设置默认值,这可以解决您的问题
可以使用dependencProperty.OverrideMetadata
方法为继承的dependencProperty
提供具有默认值的新元数据。您可以使用static
构造函数为SelectionMode
属性设置自己的默认值,如下所示:
static ExtendedDataGrid()
{
SelectionModeProperty.OverrideMetadata(typeof(ExtendedDataGrid),
new FrameworkPropertyMetadata(2));
}
更新>>> 如果将
SelectionMode
枚举替换为表示所需值的整数,则代码将编译。我只使用了SelectionMode.Extended
值(现在替换为其整数值-2),因为这就是您在示例中使用的值
我建议使用这种设置默认值的替代方法,因为您说过,如果在构造函数中将
SelectionMode
属性的默认值设置为SelectionMode.Extended
的那一行注释掉,问题就会消失。我认为,如果您使用该行替换该行,那么您的问题可能会消失。这是一个好问题,要回答它,需要了解WPF引擎是如何创建这两个DataGrid
实例的
对于DataGrid
的第一个实例,它是窗口的直接子对象,当调用窗口的构造函数中的InitializeComponents()
时,将创建该实例。我不会深入讨论初始化组件的工作原理,但只是一个jist,它调用方法System.Windows.Application.LoadComponent()
,并LoadComponent()
加载位于传入的URI
上的XAML
文件,并将其转换为由XAML
文件的根元素指定的对象实例。执行此操作时,它首先调用要创建的元素的默认构造函数,然后再次设置属性中提到的dependancProperties
现在,您在ControlTemplate
中放置的第二个实例。当将ControlTemplate
应用于元素时,将创建该实例。如果未应用模板
,则永远不会创建实例。在应用模板
时,调用ControlTemplate.LoadContent()
来创建ControlTemplate
的根元素。现在LoadContent()
对创建controlTemplate
中定义的ui元素采取不同的粗略方法。它确实为每个元素调用默认构造函数,但在设置dependandcroperties
时,它会运行大量检查以确定属性值。简而言之,它检查在元素实例上是否已经为特定的<代码>依赖项属性< /代码>设置了任何值(即,值不是默认值,它是“代码> RealCasyObjult<代码> >的ValueDeCigIcript中的实例的本地值条目”,它不考虑XAML中指定的值。因此,在这种情况下,当LoadComponents
调用DataGrid的默认构造函数时,我们设置SelectionModeProperty
值。加载内容时,ControlTemplate
检查内容并返回相同的值,并忽略xaml中指定的值
所有的控件都是如此,不仅仅是DataGrid
最后,在PresentationFramework assembly
中使用reflector
挖掘了一些代码之后,我能够找到这个问题的确切RCA。如所述,此行为适用于所有DP和所有控件,而不仅仅是DataGrid
这一切都与此有关
设置DP时,哪个值优先于其他值。
(枚举是BaseValueSourceInternal,它在WindowsBase.dll程序集中存储DP的优先顺序)
DependencyObject类
包含方法UpdateEffectiveValue
,该方法负责通过调用DataGrid实例上的SetValue
方法来设置任何DP上的最终实际值。
UpdateEffectiveValue
方法在实际调用DP上的SetValue
方法之前包含大量逻辑
通过ControlTemplate停止设置的有趣的检查是这个(if ((newEntry.BaseValueSourceInternal != BaseValueSourceInternal.Unknown)
&& (newEntry.BaseValueSourceInternal < oldEntry.BaseValueSourceInternal))
{
return (UpdateResult) 0;
}
<ControlTemplate x:Key="MyTemplate">
<local:ExtendedDataGrid ItemsSource="{Binding Collection,
RelativeSource={RelativeSource
Mode=FindAncestor, AncestorType=Window}}">
<local:ExtendedDataGrid.Columns>
<DataGridTextColumn Binding="{Binding}"/>
</local:ExtendedDataGrid.Columns>
<local:ExtendedDataGrid.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="SelectionMode">
<DiscreteObjectKeyFrame KeyTime="00:00:00"
Value="{x:Static DataGridSelectionMode.Single}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</local:ExtendedDataGrid.Triggers>
</local:ExtendedDataGrid>
</ControlTemplate>