XamlPad小程序


   
        闲着没事,仿照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
源代码下载


posted on 2007-07-09 00:03  stswordman  阅读(6283)  评论(8编辑  收藏  举报