使用自定义DependencyProperty时,UIElement为null

时间:2012-01-15 13:34:25

标签: c# wpf silverlight xaml user-controls

我为工具提示创建了一个简单的用户控件:

public partial class TooltipControl : UserControl
{
    public static readonly DependencyProperty ToolTipControlContentProperty
        = DependencyProperty.Register("ToolTipControlContent", typeof(FrameworkElement), typeof(TooltipControl), 
            new PropertyMetadata(new Grid()));


    public static readonly DependencyProperty ToolTipProperty
      = DependencyProperty.Register("ToolTip", typeof(string), typeof(TooltipControl),
          new PropertyMetadata(string.Empty));

    public string Tooltip
    {
        get { return GetValue(ToolTipProperty) as string; }
        set { SetValue(ToolTipProperty, value); }
    }

    public FrameworkElement ToolTipControlContent
    {
        get { return GetValue(ToolTipControlContentProperty) as FrameworkElement; }
        set { SetValue(ToolTipControlContentProperty, value); }
    }

    public TooltipControl()
    {
        InitializeComponent();
    }

}

这是xaml:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
   x:Class="Dashboard.Controls.TooltipControl" 
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Width="150" Height="75">

        <Border Child="{Binding ToolTipControlContent}">
            <Border.Background>
                <LinearGradientBrush EndPoint="0.5,1" MappingMode="RelativeToBoundingBox" StartPoint="0.5,0">
                    <GradientStop Color="#FF1BA1E2" Offset="0"/>
                    <GradientStop Color="#FF096A99" Offset="1"/>
                </LinearGradientBrush>
            </Border.Background>
        </Border>

    </Grid>
</UserControl>

我在MainPage.xaml中使用此控件:

<local:TooltipControl Width="150" Height="75" x:Name="tileWidthSettings" Tooltip="Adjust the tile width of widgets" Margin="3,0,0,0" VerticalAlignment="Top">
    <local:TooltipControl.ToolTipControlContent>
        <Grid Height="75" Width="150">

            <Grid.Effect>
                <DropShadowEffect BlurRadius="8" Direction="0" ShadowDepth="0"/>
            </Grid.Effect>
            <Grid.Background>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FF1BA1E2" Offset="0.004"/>
                    <GradientStop Color="#FF096A99" Offset="1"/>
                </LinearGradientBrush>
            </Grid.Background>
            <StackPanel d:LayoutOverrides="Height" VerticalAlignment="Center" Margin="15,0">
                <TextBlock TextWrapping="Wrap" Text="Tile width" FontFamily="Trebuchet MS" HorizontalAlignment="Center" Foreground="White" FontSize="13.333"/>
                <telerik:RadSlider x:Name="radSliderTileWidth" ValueChanged="radSliderTileWidth_ValueChanged" RepeatInterval="10" Value="300" Minimum="0" Margin="0" />
            </StackPanel>
        </Grid>
    </local:TooltipControl.ToolTipControlContent>
</local:TooltipControl>

如果我直接使用:

radSliderTileWidth.Minimum = 1.0;
在MainPage.xaml.cs中

我得到NULL。即使我可以通过名称直接访问元素,它总是NULL。我是在Loaded事件处理程序中完成的。

然后我尝试了:

(tileWidthSettings.ToolTipControlContent.FindName("radSliderTileWidth" ) as RadSlider).Maximum = GetScreenWidth() / 2;

它仍然是NULL。

但是,如果我在某个事件处理程序中随机尝试它就可以了!可能是因为usercontrol的模板尚未应用于加载的事件中。

然后我尝试了:

RadSlider slider = tileWidthSettings.ToolTipControlContent.FindChildByType<RadSlider>();

这基本上是扩展方法,并使用VisualTreeHelper搜索子,它可以工作!

那我在这里做错了什么?如何在MainPage.xaml.cs中获取我的radSliderTileWidth,无论是在Loaded事件中还是在其他事件处理程序中,它都以统一的方式工作?

顺便说一句,我使用的是Silverlight 4.0,但我认为这是一个适用于WPF的一般概念。所以我也把它标记为WPF。

1 个答案:

答案 0 :(得分:0)

请参阅Silverlight中的FrameworkElement.Loaded的MSDN文档,“加载并控制对象生存期”部分:

  

Silverlight中Loaded事件的时间与WPF中FrameworkElement.Loaded事件的时间不同。具体来说,应用模板后会发生WPF Loaded事件。在Silverlight中,无法保证在应用模板后发生Loaded事件。如果您在相对常见的控件方案中使用Loaded事件,这可能是一个问题:您要检查可视树,要么获取值作为其他内容的源,要么更改模板化合成中的值您只能在运行时知道新值。在这种情况下,如果直接从Loaded处理程序创建模板内容,则调用Silverlight VisualTreeHelper方法来检查模板内容的可视树可能不起作用。

     

...