银光4工具包,图表和线系列为空。

4
我使用Silverlight 4工具包中的最新版本(即四月份发布的版本)创建了一个Silverlight图表。
请看下面的图表:
 <Grid x:Name="LayoutRoot" Background="White">
  <Charting:Chart Title="Chart to test" Name="MySuperChart">
   <Charting:LineSeries x:Name="MyLineSeries" Title="Something" />
  </Charting:Chart>
 </Grid>

目前为止一切顺利。我可以通过 MySuperChart.Series[0] 访问图表中的系列。但是当我尝试引用 MyLineSeries 时,它似乎为空。 图片 查看完整版

1个回答

6

这是一个有趣的小问题。如果您稍微深入了解变量MyLineSeries的创建和分配方式,会更有帮助。请导航到InitializeComponent方法的定义。您将会进入MainPage.g.cs生成的文件。它将包含以下字段:

internal System.Windows.Controls.DataVisualization.Charting.LineSeries MyLineSeries;

InitializeComponent 中,你会找到这一行代码:

this.MyLineSeries = ((System.Windows.Controls.DataVisualization.Charting.LineSeries)(this.FindName("MyLineSeries")));

表面上看,在构造函数中调用InitializeComponent时,MyLineSeries应该已被赋值。但是,正如你所看到的,它仍然为空,因此可以得出结论,FindName("MyLineSeries")未能找到该系列。那么问题在于它为什么失败了?
为什么FindName不起作用? FindName搜索文档中所称的“对象树”,寻找具有指定名称的对象(这里涉及到名字空间的复杂性,但在这里不适用)。通常,对象通过像PanelContentControl这样的共同基类型进入“对象树”,这些类型具有诸如ChildrenChild等属性。这些属性在类上指定了ContentProperty属性,允许更自然地描述UI结构。例如:-
<Button x:Name="MyButton">
  <Image x:Name="MyImage" ... />
</Button>

与其

<Button x:Name="MyButton">
  <Button.Child>
    <Image x:Name="MyImage" ... />
  </Button.Child>
</Button>

相比之下,Chart控件不是一个简单的Panel派生类,需要更多的工作来构建其用户界面。在Chart的情况下,ContentPropertyAttribute指定了Series集合参数。这使您的Xaml代码更加自然:

<Charting:Chart Title="Chart to test" Name="MySuperChart">
  <Charting:LineSeries x:Name="MyLineSeries" Title="Something" />
</Charting:Chart>

然而,由于Chart需要大量额外的工作来确定最终UI所代表的"对象树"中确切的内容,因此系列集合项并不会立即成为"对象树"的一部分。结果是,在InitializeComponent中,FindName无法找到它们。
解决方法1:
您可以利用"MyLineSeries"在图表中的顺序位置的知识,在构造函数中处理MyLineSeries变量的赋值。从Xaml中删除x:Name="MyLineSeries",然后在代码中进行操作:
public partial MainPage : UserControl
{
  private LineSeries MyLineSeries;

  public MainPage()
  {
    InitializeComponent();
    MyLineSeries = (LineSeries)MySuperChart.Series[0];
  }
}

解决方法 - 选项2

你可以等待该系列在“对象树”中可用,这是在包含UserControl触发其Loaded事件后为真:

public partial MainPage : UserControl
{
  public MainPage()
  {
    InitializeComponent();
    Loaded += (s, args) =>
    {
      MyLineSeries = (LineSeries)FindName("MyLineSeries");
    }
  }
}

@Snake:x:Name确实被解析了,但自动生成的代码假定在执行InitializeComponent时可以在“对象树”中找到该元素。我不确定是否应将此归类为错误。 - AnthonyWJones
@AnyhonyWJones:实际上你的解决方法2不起作用。它找不到该名称。 - Snake
是的。虽然我可以使用第一种修复方法,但我不喜欢它。但还是谢谢! - Snake
@Snake:实际上,由于我理解错误,这让我开始思考SL3的行为是否正确。结果并不完全正确。您需要的事件是包含UserControl的“Loaded”事件。这适用于SL3和SL4。我已相应地调整了我的答案。 - AnthonyWJones
我想报告一下,在Silverlight 5中,解决方法2对我有效。 - David S.
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接