使用样式时无法获取属性值
我有一个应用模板的自定义控件。在自定义控件内,我定义了绑定到样式内模板化控件的属性。如果我订阅了 Loaded 事件并尝试获取它们为空的属性。然而,如果我正在验证 OnPropertyChanged,它们就有值。有人可以解释一下为什么会这样吗? 请查看 ColumnEntity 属性。
谢谢。
为了简短起见,我删除了一些部分
<!-- This code is based on http://www.codeproject.com/KB/WPF/DataGridFilterLibrary.aspx -->
<Style TargetType="{x:Type local:DataGridColumnFilter}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:DataGridColumnFilter}">
<Border Background ="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<TextBox VerticalAlignment="Top" VerticalContentAlignment="Center" Background="AliceBlue"
Text="{Binding
RelativeSource={RelativeSource AncestorType={x:Type local:DataGridColumnFilter}},
Path=QueryEntity.Text, Mode=OneWayToSource, UpdateSourceTrigger=Explicit}">
</TextBox>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="{ComponentResourceKey
TypeInTargetAssembly={x:Type local:DataGridColumnFilter}, ResourceId=DataGridHeaderFilterControlStyle}"
TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<local:DataGridColumnFilter Grid.Row="0"
DataGridEntity="{Binding
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=.}"
ColumnEntity="{Binding
RelativeSource={RelativeSource AncestorType={x:Type DataGridColumnHeader}}, Path=Column}"
ItemsSourceEntity ="{Binding
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=ItemsSource}"/>
<theme:DataGridHeaderBorder Grid.Row="1"
SortDirection ="{TemplateBinding SortDirection}"
IsHovered ="{TemplateBinding IsMouseOver}"
IsPressed ="{TemplateBinding IsPressed}"
IsClickable ="{TemplateBinding CanUserSort}"
Background ="{TemplateBinding Background}"
BorderBrush ="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding ="{TemplateBinding Padding}"
SeparatorBrush ="{TemplateBinding SeparatorBrush}"
SeparatorVisibility="{TemplateBinding SeparatorVisibility}">
<TextBlock Grid.Row="1" TextWrapping="Wrap"
Text ="{TemplateBinding Content}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment ="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}">
</TextBlock>
</theme:DataGridHeaderBorder>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
public class DataGridColumnFilter : Control
{
static DataGridColumnFilter()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(DataGridColumnFilter), new FrameworkPropertyMetadata(typeof(DataGridColumnFilter)));
}
public DataGridColumnFilter()
{
this.Loaded += new RoutedEventHandler(DataGridColumnFilter_Loaded);
}
void DataGridColumnFilter_Loaded(object sender, RoutedEventArgs e)
{
// here is would be null!
var controller = ColumnEntity;
}
// For some reason this seems to be the only place to access the ColumnEntity
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if (e.Property == ItemsSourceEntityProperty && e.OldValue != e.NewValue && null != DataGridEntity && ColumnEntity is DataGridColumn)
{
// here it works fine. The property has a proper value
var controller = ColumnEntity;
}
base.OnPropertyChanged(e);
}
#region Properties
public Query QueryEntity
{
get { return (Query)GetValue(QueryEntityProperty); }
set { SetValue(QueryEntityProperty, value); }
}
public static readonly DependencyProperty QueryEntityProperty =
DependencyProperty.Register("QueryEntity", typeof(Query), typeof(DataGridColumnFilter));
public DataGridColumn ColumnEntity
{
get { return (DataGridColumn)GetValue(ColumnEntityProperty); }
set { SetValue(ColumnEntityProperty, value); }
}
public static readonly DependencyProperty ColumnEntityProperty =
DependencyProperty.Register("ColumnEntity", typeof(DataGridColumn), typeof(DataGridColumnFilter));
public DataGrid DataGridEntity
{
get { return (DataGrid)GetValue(DataGridEntityProperty); }
set { SetValue(DataGridEntityProperty, value); }
}
public static readonly DependencyProperty DataGridEntityProperty =
DependencyProperty.Register("DataGridEntity", typeof(DataGrid), typeof(DataGridColumnFilter));
public IEnumerable ItemsSourceEntity
{
get { return (IEnumerable)GetValue(ItemsSourceEntityProperty); }
set { SetValue(ItemsSourceEntityProperty, value); }
}
public static readonly DependencyProperty ItemsSourceEntityProperty =
DependencyProperty.Register("ItemsSourceEntity", typeof(IEnumerable), typeof(DataGridColumnFilter));
#endregion
}
I have a custom control that I apply the template to. Inside custom control I have defined properties that are binded to the templated control inside the style. If I'm subscribed to the Loaded event and trying to get the properties they are null. If however I'm ovveriding the OnPropertyChanged they have values. Can someone please explain why is that so.
Please look at the ColumnEntity property.
Thank you.
I've removed some parts for briefety
<!-- This code is based on http://www.codeproject.com/KB/WPF/DataGridFilterLibrary.aspx -->
<Style TargetType="{x:Type local:DataGridColumnFilter}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:DataGridColumnFilter}">
<Border Background ="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<TextBox VerticalAlignment="Top" VerticalContentAlignment="Center" Background="AliceBlue"
Text="{Binding
RelativeSource={RelativeSource AncestorType={x:Type local:DataGridColumnFilter}},
Path=QueryEntity.Text, Mode=OneWayToSource, UpdateSourceTrigger=Explicit}">
</TextBox>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="{ComponentResourceKey
TypeInTargetAssembly={x:Type local:DataGridColumnFilter}, ResourceId=DataGridHeaderFilterControlStyle}"
TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<local:DataGridColumnFilter Grid.Row="0"
DataGridEntity="{Binding
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=.}"
ColumnEntity="{Binding
RelativeSource={RelativeSource AncestorType={x:Type DataGridColumnHeader}}, Path=Column}"
ItemsSourceEntity ="{Binding
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=ItemsSource}"/>
<theme:DataGridHeaderBorder Grid.Row="1"
SortDirection ="{TemplateBinding SortDirection}"
IsHovered ="{TemplateBinding IsMouseOver}"
IsPressed ="{TemplateBinding IsPressed}"
IsClickable ="{TemplateBinding CanUserSort}"
Background ="{TemplateBinding Background}"
BorderBrush ="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding ="{TemplateBinding Padding}"
SeparatorBrush ="{TemplateBinding SeparatorBrush}"
SeparatorVisibility="{TemplateBinding SeparatorVisibility}">
<TextBlock Grid.Row="1" TextWrapping="Wrap"
Text ="{TemplateBinding Content}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment ="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}">
</TextBlock>
</theme:DataGridHeaderBorder>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
public class DataGridColumnFilter : Control
{
static DataGridColumnFilter()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(DataGridColumnFilter), new FrameworkPropertyMetadata(typeof(DataGridColumnFilter)));
}
public DataGridColumnFilter()
{
this.Loaded += new RoutedEventHandler(DataGridColumnFilter_Loaded);
}
void DataGridColumnFilter_Loaded(object sender, RoutedEventArgs e)
{
// here is would be null!
var controller = ColumnEntity;
}
// For some reason this seems to be the only place to access the ColumnEntity
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if (e.Property == ItemsSourceEntityProperty && e.OldValue != e.NewValue && null != DataGridEntity && ColumnEntity is DataGridColumn)
{
// here it works fine. The property has a proper value
var controller = ColumnEntity;
}
base.OnPropertyChanged(e);
}
#region Properties
public Query QueryEntity
{
get { return (Query)GetValue(QueryEntityProperty); }
set { SetValue(QueryEntityProperty, value); }
}
public static readonly DependencyProperty QueryEntityProperty =
DependencyProperty.Register("QueryEntity", typeof(Query), typeof(DataGridColumnFilter));
public DataGridColumn ColumnEntity
{
get { return (DataGridColumn)GetValue(ColumnEntityProperty); }
set { SetValue(ColumnEntityProperty, value); }
}
public static readonly DependencyProperty ColumnEntityProperty =
DependencyProperty.Register("ColumnEntity", typeof(DataGridColumn), typeof(DataGridColumnFilter));
public DataGrid DataGridEntity
{
get { return (DataGrid)GetValue(DataGridEntityProperty); }
set { SetValue(DataGridEntityProperty, value); }
}
public static readonly DependencyProperty DataGridEntityProperty =
DependencyProperty.Register("DataGridEntity", typeof(DataGrid), typeof(DataGridColumnFilter));
public IEnumerable ItemsSourceEntity
{
get { return (IEnumerable)GetValue(ItemsSourceEntityProperty); }
set { SetValue(ItemsSourceEntityProperty, value); }
}
public static readonly DependencyProperty ItemsSourceEntityProperty =
DependencyProperty.Register("ItemsSourceEntity", typeof(IEnumerable), typeof(DataGridColumnFilter));
#endregion
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
尝试使用 OnApplyTemplate 事件而不是加载事件
public override void OnApplyTemplate()
try using the OnApplyTemplate event instead of loaded event
public override void OnApplyTemplate()
绑定评估发生在整个可视化树构建完成之后的加载过程中。不必依赖单个事件来收集值,只需在 DependencyProperties 上使用 PropertyChanged 处理程序,您已经确认该处理程序正在为您提供预期值。
您还可以简化 ColumnEntity 以使用
ColumnEntity="{BindingrelativeSource={RelativeSource TemplatedParent}, Path=Column}"
Binding evaluation happens later in the loading process after the whole Visual Tree has been constructed. Rather than relying on a single event to collect values just use PropertyChanged handlers on the DependencyProperties, which you've already confirmed are giving you the expected values.
You can also simplify the ColumnEntity to use
ColumnEntity="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Column}"