闲着没事,仿照SDK的样子自己做了一个。
程序主要使用了System.Windows.Markup命名空间下的XamlReader类和XamlWriter,
其中XamlReader可以将Xaml代码转换为元素示例,而XamlWriter类可以将元素示例保存成“流”的形式。(我在之前的
文章中介绍过这两个类)
首先仿照SDK中的xamlPad构建出相应的界面,页面主要包括以下几个控件。一个Label控件,用于呈现XAML代码所显示的界面;一个TextBox控件,用于输入xaml代码;还有一个GridSpliter,用于调节2这的布局比例;TextBox下面紧接着一个TextBlock控件,用于显示错误信息。整体代码如下:
<Grid> <Grid.RowDefinitions> <RowDefinition Height="4*"/> <RowDefinition Height="auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Label HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="0"/> <GridSplitter Height="2" Grid.Row="1" HorizontalAlignment="Stretch" ></GridSplitter> <GroupBox Grid.Row="2"> <DockPanel> <Label DockPanel.Dock="Bottom" VerticalAlignment="Bottom" VerticalContentAlignment="Bottom" Height="30"></Label> <TextBox Name="xamlTB" Foreground="Red" AcceptsReturn="True" VerticalScrollBarVisibility="Visible" ></TextBox> </DockPanel> </GroupBox> </Grid> 下面看一下具体的逻辑代码:
string xaml = value.ToString().Trim(); XmlReader reader = new XmlTextReader(new StringReader(xaml)); object obj = System.Windows.Markup.XamlReader.Load(reader); XamlReader.Load方法需要一个流对象,因为XAML是基于XML的,所以很自然的选用了XmlReader对象。这样就通过Load方法得到了一个WPF的元素,将它存储在obj变量中。得到元素后并不能直接将它赋值给Label对象,因为可能会发生错误:
我们可能得到多种类型的元素,如过元素类型是Window,对于Window对象来说,它只能是根级元素,不能让它作为其他元素的子元素;如果是Page对象,它只能成为Window元素或者Frame的子元素;其他元素就好说了,可以直接将他们赋值给Label的Content属性:
if ((obj as Window) != null) { #region if (win != null) { win.Close(); win = null; } win = obj as Window; win.Show(); #endregion } else if ((obj as Page) != null) { #region StreamWriter sw = new StreamWriter(path); XamlWriter.Save(obj, sw); sw.Close(); Frame f = new Frame(); f.Source = new Uri(path, UriKind.RelativeOrAbsolute); #endregion } else { ///......... } 整个的程序结构大概就是这样了,还是比较简单的。不过在程序的制作过程中,有一个问题困扰了我很久。究竟是应该的使用原始的.Net事件呢?还是应该使用WPF的绑定呢?实际上我在做项目的时候也遇到了这个问题。那是因为对时间要求很紧,我还是选择了前者(因为更加熟悉: P)。但这个程序我全部使用了WPF的特性,现在就给大家介绍一下:
文本框输入,结果输出到Label中,这可以说是WPF非常典型的绑定“案例”了。不过将XAML直接输出到Label上是没有意义的,需要进行XAML-Element的转化,所以使用了IValueConverter接口。我创建了一个XamlToElement类。该类实现了IValueConverter接口IConvert和ConverterBack方法,并且在Converter中实现了对xaml到元素的转换操作。同时为了让错误信息的及时的显示到TextBlock上,XamlToElement实现了INotifyPropertyChanged接口,用于及时消息通知。完整的代码如下:
XAML:
<Window x:Class="XamlPad.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:XamlPad" Title="XamlPad" Width="746" Height="540" > <Window.Resources> <local:XamlToElement x:Key="xamlToElement"/> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="4*"/> <RowDefinition Height="auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Label HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="0" Content="{Binding Path=Text, ElementName=xamlTB, Converter={StaticResource xamlToElement}}"/> <GridSplitter Height="2" Grid.Row="1" HorizontalAlignment="Stretch" ></GridSplitter> <GroupBox Grid.Row="2"> <DockPanel> <Label DockPanel.Dock="Bottom" VerticalAlignment="Bottom" VerticalContentAlignment="Bottom" Height="30" Content="{Binding Path=ErrorMessage,Source={StaticResource xamlToElement}}" ></Label> <TextBox Name="xamlTB" Foreground="Red" AcceptsReturn="True" VerticalScrollBarVisibility="Visible" ></TextBox> </DockPanel> </GroupBox> </Grid></Window>C#:
public class XamlToElement : IValueConverter,INotifyPropertyChanged { /// <summary> /// xaml转换后得到的Window对象 /// </summary> Window win; /// <summary> /// xaml转换后得到的元素,其中包括Page /// </summary> object obj; /// <summary> /// 判断元素类型,Window=true,Page=false,element=null; /// </summary> bool? flag; /// <summary> /// Page的存储路径 /// </summary> string path = Environment.CurrentDirectory + "\\temp.xaml"; private string errorMessage; public string ErrorMessage { get { return errorMessage; } set { errorMessage = value; OnPropertyChanged("ErrorMessage"); } } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { string xaml = value.ToString().Trim(); XmlReader reader = new XmlTextReader(new StringReader(xaml)); try { //得到元素对象 obj = System.Windows.Markup.XamlReader.Load(reader); ErrorMessage = ""; if ((obj as Window) != null) { #region flag = true; if (win != null) { win.Close(); win = null; } win = obj as Window; win.Show();//这里会出现闪屏的情况,大家忍耐以下吧,^_^ return null; #endregion } else if ((obj as Page) != null) { #region flag = false; StreamWriter sw = new StreamWriter(path); XamlWriter.Save(obj, sw); sw.Close(); Frame f = new Frame(); f.Source = new Uri(path, UriKind.RelativeOrAbsolute); return f; #endregion } else { flag = null; return obj; } } catch (System.Exception a) { ErrorMessage = a.Message; if (flag == true) return ""; else if (flag == false) { Frame f = new Frame(); f.Source = new Uri(path, UriKind.RelativeOrAbsolute); return f; } else return obj; } } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return null; } public event PropertyChangedEventHandler PropertyChanged; // OnPropertyChanged to update property value in binding private void OnPropertyChanged(string propName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propName)); } } } 整个程序就介绍完了,希望大家多提意见:P
源代码下载