技术开发 频道

WPF 企业应用基础 WPF的千年轮回

  这里我们需要特别注意的是 XamlReader 载入的 XAML 代码不能包含任何类型(x:Class)以及事件代码(x:Code),也就是说要XAML自身的代码才受支持(这个也在WPF揭秘这本书讲到过)。那么我们可以用 XamlWriter 将一个编译的 BAML 还原成 XAML了,具体代码如下:

//XamlWritervar  
xaml
= XamlWriter.Save(new
Window2());
MessageBox.Show(xaml);

 

  输出的Message如下(为了效果更好看一些,我粘贴到了VS):

<Window2 Title="Window2" idth="300"Height="300"
xmlns
="clr-namespace:XamlReaderWriterDemo;

assembly
=XamlReaderWriterDemo"

xmlns:av
="http://schemas.microsoft.com/winfx/2006/xaml/presentation">  
  
<av:Grid>      
  
<av:Button Name="btnTest" Height="23" Margin="98,72,105,0" VerticalAlignment="Top">
Button
</av:Button>
    
</av:Grid>
</Window2>

 

  XAML 的动态载入在使用动态换肤以及运行时加载等场景颇为有用,以后也会慢慢接触。

  由于使用XamlReader和XamlWriter有很多限制,比如我想把一批Baml转化为Xaml,再比如我想指定Baml的路径,然后通过Load的方式载入,那么这些场景就无法通过XamlReader和XamlWriter完成了,这个让我也做过不少的Demo,也跟踪了很长时间的IL代码,在百思不得其解之后和周永恒、Virus等讨论了一下,最后终于找到了一个方案,如下代码所示:

public static class BamlWriter {  
  
public static void Save(object obj, Stream stream)  
  {      
  
string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
        Directory.CreateDirectory(path);      
   try  
      {      
      
string xamlFile = Path.Combine(path, "input.xaml");
            
string projFile = Path.Combine(path, "project.proj");  
           using (FileStream fs
= File.Create(xamlFile))    
         {          
      XamlWriter.Save(obj, fs);        
     }          
   Engine engine
= new Engine();
             engine.BinPath
= RuntimeEnvironment.GetRuntimeDirectory();      
       Project project
= engine.CreateNewProject();
            BuildPropertyGroup pgroup
= project.AddNewPropertyGroup(false);      
       pgroup.AddNewProperty(
"AssemblyName", "temp");
             pgroup.AddNewProperty(
"OutputType", "Library");
             pgroup.AddNewProperty(
"IntermediateOutputPath", ".");
            pgroup.AddNewProperty(
"MarkupCompilePass1DependsOn", "ResolveReferences");
            BuildItemGroup igroup
= project.AddNewItemGroup();  
           igroup.AddNewItem(
"Page", "input.xaml");
            igroup.AddNewItem(
"Reference", "WindowsBase");
            igroup.AddNewItem(
"Reference", "PresentationCore");
             igroup.AddNewItem(
"Reference", "PresentationFramework");
            project.AddNewImport(@
"$(MSBuildBinPath)\Microsoft.CSharp.targets", null);  
           project.AddNewImport(@
"$(MSBuildBinPath)\Microsoft.WinFX.targets", null);      
      project.FullFileName
= projFile;            
if (engine.BuildProject(project, "MarkupCompilePass1"))
             {                
byte[] buffer = new byte[1024];                
using (FileStream fs
= File.OpenRead(Path.Combine(path, "input.baml")))
                {                  
  
int read = 0;    
                
while (0 < (read = fs.Read(buffer, 0, buffer.Length)))  
                  {    
                    stream.Write(buffer,
0, read);    
              
}  
              }  
           }        
    
else          
   {              
   throw
new System.Exception("Baml compilation failed.");    
         }    
     }      
   finally      
   {            
Directory.Delete(path,
true);  
       }  
   }
}
public static class BamlReader
{    
public static object Load(Stream stream)
     {        
ParserContext pc
= new ParserContext();
    
   return typeof(XamlReader)          
   .GetMethod(
"LoadBaml", BindingFlags.NonPublic | BindingFlags.Static)      
       .Invoke(
null, new object[] { stream, pc, null, false });  
  }
}

 

  上面的代码,大家可以试一下运行效果。或者有更好的方式也请告知。

  七,本文总结

  本篇主要对前几次的课程进了一些简单的回顾,同时用一个比较全的Demo介绍了Xaml中引用各种控件和类等,另外对脱离VS工具CSC编译WPF以及XamlReader与XamlWriter 做了比较详细的介绍。下篇我们将进入WPF布局的世界进行漫游,争取和布局控件及应用来一个全接触!

  最后圣殿骑士 会尽心尽力写好这个系列,同时由于是自己对这些技术的使用总结和心得体会,错误之处在所难免,怀着技术交流的心态,在博客园和51CTO发表出来,所以希望大家能够多多指点,这样在使一部分人受益的同时也能纠正我的错误观点,以便和各位共同提高,后续文章敬请关注!

0
相关文章