这篇主要介绍了项目中Gif图片的使用与HyperlinkButton视图状态的图片效果实现,以及资源的绝对路径与相对路径在使用中的遇到的问题
先来看下运行效果
布局上的细节就不多说了,还是Grid、StackPanel的嵌套,这个页面的主体分上下两部分,上半部分为导航与功能模块,下半部分目前是一个空的Border,为各模块的功能展示区。
实现这个界面的过程中遇到几个问题,这里主要进行说明
首先,上图中
这些,其实每一个都是一个HyperlinkButton,为什么要使用HyperlinkButton呢,因为如果使用button,还要去改变各种视图状态的效果,比如按下,悬停这些状态,而我们这里根本用不上。在web中我们一般会使用<a>来实现,但sl里我没有找到类似winform里的linkbutton或imagebutton,只找到了HyperlinkButton,所以我就用它来实现了,可能有人会问,为什么不用image呢?嗯,这个就是这个问题的关键了,因为,我们的图标是gif格式的。对,sl至今仍不支持GIF图,网上有一种解决办法,是一个网友写的GifImageLib.dll,可以加载gif图片,所以,这里使用HyperlinkButton就是为了使用它的模板里承载这个自定义控件(GifImageLib)。
实现的XAML代码如下
<StackPanel Orientation="Horizontal" Margin="0" RenderTransformOrigin="0.5,0.5" Width="625">
<HyperlinkButton x:Name="lnkBtn1" BorderThickness="0" Margin="0" Width="41" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="0">
<GifImageLib:GifImage UriSource="/Images/icons/ico9.gif" Margin="9,0,0,0"/>
</HyperlinkButton>
<HyperlinkButton x:Name="lnkBtn2" BorderThickness="0" Margin="0" Width="41" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="0">
<GifImageLib:GifImage UriSource="/Images/icons/ico8.gif" Margin="9,0,0,0"/>
</HyperlinkButton>
<HyperlinkButton x:Name="lnkBtn3" BorderThickness="0" Margin="0" Width="41" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="0">
<GifImageLib:GifImage UriSource="/Images/icons/ico5.gif" Margin="9,0,0,0"/>
</HyperlinkButton>
<HyperlinkButton x:Name="lnkBtn4" BorderThickness="0" Margin="0" Width="41" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="0">
<GifImageLib:GifImage UriSource="/Images/icons/ico11.gif" Margin="9,0,0,0"/>
</HyperlinkButton>
<HyperlinkButton x:Name="lnkBtn5" BorderThickness="0" Margin="0" Width="41" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="0">
<GifImageLib:GifImage UriSource="/Images/icons/ico2.gif" Margin="9,0,0,0"/>
</HyperlinkButton>
<HyperlinkButton x:Name="lnkBtn6" BorderThickness="0" Margin="0" Width="41" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="0">
<GifImageLib:GifImage UriSource="/Images/icons/ico4.gif" Margin="9,0,0,0"/>
</HyperlinkButton>
<HyperlinkButton x:Name="lnkBtn7" BorderThickness="0" Margin="0" Width="41" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="0">
<GifImageLib:GifImage UriSource="/Images/icons/ico13.gif" Margin="9,0,0,0"/>
</HyperlinkButton>
</StackPanel>
不过这个控件有点问题,可能我找到的这个是个半成品吧,它原来的UriSource只能接受服务器上的资源地址,因为它内部实现是使用WebClient去服务器上动态下载,所以如果直接设置为我们项目里的图片资源,它会报错的。不过还好,开源的,只要我们简单修改一下就可以了,在此对作者表示感谢!
修改后的代码如下:(SetSoruce方法为内部加载gif方法)
public Uri UriSource
{
//set
//{
// WebClient myClient = new WebClient();
// myClient.OpenReadCompleted += new OpenReadCompletedEventHandler(myClient_OpenReadCompleted);
// myClient.OpenReadAsync(value);
//}
set
{
this.SetSoruce(Application.GetResourceStream(value).Stream);
}
}
这里提到了资源,嗯,这确实是个头痛的问题,至少我在“实习”的过程中为它头痛了好多回
先说一下这里遇到的问题吧,代码做了上述修改后会报错,Application.GetResourceStream(value).Stream 这一句是取得资源,但这一块要注意一下,因为如果把资源做为Resouce(默认行为),如果在其它dll中引用的时候(不是后台,是写在xmal里时,例如我们这里的引用方式<GifImageLib:GifImage UriSource="Images/icons/ico8.gif"/>),就会找不到,因为它是在当前程序集中取得资源。所以,我们的程序集引用了GifImageLib.dll,而资源都是在主程序集中,并没有在GifImageLib.dll中,这样当加载程序的时候就会出错了。
那怎么解决呢?既然知道了是因为程序集找错了的原因,那我就指定程序集好了,在初始化属性设置时使用Assembly.GetExecutingAssembly().GetName().Name得到主程序集名称并构造一个新的Uri,然后再调用SetSoruce方法,但总是提示安全性问题,应该是初始化时并不是由主程序集加载的原因吧(我的怀疑,没有被验证过)。既然这样不行,那就再想别的办法吧。
对于资源的访问,一般会有两种形式的区别,即是否是以反斜杠开头,如UriSource="Images/icons/ico8.gif"和UriSource="/Images/icons/ico8.gif",这两种方式有什么区别这里不多讲,网上好多。这里先看下我们的情况,我们复制过来的图片默认都是以Resouce的形式打包在程序集(dll)中,这样,在使用Blend设置URI的时候,你会发现,选择的图片前面全是不带反斜杠的,现在我们把图片全部改成内容
(这需要在VS中进行,Blend中没发现操作的地方),然后再选择图片试试,发现默认的Blend就会为图片前面加上反斜杠了。而作为内容形式输出,也可以在多个程序集中共享这些资源,以后我们会见到这种情况。
现在运行,又有问题了。The property does not exist on the type in the XML namespace,一直以为是命名空间或是资源上的问题,搞了好久,后来发现,是属性没有提供get访问器,这样在编译的时候就取不到这个属性(怀疑是这样,但为什么要去取值,不知道),所以就会编译不过,但如果没有在XAML代码中设置这个属性则没有任何问题。
接下来,说说第二种HyperlinkButton,如图所示
即是在鼠标悬停时有一张背景图来区别其它状态,本来这里不会有什么问题的,直接修改背景图在各种视图状态中的可见性即可,但我们这里应用的有些不同,注意看按钮的右下角,是的,有一个小的分隔线,这就要求,一个按钮需要有两张不同的背景图来区分不同的状态。
按典型的应用,这个问题应该使用控件模板来解决,于是想,初始时设置一张背景图,在MouseOver状态时再换成另一张图片试试,但不行,其原因应该是在控件模板的不同视图状态中不能动态添加或切换其它元素吧。我们再看看现在的控件模板
有两个地方可以引用背景,Grid与ContentPresenter,当然要做一些小的修改,如下
然后我们设置grid的背景为悬停状态的背景图,如下
设置border的背景,如下
然后再设置整个HyperlinkButton的背景图片
<HyperlinkButton.Background>
<ImageBrush ImageSource="/Images/topmenu.png"/>
</HyperlinkButton.Background>
这样就可以在不同的视图状态中修改grid的背景图的可见性,但好像在某个地方看到过,尽量不要设置控件的Visibility属性,因为绘制透明是比较耗资源的,那我们这里就设置图片的相对位置偏移就行了,也可以达到同样的目的,毕竟不需要缓动效果。