【问题标题】:Silverlight 4.0 Cannot create an instance of "CustomControl"Silverlight 4.0 无法创建“CustomControl”的实例
【发布时间】:2011-07-25 10:23:18
【问题描述】:

我目前正在处理一个小项目,但在使用 silverlight 自定义控件时遇到了一些问题。我正在尝试为照片库创建一个自定义 ScrollViewer(将包含小图像)。我遇到的问题是 Visual Studio 抛出以下错误:

无法创建 ScrollableImageViewer 的实例

有人可以提供一些关于可能是什么原因导致此错误的指针,并可能提供一些解决方法吗?

下面是我编写的 XAML 和 C# 代码。

<navigation:Page x:Class="PWS.Views.Biography" 
       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"
       xmlns:local="clr-namespace:PWS.Controls"
       mc:Ignorable="d"
       xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
       d:DesignWidth="640" d:DesignHeight="480"
       Title="This is the biography page">
<Grid x:Name="LayoutRoot">
    <TextBlock x:Name ="tempText" FontSize="15" Foreground="Blue">this is the biography page</TextBlock>
    <local:ScrollableImageViewer x:Name= "scrollableViewer" />
</Grid>
</navigation:Page>

我的自定义控件类名为ScrollableImageViewer,您可以在下面看到它的代码。

namespace PWS.Controls
{
    [ContentProperty("Items")]
    public class ScrollableImageViewer : Control
    {
        public static DependencyProperty ItemsProperty = DependencyProperty.RegisterAttached("Items", typeof(IList<UIElement>), typeof(ScrollableImageViewer), new PropertyMetadata(""));

        public ScrollableImageViewer()
        {
            this.DefaultStyleKey = typeof(ScrollableImageViewer);
            this.Items = new List<UIElement>();
        }

        public IList<UIElement> Items
        {
            get { return (IList<UIElement>)GetValue(ScrollableImageViewer.ItemsProperty); }
            set { SetValue(ScrollableImageViewer.ItemsProperty, value); }
        }
    }
}

目前它非常简单,并且不包含用于滚动的自定义逻辑。
我必须添加的另一件事是包含此控件模板的 generic.xaml 文件。

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:PWS.Controls"
    >
  <Style TargetType="local:ScrollableImageViewer">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="local:ScrollableImageViewer">
          <Grid Background="{TemplateBinding Background}">
            <ScrollViewer x:Name="internalScrollViewer" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                          Background="{TemplateBinding Background}"
                          VerticalScrollBarVisibility="Disabled"
                          HorizontalScrollBarVisibility="Hidden"
                          >
              <StackPanel Background="{TemplateBinding Background}" FlowDirection="LeftToRight" IsHitTestVisible="False" Children="{TemplateBinding Items}"></StackPanel>
            </ScrollViewer>
          </Grid>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</ResourceDictionary>

从模板中可以看出,我希望我的控件包含一个内部 ScrollViewer 和一个 StackPanel,其 Children 属性应绑定到自定义控件的 Items 属性。

P.S 我在 SO 上进行了一些搜索,发现了一些关于类似问题的问题。其中大部分是通过在构造函数中添加代码来检查控件是否以设计器模式显示的来解决的,但这对我不起作用。看来我有不同的问题。

P.P.S我刚开始学习 Silverlight,所以如果你看到一些不好的代码,请随时指出来。

【问题讨论】:

    标签: silverlight-4.0 c#-4.0 custom-controls


    【解决方案1】:

    使用自定义控件时,您必须处理很多规则。首先让我们保证:

    1. 您的项目必须有一个“主题”文件夹,其中包含一个“Generic.xaml”资源字典,用于保存模板的样式。
    2. 定义依赖属性时,不能使用不同类型的值对其进行初始化。您的 Items 属性正在使用空字符串 ("") 进行初始化,这是“PropertyMetadata”中您的属性的初始值。 “null”或“new ...”应该可以解决问题。

    声明,我为您提供了 Items 属性的解决方法:为您的 StackPanel 命名,从“OnApplyTemplate”方法访问它。使用临时 StackPanel 来保存可能在将实际模板应用于您的控件之前添加的子级,并且当这种情况真正发生时,将临时 StackPanel 中的子级传递给模板中的子级。为此,请为 StackPanel 使用 NamedPart。

    这里是 xaml 的代码:

    <Style TargetType="local:ScrollableImageViewer">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:ScrollableImageViewer">
                    <Grid Background="{TemplateBinding Background}">
                        <ScrollViewer x:Name="internalScrollViewer"
                                                    HorizontalAlignment="Stretch"
                                                    VerticalAlignment="Stretch"
                                                    Background="{TemplateBinding Background}"
                                                    VerticalScrollBarVisibility="Disabled"
                                                    HorizontalScrollBarVisibility="Hidden">
                            <StackPanel x:Name="myStackPanel"
                                                    Background="{TemplateBinding Background}"
                                                    FlowDirection="LeftToRight"
                                                    IsHitTestVisible="False"></StackPanel>
                        </ScrollViewer>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    这是后面的代码:

    [TemplatePart(Name = "myStackPanel", Type = typeof(StackPanel))]
    [ContentProperty("Items")]
    public class ScrollableImageViewer : Control
    {
        public ScrollableImageViewer()
        {
            this.DefaultStyleKey = typeof(ScrollableImageViewer);
        }
    
        StackPanel MyStackPanel = null;
        StackPanel TemporalSP = new StackPanel();
    
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            MyStackPanel = GetTemplateChild("myStackPanel") as StackPanel;
    
            // Pass created children before appliying the template.
            for (int i = TemporalSP.Children.Count - 1; i >= 0; i--)
            {
                UIElement OneControl = TemporalSP.Children[i];
                TemporalSP.Children.Remove(OneControl);
                MyStackPanel.Children.Add(OneControl);
            }
            TemporalSP = null;
    
        }
    
        public UIElementCollection Items
        {
            get
            {
                if (MyStackPanel != null)
                    return MyStackPanel.Children;
                else
                    return TemporalSP.Children;
            }
        }
    
    }
    

    【讨论】:

    • 您好,非常感谢您的回答。我想我会按照你的建议去做,并且会使用临时堆栈面板。不过,我有一个问题:从您发布的代码中,临时堆栈面板从未添加过项目。它是由框架设置的吗?还是仅供开发人员从代码中使用?
    • 不客气...假设您有一个包含控件的页面。如果您想在代码中,在加载事件中,将控件添加到 items 属性,您会发现此自定义控件的模板尚未应用,如果未应用,则您的堆栈面板尚未创建。临时堆栈面板让您的自定义控件在应用模板时保持子级。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-09
    • 2021-05-17
    • 2012-01-29
    • 2016-08-24
    • 1970-01-01
    相关资源
    最近更新 更多