终于开始我的代码之旅了。
资料当然是从博客园里找了,发现
Terrylee 的Silverlight2-step-by-step系列还真的入门的好文章,先不管Silverlight的版本问题,拿过来先试试了,好期待!
找个比较综合的小例子一步一步学Silverlight 2系列(3):界面布局 里面发现了诡异的问题
按博主的代码我把该写的代码都用上了,
Code
<UserControl xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation" xmlns:input="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input" xmlns:dataInput="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input" xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" x:Class="SilverlightRun1.MainPage"
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"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayOutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="260"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="120"/>
<RowDefinition Height="120"/>
</Grid.RowDefinitions>
<Rectangle Grid.Row="0" Grid.Column="1" x:Name="PreviewColor"
Fill="DarkCyan" Margin="10" Stroke="Black" StrokeThickness="2"/>
<StackPanel Grid.Row="1" Grid.Column="1">
<TextBlock FontSize="12">Color</TextBlock>
<TextBox x:Name="HexColor" Width="160" Height="30" Text="#FF6600" Margin="10,5" FontSize="11"></TextBox>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" VerticalAlignment="Center">
<TextBlock Text="Alpha" FontSize="12" Margin="10,15,0,0"/>
<Slider x:Name="AlphaSlider" Margin="20,0,10,0" Maximum="255" Value="255" ValueChanged="Slider_ValueChanged" />
<TextBlock Text="Red" FontSize="12" Margin="10,15,0,0"/>
<Slider x:Name="RedSlider" Margin="20,0,10,0" Maximum="255" Value="255" ValueChanged="Slider_ValueChanged" />
<TextBlock Text="Green" FontSize="12" Margin="10,15,0,0"/>
<Slider x:Name="GreenSlider" Margin="20,0,10,0" Maximum="255" Value="102" ValueChanged="Slider_ValueChanged" />
<TextBlock Text="Blue" FontSize="12" Margin="10,15,0,0"/>
<Slider x:Name="BlueSlider" Margin="20,0,10,0" Maximum="255" Value="0" ValueChanged="Slider_ValueChanged" />
</StackPanel>
</Grid>
</UserControl>
后台代码为:
一切都OK了,运行发现有空对象引用的异常。怎么可能这些不都是公布可用的代码吗?
无奈还是跟下吧。
发现原来问题出在当前页的InitializeComponent(),里面,看看后面的实现吧,
Code
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public void InitializeComponent() {
if (_contentLoaded) {
return;
}
_contentLoaded = true;
System.Windows.Application.LoadComponent(this, new System.Uri("/SilverlightRun1;component/MainPage.xaml", System.UriKind.Relative));
this.LayOutRoot = ((System.Windows.Controls.Grid)(this.FindName("LayOutRoot")));
this.PreviewColor = ((System.Windows.Shapes.Rectangle)(this.FindName("PreviewColor")));
this.HexColor = ((System.Windows.Controls.TextBox)(this.FindName("HexColor")));
this.AlphaSlider = ((System.Windows.Controls.Slider)(this.FindName("AlphaSlider")));
this.RedSlider = ((System.Windows.Controls.Slider)(this.FindName("RedSlider")));
this.GreenSlider = ((System.Windows.Controls.Slider)(this.FindName("GreenSlider")));
this.BlueSlider = ((System.Windows.Controls.Slider)(this.FindName("BlueSlider")));
}
看这个代码的基本意思应该是通过标记_contentLoaded来判断当前页是不是已经载入页面元素了,如果已经完成初始化了,则不再载入,如果没有载入则执行下面的LoadComponent的代码。
按理来说整个载入的过程都是没有什么复杂的,但是问题是当代码执行LoadComponent时,代码走到了后台代码的Slider_ValueChanged事件里面。
我猜想LoadComponent应该是读取了页面上的元素标签来构造当前页面中对象,因为其中对对象设定了Value,结果就执行了ValueChange的事件。
可是实际上从上面代码看页面对象的初始化应该是类似this.PreviewColor = ((System.Windows.Shapes.Rectangle)(this.FindName("PreviewColor")));
的代码完成的。
如果真的是上面的代码完成初始化,那前面我的猜想就不应该存在,如果真的存在那就一定会出现对象还没有初始化就在事件中使用该对象的空对象引用异常的错误。
不知道这个是3.0里面才存在的问题,还是原2.0里面就有,还奇怪!
最后我只能把事件里面的代码重新改造下
1:消除页面代码中事件的部分。(这个只是对Slider控件的事件)
2:在页面代码中对页面的Load添加事件代码
Code
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
this.AlphaSlider.ValueChanged += new RoutedPropertyChangedEventHandler<double>(Slider_ValueChanged);
this.RedSlider.ValueChanged += new RoutedPropertyChangedEventHandler<double>(Slider_ValueChanged);
this.GreenSlider.ValueChanged += new RoutedPropertyChangedEventHandler<double>(Slider_ValueChanged);
this.BlueSlider.ValueChanged += new RoutedPropertyChangedEventHandler<double>(Slider_ValueChanged);
}
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Color color = Color.FromArgb((byte)AlphaSlider.Value, (byte)RedSlider.Value, (byte)GreenSlider.Value, (byte)BlueSlider.Value);
PreviewColor.Fill = new SolidColorBrush(color);
HexColor.Text = color.ToString();
}
如此改造后一切正常。
最后总结下。
上面的改造方式应该不是唯一的,也不一定完全合理,但是主要解决的根本问题看起来是Silverlight在初始化页面时候也可能会因为页面元素设定值时响应后台的事件代码,且如果事件代码中引用到页面元素的值时就会造成空对象的引用。
所以如果遇到类似情况,改造时只要将页面中的事件放在Loaded事件中加载,应该就可以避免上述问题的发生