我目前正在开展一个小项目,我在使用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,所以如果你看到一些不好的代码,请随时向我指出。
答案 0 :(得分:2)
使用自定义控件时,您必须处理很多规则。首先,让我们保证:
说明,我为Items属性提供了一个解决方法:给StackPanel一个名称,从“OnApplyTemplate”方法访问它。使用临时StackPanel来保存可能在将真实模板应用于控件之前添加的子项,并且当这种情况发生时,将子项从时间StackPanel传递到模板中的子项。为此,请使用NamedPart作为StackPanel。
这是代码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;
}
}
}