使用样式时无法获取属性值

发布于 2024-10-07 08:55:29 字数 6468 浏览 3 评论 0原文

我有一个应用模板的自定义控件。在自定义控件内,我定义了绑定到样式内模板化控件的属性。如果我订阅了 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

手心的温暖 2024-10-14 08:55:29

尝试使用 OnApplyTemplate 事件而不是加载事件

public override void OnApplyTemplate()

try using the OnApplyTemplate event instead of loaded event

public override void OnApplyTemplate()

烧了回忆取暖 2024-10-14 08:55:29

绑定评估发生在整个可视化树构建完成之后的加载过程中。不必依赖单个事件来收集值,只需在 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}"

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文