【问题标题】:UIElements inside of Wrapped RadBusyIndicator's content are nullWrapped RadBusyIndi​​cator 内容内的 UIElements 为空
【发布时间】:2014-09-17 08:53:06
【问题描述】:

我遇到了一个有趣的 UI 问题。我有一个来自 Telerik 的 RadBusyIndicator 包裹在 UserControl 中(如果 Telerik 仍然存在内存泄漏,则可以轻松切换到 Windows 繁忙指示器)。当我将内容放入控件时,如果它在包装器控件的开始和结束标记之间有一个 ContentControl 以外的任何内容,则具有 x:Name 属性的所有内容在后面的代码中为空,并在页面时导致异常已加载。

这是代码的相似之处,已删除名称以保护无辜者。

xaml...

<UserControl>
    <Grid x:Name="Indicator">
        <telerik:RadBusyIndicator x:Name="BusyIndicator" IsBusy="{Binding Path=IsStatusBusy, Mode=TwoWay}" BusyContent="{Binding Path=WaitingContent, Mode=TwoWay}" Content="{Binding Path=UserContent, Mode=TwoWay}"/>
    </Grid>  
</UserControl>

还有后面的代码……

[ContentProperty("UserContent")]
public partial class CustomBusyIndicator : UserControl
{
    public CustomBusyIndicator()
    {
        InitializeComponent();
        Indicator.DataContext = this;
    }  

    public UIElement UserContent
    {
        get { return (UIElement)GetValue(UserContentProperty); }
        set { SetValue(UserContentProperty, value); }
    }

    private static readonly DependencyProperty UserContentProperty = DependencyProperty.Register("PageContent", 
        typeof(UIElement), typeof(CustomBusyIndicator), new PropertyMetadata(null)); 

    private static readonly DependencyProperty WaitingContentProperty = DependencyProperty.Register("WaitingContent",
        typeof (object), typeof (CustomBusyIndicator), new PropertyMetadata(null, OnWaitingContentChanged));

    private static void OnWaitingContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {}

    private static readonly DependencyProperty IsStatusBusyProperty = DependencyProperty.Register("IsStatusBusy",
        typeof (bool), typeof (CustomBusyIndicator), new PropertyMetadata(false, OnIsStatusBusyChanged));

    private static void OnIsStatusBusyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {}


    public bool IsStatusBusy
    {
        get { return (bool) GetValue(IsStatusBusyProperty); }
        set { SetValue(IsStatusBusyProperty, value); }
    }

    public object WaitingContent
    {
        get { return GetValue(WaitingContentProperty); }
        set { SetValue(WaitingContentProperty, value); }
    }
}

我就是这样用的.....

<CustomBusyIndicator IsStatus={Binding IsBusy}>
    <CustomBusyIndicator.WaitingContent>
        <TextBlock Text="Loading..." Foreground="Black" />
    </CustomBusyIndicator.WaitingContent>
    <Grid>
    .
    .
    .
    .
    </Grid>
</CustomBusyIndicator>

有什么想法吗?提前感谢您的帮助!

编辑

我现在已经确定似乎是 x:Name 导致了这些问题。在调用InitializeComponent() 后,它们在后面的代码中为空。

【问题讨论】:

  • 据我了解,这与x:Name 无关。等一下,我会在答案部分写一个正确的答案。

标签: c# silverlight xaml telerik


【解决方案1】:

您是从UserControl 派生的,所以会发生什么……让我们看看:

您的类继承了一个名为Content 的公共属性,而该属性正是基类的专用ContentProperty,由基类级别的[ContentProperty("Content")] 之类的注释引起。

这就是为什么您在 userControl 定义的 xaml 部分中声明的所有内容通常在加载时都会显示的原因。 所以当你看到这个...

<UserControl ... >
    <Grid x:Name="Indicator">
        <telerik:RadBusyIndicator x:Name="BusyIndicator" ... />
    </Grid>  
</UserControl>

技术上和写这个是一样的:

<UserControl ... >
    <UserControl.Content>
        <Grid x:Name="Indicator">
            <telerik:RadBusyIndicator x:Name="BusyIndicator" ... />
        </Grid>
    </UserControl.Content>
</UserControl>

这意味着每当您在 xaml 中的某处使用 UserControl 并以您的方式添加内容时...

<CustomBusyIndicator ...>
    <Grid> ... </Grid>
</CustomBusyIndicator>

...您正在覆盖在 UserControl 定义的 xaml 部分中声明的所有内容(您将另一个属性注释为 ContentProperty 并不重要,这只是意味着您设置了两次新的 ContentProperty)。

那么你现在有什么选择:

选项 1:保留 UserControl 作为基础,但仅明确使用您的属性 UserContent 所以用法看起来像这样:

<CustomBusyIndicator ...>
    <CustomBusyIndicator.UserContent>
        <Grid> ... </Grid>
    </CustomBusyIndicator.UserContent>
</CustomBusyIndicator>

选项编号 2:派生自 ControlContentControl 并将您的 UserControl 的 xaml-part 转换为默认的 ControlTemplate 这样你就可以像这样使用它了

<CustomBusyIndicator ...>
    <Grid> ... </Grid>
</CustomBusyIndicator>

但您必须确保在解析 xaml 时找到您的模板。我通常会这样做:

  • 创建资源字典CustomBusyIndicator.xaml
  • themes/generic.xaml 添加一个包含字典的条目
  • DefaultStyleKey = typeof(CustomBusyIndicator); 添加到控件的构造函数中
  • 向 CustomBusyIndi​​cator.xaml 添加隐式样式

这还有另一个影响。您不能像以前那样轻松地使用命名元素:您必须为 OnApplyTemplate 编写覆盖并通过 GetTemplateChild("BusyIndicator") as RadBusyIndicator; 获取对这些命名元素的引用

选项编号 3:将 UserControl 作为基础,将 UserContent 作为 ContentProperty,但明确设置 xaml-part 所以定义看起来像这样:

<UserControl ... >
    <UserControl.Content>
        <Grid x:Name="Indicator">
            <telerik:RadBusyIndicator x:Name="BusyIndicator" ... />
        </Grid>
    </UserControl.Content>
</UserControl>

【讨论】:

  • 我去看看。谢谢你的回答。
  • 我花了一段时间才完全理解你在说什么,但你的第二种方法是正确的。非常感谢!
  • @Madviola:我想到了我的说法“如果你想使用 ContentProperty 快捷语法,就不能使用 UserControl”,嗯,这是不正确的。您应该能够在定义中明确设置 xaml-part,但我还没有尝试过。我将它作为第三个选项添加到我的答案中。
猜你喜欢
  • 1970-01-01
  • 2013-01-29
  • 2011-08-17
  • 2015-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多