如何从 仅使用代码 过渡到 使用XAML 呢...
例子 |
程序文件 |
编译 |
(一)只包含代码 |
program.cs |
直接命令行调用csc |
(二)代码+未编译XAML |
grid.xaml |
同上 |
(三)代码+编译的XAML |
mywindow.xaml |
写个工程文件(project.wpf),直接调用msbuild |
(四)代码+编译的XAML |
app.xaml |
同上 |
我想写一个带布局的窗口,使用Grid布局一个 按钮和一个文本框
using System; using System.Windows; using System.Windows.Controls; namespace DbZhang800 { public class MyWindow : Window { private TextBox textEdit; private int clickCount; public MyWindow() { this.Width = 300; this.Height = 300; this.Title = "Grid Layout"; Grid grid = new Grid(); ColumnDefinition col1 = new ColumnDefinition(); col1.Width = GridLength.Auto; ColumnDefinition col2 = new ColumnDefinition(); col2.Width = new GridLength(1, GridUnitType.Star); grid.ColumnDefinitions.Add(col1); grid.ColumnDefinitions.Add(col2); this.Content = grid; Button button1 = new Button(); button1.Content = "Say Hello!"; button1.Click += new RoutedEventHandler(button1_Click); grid.Children.Add(button1); Grid.SetColumn(button1, 0); textEdit = new TextBox(); grid.Children.Add(textEdit); Grid.SetColumn(textEdit, 1); this.clickCount = 0; } void button1_Click(object sender, RoutedEventArgs e) { textEdit.Text = string.Format("Hello WPF's Grid Layout! No.{0}", this.clickCount); this.clickCount ++; } } public class App:Application { public App() { } [STAThread] public static void Main() { App app = new App(); app.Run(new MyWindow()); } } }
编译一下:
Csc.exe /lib:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0" /r:PresentationCore.dll /r:PresentationFramework.dll /r:System.Core.dll /r:System.Windows.Presentation.dll /r:WindowsBase.dll /target:exe Program.cs
其他似乎都好说,就是和布局有关系的代码,太让人难受了(似乎和Qt的代码完全没办法比,哈)
如果使用将布局相关的代码剥离出来,会不会好一点?
类似于Qt中 .ui 文件的动态加载
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Button Name="button1" Grid.Column="0">Say Hello!</Button> <TextBox Name="textEdit1" Grid.Column="1" xml:space="preserve" /> </Grid>
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Markup; using System.IO; namespace DbZhang800 { public class MyWindow : Window { private TextBox textEdit; private int clickCount; public MyWindow() { this.Width = 300; this.Height = 300; this.Title = "Grid Layout"; FileStream s = new FileStream("grid.xaml", FileMode.Open); DependencyObject root = (DependencyObject)XamlReader.Load(s); this.Content = root; Button button1 = (Button)LogicalTreeHelper.FindLogicalNode(root, "button1"); button1.Click += new RoutedEventHandler(button1_Click); textEdit = (TextBox)LogicalTreeHelper.FindLogicalNode(root, "textEdit1"); this.clickCount = 0; } void button1_Click(object sender, RoutedEventArgs e) { textEdit.Text = string.Format("Hello WPF's Grid Layout! No.{0}", this.clickCount); this.clickCount ++; } } public class App:Application { public App() { } [STAThread] public static void Main() { App app = new App(); app.Run(new MyWindow()); } } }
编译命令和前面完全相同(此处略)。
在代码中,我们通过 XamlReader 来加载这个 xaml 文件,并生成一个 DependencyObject,然后借助LogicalTreeHelper 找到我们需要进行逻辑操作的节点。
由于Grid等都是FrameWorkElement的派生类,故还可以
//DependencyObject root = (DependencyObject)XamlReader.Load(s); FrameworkElement root = (FrameworkElement)XamlReader.Load(s); this.Content = root; //Button button1 = (Button)LogicalTreeHelper.FindLogicalNode(root, "button1"); Button button1 = (Button)root.FindName("button1");
WPF程序中,xaml一般要编译成后baml文件,然后嵌入到资源中,同时,自动生成一个partial类,来完成xmal中控件和类中field的连接。(网上提到较多是xamlc.exe负责完成该工作;但现在,这个工具程序应该不存在了,该为由msbuild内置的Task来完成)。
同样是前一个程序,现在整个MyWindow改由 xaml实现:
<Window x:Class="DbZhang800.MyWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="300" Width="300" Title="Grid Layout"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Button Name="button1" Click="button1_Click" Grid.Column="0">Say Hello!</Button> <TextBox Name="textEdit" Grid.Column="1" xml:space="preserve" /> </Grid> </Window>
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Markup; namespace DbZhang800 { public partial class MyWindow : Window { private int clickCount; public MyWindow() { InitializeComponent(); this.clickCount = 0; } void button1_Click(object sender, RoutedEventArgs e) { textEdit.Text = string.Format("Hello WPF's Grid Layout! No.{0}", this.clickCount); this.clickCount ++; } } public class App:Application { public App() { } [STAThread] public static void Main() { App app = new App(); app.Run(new MyWindow()); } } }
恩,程序写完了,一共两个文件。可是在没有Visual Studio的情况下,如何编译它呢??
因为没有xamlc.exe 这种命令行工具,只能使用MSBuild了,这样需要有一个工程文件
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <AssemblyName>HelloWPF</AssemblyName> <OutputType>winexe</OutputType> </PropertyGroup> <ItemGroup> <Reference Include="System" /> <Reference Include="WindowsBase" /> <Reference Include="PresentationCore" /> <Reference Include="PresentationFramework" /> </ItemGroup> <ItemGroup> <Page Include="mywindow.xaml" /> <Compile Include="program.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets" /> </Project>
基本完工了了,运行
msbuild project.wpf
即可得到可执行程序 HelloWPF.exe
上一个例子和Visual Studio生成的工程很接近了,但是还有一点。VS生成的工程中,Application也需要一个xaml文件(似乎比较让人困惑)。
<Application x:Class="DbZhang800.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="MyWindow.xaml"> </Application>
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Markup; namespace DbZhang800 { public partial class MyWindow : Window { private int clickCount; public MyWindow() { InitializeComponent(); this.clickCount = 0; } void button1_Click(object sender, RoutedEventArgs e) { textEdit.Text = string.Format("Hello WPF's Grid Layout! No.{0}", this.clickCount); this.clickCount ++; } } public partial class App:Application { } }
要编译这个程序,需要将 app.xaml加入我们前面的工程文件
... <ItemGroup> <ApplicationDefinition Include="app.xaml" /> <Page Include="mywindow.xaml" /> <Compile Include="program.cs" /> </ItemGroup> ...
对于普通的xaml,使用的是Page,对于程序xaml文件,使用的是ApplicationDefinition(这样,为其自动生成的那个app.g.cs文件中会包含 Main入口函数)
好了,现在运行
msbuild project.wpf
即可。
程序编译没问题了,但是,但是,这个xaml和界面没有什么关系,为什么要弄个这东西出来??
对于代码编写者来说,这个确实没什么必要,而且有时它自动生成的Main入口可能还不符合我们的口味。但是对于使用其他工具进行界面设计的人来说,它就变得很重要了,比如:用来存放程序所需要的资源文件等。
LIVING WITHOUT APP.XAML (... AND STILL BEING ABLE TO USE BLEND!)
Building a WPF Application (WPF)
Code and Compiled XAML
Understanding In and Out of XAML in WPF
How to load BAML resources