silverlight获取网页里的资源文件

内容来源http://longer3436.blog.163.com/blog/static/12833062200987104249150/该博客

Silverlight 3 Theme研究

Silverlight 2009-09-07 22:42:49 阅读503 评论0   字号: 订阅

 

  •  

    Silverlight 3对于主题也有了很好的支持,在toolkit中已经提供了不少主题,当然也可能自己设计主题了,只要有一个xaml文件就够了,这样设计人员之间就能够共享主题。这里主要总结两个东西,一个是关于隐式主题,另一个当然就是显式的啦。

    ImplicitStyle

    什么是隐式样式?知道CSS的大概就知道是什么意思了。在SL中写一个Style的话,除了需要指明其TargetType,还需要指定一个Key,这样在控件中使用Style={StaticResource KeyName}的方式来加载Style。而隐式样式则不需要指定Key,也就是说如果指定了一个隐式样式的TargetType并且在项目或者某个Layout的控件中引用了这个样式,那么在项目或控件内部所有那种类型的控件都会应用那个样式,这样就不用一个一个控件地写Style=了,自然是方便不少。

    正是因为所有同类型的控件都会加载同样的Style,可能在设计的时候并不希望这样,总是有一些是特别的。没有关系,因为隐式样式的优先级比较低,如果你设置了其他的样式的话自然会覆盖掉隐式样式的。

    好了,现在来总结一下如何使用ImplictStyle。

    使用隐式样式,首先要添加toolkit的System.Windows.Controls.Theming.Toolkit.dll程序集,当然在需要使用的xaml中也要添加相应的命名空间啦。现在添加一个新的User Control,就叫TestStyle吧。首先添加命名空间:

     

     

    xmlns:theme="clr-namespace:System.Windows.Controls.Theming;assembly=System.Windows.Controls.Theming.Toolkit"

     

    然后添加一个StackPanel吧,在里面添加一个按钮,然后设定样式:

     

     

    <Button Content="button" Width="100" Height="22" x:Name="button" ></Button>

     

    当然了,这个按钮的样式现在还没有写,接下来的工作就是要添加这样一个样式了。文件放置的位置无所谓了,这里按照微软的习惯,先建立一个文件夹,名字为Assets,然后在里面添加一个xaml文件,叫Styles.xaml,样式就写在这个文件里

    Silverlight 3 Theme研究 - longer3436 - 女神的香

     

     

    <ResourceDictionary

      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

      xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"

        xmlns:uc="clr-namespace:TestControl;assembly=TestControl"

        xmlns:common="clr-namespace:Common;assembly=Common"

        >

       

        <Style TargetType="Button">

            <Setter Property="Foreground" Value="Red"></Setter>

        </Style>

    /ResourceDictionary>

     

    这个时候如果直接运行会发现,按钮的样式并没有改变。这个时候toolkit的ImplicitStyleManager就该出场了,可以在任意的Layout控件中使用,现在我们就在StackPanel中添加吧:

     

     

     <StackPanel x:Name="LayoutRoot" theme:ImplicitStyleManager.ApplyMode="Auto" theme:ImplicitStyleManager.ResourceDictionaryUri="Assets/Styles.xaml" Background="White" >

     

    上面的代码指定了两个东西,一个是隐式样式的添加模式,有三种:none、auto和onetime。none就跟你没有写ApplyMode的效果是一样的,而onetime就是只加载一次了,auto则允许多次加载。另一个就是ResourceDictionaryUri,它指定了隐式样式所在的文件。

    那么好吧,现在直接运行一下?很不幸,程序可以编译通过,但是运行的时候出错了。这是因为ImplicitStyleManager无法找到相应的资源。那怎么办呢,很简单,Styles.xaml文件在新建的时候,其默认的“Build action”是page,这样隐式样式是无法加载的,我们需要把它改为Content。在Styles.xaml上右键,选择属性,将Build Action 改为Content。运行下程序,OK了,按钮的字体变成红色了:

    Silverlight 3 Theme研究 - longer3436 - 女神的香

    并且我们可以看到,在StackPanel外面的Button是不受这个隐式样式的影响的,比如:

     

     

    <StackPanel x:Name="LayoutRoot" Background="White" ><!---->    

              <Button Content="button without style" Width="200" Height="22"></Button>

            <StackPanel theme:ImplicitStyleManager.ApplyMode="Auto" theme:ImplicitStyleManager.ResourceDictionaryUri="Assets/Styles.xaml" >

            <Button Content="button" Width="200" Height="22" x:Name="button"></Button>

             </StackPanel>

    </StackPanel>

     

    这样运行的结果将是:

    Silverlight 3 Theme研究 - longer3436 - 女神的香

    这个结果正是我们希望的。同样,即使是在Layout控件内部的,如果已经定义了样式或对相应属性进行了设置,也是会覆盖隐式样式的。至于说隐式样式到底是怎么起作用的,这个就要涉及AttachProperty,比较麻烦了,这里暂时不讲,可以到网上搜一下。

    还有一点要说的是,ResourceDictionaryUri是全局的,不仅可以在这里指定,在其他地方也可以指定,最后使用哪个路径就看哪个最后加载了。

    在预编译的时候设定样式是很顺利了,那么在运行时又该如何改变呢?其实也非常简单,现在就来做个小测试吧。

    首先添加一个按钮,其作用就是改变样式。然后依照刚才的方法,在Assets文件夹中添加一个新的xaml文件,将按钮的字体颜色设置为绿色。注意别忘了把Build Action改为了Content。这时需要对xaml文件作一些修改:

     

     

    <Button Content="button without style" Width="200" Height="22"></Button>

            <StackPanel x:Name="Container" theme:ImplicitStyleManager.ApplyMode="Auto" theme:ImplicitStyleManager.ResourceDictionaryUri="Assets/Styles.xaml" >

            <Button Content="button" Width="200" Height="22" x:Name="button"></Button>

            <Button Content="change style" Width="100" Height="22" Foreground="Black" Click="Button_Click" ></Button>

        </StackPanel>

     

    然后在后台添加代码:

     

     

      private bool _change = false;

            private void Button_Click(object sender, RoutedEventArgs e)

            {

                if (_change)

                {

                    ImplicitStyleManager.SetResourceDictionaryUri(this.Container, new Uri("Assets/GreenStyles.xaml", UriKind.RelativeOrAbsolute));

                }

                else

                {

                    ImplicitStyleManager.SetResourceDictionaryUri(this.Container, new Uri("Assets/Styles.xaml", UriKind.RelativeOrAbsolute));

                }

                ImplicitStyleManager.SetApplyMode(this.Container, ImplicitStylesApplyMode.Auto);

                ImplicitStyleManager.Apply(this.Container);

                _change = !_change;

    }

     

    运行一下就可以看到了,添加了隐式样式的按钮,在点击之后按钮的样式就会改变,而没添加的按钮就不收影响。需要对上面的代码作一个简单的说明,调用SetResourceDictionaryUri方法来改变当前的样式文件的路径,这样可以调用不同的样式了,但是仅仅是这样是不会立刻改变的,还需要调用SetApplyMode方法设置模式,并调用Apply方法来提交改变,这样就能达到目的了。不过需要注意的是这几个方法传递的参数,第一个参数都是你想要Attach相应的样式的控件,比如我现在就是将样式Attach到StackPanel中,这样只有在里面的Button才会受影响。而如果我把“this.Container”改成“this”,那么整个UserControl都会Attach这个样式,其结果就是即使是在StackPanel外面的那个Button样式也会改变。

    就跟显式样式会优于隐式样式一样,隐式样式自己也是有优先级的关系的。就像上面说的,如果在UserControl上Attach样式,但是如果在StackPanel上同样也Attach了,并且指定了ResourceDictionaryUri,那么在StackPanel里面的Button的样式就不会改变了。简单来说,就是父控件样式的范围会更广,而子控件样式的优先级会比较高。

    最后还有一点想要说明的是,之前的测试都是在同一个工程里面的,如果在解决方案下有多个工程,那么在其他工程中该如何使用呢?其实是一样的,并不需要做什么改动。

    好了,关于隐式样式的内容就是那么多了,再来总结一下显示样式吧。

    Theme

    我想写过Silverlight程序的人大多应该有这样的体会:写Style真是件让人很痛苦的事。因为随便一个什么样式都很可能会写上上百行甚至数百行或者更多。而以前全局的样式只能写在App.xaml里面,这样直接导致的一个结果就是这个文件会变得超大,大得让人无法忍受,除了打开会很慢很慢外,想要从中找出个什么东西来也是非常困难的一件事。现在就不一样了,允许将样式文件分放到不同的地方,这真是个很好的改进。现在来看看这个东西是怎么工作的吧。

    为了简便起见还是用刚才定义的两个样式文件:Styles.xaml和GreenStyles.xaml。如果是显式样式的话,其Build Action似乎不是很重要(具体还没详细研究),无论是page还是Content都可以正常工作,因此就不改了。唯一做的改动就是给每个样式添加一个key,就叫ButtonStyle好了。

     

     

     <Style x:Key="ButtonStyle" TargetType="Button">

            <Setter Property="Foreground" Value="Red"></Setter>

        </Style>

     

    接下来就是要改动app.xaml了:

     

     

    <Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

                 x:Class="TestControl.App"

                 >

        <Application.Resources>

            <ResourceDictionary>

                <ResourceDictionary.MergedDictionaries >

                    <ResourceDictionary  Source="Assets/Styles.xaml"></ResourceDictionary>

                </ResourceDictionary.MergedDictionaries>

            </ResourceDictionary>

        </Application.Resources>

    </Application>

     

    可以看到,我在Application.Resources里面添加了一个ResourceDictionary,同时又在其MergedDictionaries 里面再添加了一个ResourceDictionary ,在最后这个ResourceDictionary 里面指定其Source是事先写好的Style文件的路径,这样就可以全局调用这个资源了。调用的方法跟普通的样式是一样的,如下:

     

     

    <Button Content="button" Width="200" Height="22" x:Name="button" Style="{StaticResource ButtonStyle}" ></Button>

     

    这样Button就添加了样式了。

    MergedDictionaries 是一个集合,有了这个东西,ResourceDictionary里面可以再添加ResourceDictionary,这样就能把样式分开到不同的文件了,是不是方便很多呢?最关键的还不是这里,有了这个东西就可以很方便的改变样式了哦,因此改变主题也就不是那么困难了。那么下面再来通过一个小例子说明下如果动态改变主题吧。

    还是像刚才那样,点击一下按钮样式就改变,但是代码要做相应的变动:

     

     

     App.Current.Resources.MergedDictionaries.Clear();

                if (_change)

                {

                    App.Current.Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("/Assets/Styles.xaml", UriKind.RelativeOrAbsolute) });

                }

                else

                {

                    App.Current.Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("/Assets/GreenStyles.xaml", UriKind.RelativeOrAbsolute) });

                }

                his.button.Style = App.Current.Resources["ButtonStyle"] as Style;

     

    上面的代码跟之前的隐式样式有些不同,首先是要将MergedDictionaries清除掉,然后添加新的资源,但是这样并不会马上改变控件的样式,还需要显示地设置其style才行,或者重新加载页面。这里有一个地方尤其需要注意的,请仔细观察两个方法设置xaml文件路径的异同,细心点可以发现,在显式样式的时候前面多了一个斜杠!这个是必须的,否则编译不通过,会抛出“对 COM 组件的调用返回了错误 HRESULT E_FAIL。”这么一个异常,原因是无法找到相应的资源(我以后哈,不是特别确定)。关于这点,就要涉及到Silverlight关于资源的引用的问题了,这里不想多说,引用同事Kevin Yang博客的一片文章中的一段话来简要说明一下吧:

     

    1. Resource —— 资源会被打包在程序集内部
    2. Content——资源会被打包在Xap包里面
    3. None——资源既不会被集成到程序集内,也不会打包到xap包中。不过我们可以通过设置CopyToOutputDirectory选项让其自动拷贝到xap包所在目录。

       

      再来说引用的问题。

    4. 使用前置 / 引用资源时,SL会从当前Xap包中查找资源,找不到的话会到Xap包所在的目录查找
    5. 不使用前置 / 引用资源时,SL会从当前程序集内查找资源,如果找不着则会到Xap包所在目录查找其他选项你知道的话
    6. 你也可以使用/{程序集名};component/{图片资源路径}的方式来访问,这样就查找的路径就限定在程序集内部了,也就是那些标记为Resource的资源。

     

    最后需要说的是,如果你的解决方案是有多个工程的,而且使用上面的路径还是抛出那个异常了,那么也不用太担心,基本上是路径的问题,可以尝试用“/{程序集名};component/{图片资源路径}”的方法来设置路径,比如我现在这个项目就可以这样设置“/TestControl;component/Assets/Styles.xaml”,这样一般不会有问题了,如果还有问题可能就是RP问题了。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值