- 回过头,继续看看 WPF 程序
如何从仅使用代码过渡到使用XAML呢...
| 例子 | 程序文件 | 编译 |
| (一)只包含代码 | program.cs | 直接命令行调用csc |
| (二)代码+未编译XAML | grid.xaml | 同上 |
| (三)代码+编译的XAML | mywindow.xaml | 写个工程文件(project.wpf),直接调用msbuild |
| (四)代码+编译的XAML | app.xaml | 同上 |
程序结构?
- C# 程序 需要有一个static的 Main() 成员函数作为入口点
- GUI 程序至少需要有一个窗口
- GUI 程序一般有一个 Application 实例来管理所有窗口以及程序全局资源等等
例子一(只使用代码)
我想写一个带布局的窗口,使用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的代码完全没办法比,哈)
例子二(未编译的xaml)
如果使用将布局相关的代码剥离出来,会不会好一点?
类似于Qt中 .ui 文件的动态加载
- grid.xaml
<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>
- program.cs
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");
例子三(编译的xaml)
WPF程序中,xaml一般要编译成后baml文件,然后嵌入到资源中,同时,自动生成一个partial类,来完成xmal中控件和类中field的连接。(网上提到较多是xamlc.exe负责完成该工作;但现在,这个工具程序应该不存在了,该为由msbuild内置的Task来完成)。
同样是前一个程序,现在整个MyWindow改由 xaml实现:
- 界面文件: 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>
- 逻辑 program.cs
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.wpf
<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文件(似乎比较让人困惑)。
- mywindow.xaml (和前一个例子一样,略过)
- app.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>
- program.cs
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加入我们前面的工程文件
- project.wpf
...
<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入口可能还不符合我们的口味。但是对于使用其他工具进行界面设计的人来说,它就变得很重要了,比如:用来存放程序所需要的资源文件等。
从代码到XAML:WPF程序的过渡与实践
本文详细介绍了WPF程序如何从纯代码过渡到使用XAML,包括不同阶段的代码实现与编译过程。通过具体例子展示了如何在C#程序中集成XAML文件,实现界面与逻辑的分离,最终使用MSBuild工具进行编译。讨论了不同文件结构对程序的影响,并解释了为何在某些情况下需要引入特定的XAML文件和Application定义。
2132

被折叠的 条评论
为什么被折叠?



