使用winform编写商场收银系统
主要是以学习为主,以前用Winform写过简单商场收银系统,现在转换到使用WPF来实现
目录
②使用属性元素(Property Element)进行复杂赋值
第一部分、WPF基础知识
对象属性赋值
XAML是一种声明性语言,XAML编译器会为每个标签创建一个与之对应的对象。创建对象后,需对其属性初始化。因为XAML语言不能编写程序的运行逻辑,所以一份XAML文档中除了使用标签声明对象就是初始化对象的属性。
XAML中为对象属性赋值共两种语法(例子为Rectangle类对象的Fill属性):
①使用字符串进行简单赋值
Attribute1=Value1
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Rectangle x:Name="rectangle" Width="200" Height="120" Fill="Blue"/>
</Grid>
更复杂的字符串实例
<Path Data="M 0,0 L 0,65 L 65,0 Z" Stroke="Transparent" Fill="HotPink"/>
由于使用Attribute1=Value1存在缺点:Value只能是一个字符串。如果一个类只能使用XAML语言进行声明,并允许其Property(面向对象理论范畴,对客观实物进行抽象出来的属性)与XAML标签的Attribute(编程语言文法层面,用于区分两个同类语法元素A和B的特征)互相映射,那就需要为这些Property进行转换。
定义TypeConverter类的派生类,重写TypeConverter的方法
使用TypeConverter类将XAML标签的Attribute与对象的Property进行映射
.cs文件中的代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ShopWpf
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//先把Window资源检索出来,窗体自己的方法FindResource,把字典给方法,返回类型为object,要转换为Staff
Staff staff = this.FindResource("staff") as Staff;
if (staff != null)
{
MessageBox.Show("当前员工姓名:"+ staff.Name + "\n" +
"员工号码:" + staff.Telephone + "\n" +
"员工家庭成员:" + staff.Familymember.Name); //staff的Name属性本身就是字符串类型
}
}
}
//NameToStaffTypeConverter类以特性形式附加到Staff类上去
[TypeConverterAttribute(typeof(NameToStaffTypeConverter))]
public class Staff
{
public string Name { get; set; }
public string Telephone { get; set; }
public Staff Familymember { get; set; } //职员的家庭成员也有名字和电话号码
}
public class NameToStaffTypeConverter : TypeConverter //定义TypeConverter的派生类
{ //给出staff中的Familymember一个字符串就可以基于这个字符串就可以声明一个Staff的对象并且把这个字符串赋值给Name属性
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) //重写方法
{
string name = value.ToString();
Staff familymember = new Staff();
familymember.Name = name;
return familymember;
}
}
对应的.xaml文件
<Window x:Class="ShopWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cl="clr-namespace:ControlLibrary;assembly=ControlLibrary"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:ShopWpf"
Title="商场收银系统" Height="600" Width="450" WindowStartupLocation="CenterScreen">
<!--local:因为ShopWpf命名空间包含在当前程序集中,一般将当前程序集包含的命名空间映射为local的名称空间-->
<!--启动在屏幕正中央-->
<Window.Resources>
<!--通过window的资源声明出来,添加资源,资源字典,通过索引检索,属性标签形式,添加字符串,用于标签扩展-->
<!--Staff对象作为Window资源声明出来-->
<local:Staff x:Key="staff" Name="Alice" Telephone="10000000" Familymember="Tom"/>
<!--Staff对象检索存在于命名空间中Key对象-->
<!--通过标签形式声明一个Staff对象-->
</Window.Resources>
<Grid>
<Button Content="登录" HorizontalAlignment="Left" VerticalAlignment="Top" Height="46" Background="Transparent" BorderBrush="Transparent" RenderTransformOrigin="0.5,0.5" Margin="-28,-7,0,0" Width="88" Click="Button_Click">
<Button.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-45"/>
<TranslateTransform/>
</TransformGroup>
</Button.RenderTransform>
</Button>
</Grid>
</Window>
②使用属性元素(Property Element)进行复杂赋值
在XAML中,非空标签均具有内容(Content),标签内容指在开始标签和结束标签之间的一些子级标签,每个子级都是父级标签内容的一个元素(Element),简称为父级标签的一个元素,属性标签指的是某个标签的一个元素对应这个标签的一个属性,即以元素的形式来表达一个实例的属性。
<ClassName>
<ClassName.PropertyName>
<!--以对象形式为属性赋值-->
</ClassName.PropertyName>
</ClassName>
以上一个例子改写
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Rectangle x:Name="rectangle" Width="200" Height="120">
<Rectangle.Fill>
<SoildColorBrush="Blue"/>
</Rectangle>
</Grid>
通过使用属性元素来进行赋值,可以设计一个渐变色的Canvas
<Canvas>
<Canvas.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFCDB6E6" Offset="0"/>
<GradientStop Color="#FF611CAB" Offset="0.817"/>
</LinearGradientBrush>
</Canvas.Background>
</Canvas>
也可以设计一个渐变的Rectangle
<Rectangle Width="350" Height="400" Stroke="Transparent" Canvas.Left="25" Canvas.Top="25">
<!--Content 标签的内容,不是对象的内容-->
<Rectangle.Fill>
<!--这个也是标签,对象类型.对象属性名,不可以去掉"对象类型.",XAML编译器会声明对应类的实例,以为想声明Fill类的对象-->
<!--对象属性的内容-->
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<!--linear 线性 Gradient渐变 Brush笔刷,笔刷开始点相对值0,0左上角-->
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<!--集合-->
<GradientStop Offset="0.2" Color="BlueViolet"/>
<!--启动到终点之间连线20%-->
<GradientStop Offset="0.7" Color="DarkViolet"/>
<GradientStop Offset="1.0" Color="Purple"/>
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
标记扩展
标记扩展,一种特殊的Attribute=Value语法,特殊在于Value字符串是由一堆花括号及其括起来的内容组成,XAML编译器会对这样的内容做出解析、生成相应的对象。
XAML中为对象属性赋值的语法中,大多数赋值时为属性生成一个新对象,但有时候需把同一个对象赋值给两个对象的属性,有时候需给对象的属性赋一个null值,WPF还允许一个对象的属性值依赖在其他对象的某个属性上,当需给对象的属性进行特殊类型赋值时就要使用标记扩展
Text=“{}”这句就是标记扩展了:
①当编译器看到这句代码时就会把花括号中的内容解析为相应的对象
②对象的数据类型名时紧邻做花括号的字符串
③对象的属性由一串以逗号连接的子字符串负责初始化(注意,属性值不再加引号)
两种方法去添加TextBlock的Text属性值
<Window x:Class="ShopWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:ShopWpf"
Title="商场收银系统" Height="600" Width="450" WindowStartupLocation="CenterScreen">
<!--local:因为ShopWpf命名空间包含在当前程序集中,一般将当前程序集包含的命名空间映射为local的名称空间-->
<!--启动在屏幕正中央-->
<Window.Resources>
<!--通过window的资源声明出来,添加资源,资源字典,通过索引检索,属性标签形式,添加字符串,用于标签扩展-->
<sys:String x:Key="stringHello">友谊商店欢迎您的到来
</sys:String>
</Window.Resources>
<Grid>
<!--ResourceKey=可不写-->
<TextBlock Text="{StaticResource ResourceKey=stringHello}" TextAlignment="Center" VerticalAlignment="Top" Height="46" HorizontalAlignment="Center" Width="400" FontSize="30" Margin="0,21,0,0"/>
<TextBlock Text="联系电话:88888888" TextAlignment="Center" VerticalAlignment="Top" Height="46" HorizontalAlignment="Center" Width="400" FontSize="20" Margin="0,515,0,0"/>
</Grid>
</Window>
x名称空间介绍
x:Name的含义
XAML是一种声明式语言,XAML的标签声明的式对象,一个XAML标签会对应着一个对象,一般是一个控件的实例。
XAML这种对象声明语言只负责声明对象而不负责为这些对象声明引用变量。如果需为对象准备一个引用变量以便在C#代码中直接访问就必须显示地告诉XAML编译器——为这个对象声明引用变量,使用x:Name
作用:1、告诉XAML编译器,当一个标签带有x:Name时除了为这个标签生成对应实例外,还要为实例声明一个引用变量,变量名就是x:Name的值
2、将XAML标签所对应对象的Name属性(如果有)也设为x:Name的值,并把这个值注册到UI树上,以方便查找
在XAML代码中应该使用Name还是x:Name?
Name属性定义在FrameworkElement类(WPF控件的基类),所以所有WPF控件都具有Name这个属性;当一个元素具有Name属性时,使用Name或x:Name效果一样:
<Button x:Name="btn"/>
<Button Name="btn"/>
XAML编译器的动作都是声明名为btn的Button类型变量并引用一个Button类型实例,而且此实例的Name属性亦为btn;此时Name和x:Name是可以互换的,但不能出现在一个元素中
对于没有Name属性的元素,为了在XAML声明时也创建引用变量以便在C#代码中访问,只能使用x:Name。
由于x:Name的功能涵盖了Name属性的功能,所以全部使用x:Name增强代码的同一性和可读性。
x:FieldModifier
使用x:Name后,XAML标签对应的实例就具有了自己的引用变量,而且这些引用变量都是类的字段。默认情况下,这些字段的访问级别按照面向对象的封装原则被设置成了internal,在编程时,又是需要从一个程序集访问另一个程序集中窗体的元素,这时需要把访问控件的引用变量改为public级别,x:FieldModifier就是用来在XAML里改变引用变量访问级别的。
x:FieldModifier是用来改变引用变量访问级别的,所以使用x:FieldModifier的前提是这个标签同时也使用x:Name
使用实例:
<StackPanel>
<TextBox x:Name="textBox1" x:FieldModifier="public" Margin="5"/>
<TextBox x:Name="textBox2" Margin="5"/>
</StackPanel>
x:Key
在XAML文件中,通常把需多次使用的内容提取出来放资源字典(Resource Dictionary)中,需要使用这个资源时,就用它的Key把它检索出来:x:Key的作用就是为资源贴上用于检索的索引
在WPF中,几乎每个元素都有自己的Resources属性,这个属性是个“Key-Value”式的集合,只要把元素放进这个集合,这个元素就成为资源字典中的一个条目,为了能够检索到这个条件,需添加x:Key
示例:先在Window的资源字典中添加一个条目,这个条目是一个字符串,在后面将在XAML和C#中多次使用这个字符串
为了XAML中使用String类,使用xmlns:sys="clr-namespace:System;assembly=mscorlib"引用mscorlib.dll,并把其中的System命名空间映射为XAML中的sys命名空间
使用属性标签语法向Window.Resources里添加一个字符串,把它的x:Key设置为stringHello,窗体的Grid里包含了三个Textbox和一个Button,第一个Textbox设置了Text属性时,使用到了stringHello这个资源
<Window x:Class="ShopWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="商场收银系统" Height="600" Width="450" WindowStartupLocation="CenterScreen">
<!--local:因为ShopWpf命名空间包含在当前程序集中,一般将当前程序集包含的命名空间映射为local的名称空间-->
<!--启动在屏幕正中央-->
<Window.Resources>
<!--通过window的资源声明出来,添加资源,资源字典,通过索引检索,属性标签形式,添加字符串,用于标签扩展-->
<sys:String x:Key="stringHello">友谊商店欢迎您的到来
</sys:String>
</Window.Resources>
<Grid>
<!--ResourceKey=可不写-->
<TextBox Text="{StaticResource ResourceKey=stringHello}" TextAlignment="Center" VerticalAlignment="Top" Height="46" HorizontalAlignment="Center" Width="400" FontSize="30" Margin="0,21,0,0"/>
<TextBox x:Name="textBox1" TextAlignment="Center" VerticalAlignment="Top" Height="46" HorizontalAlignment="Center" Width="400" FontSize="30" Margin="0,109,0,0"/>
<TextBox Text="联系电话:88888888" TextAlignment="Center" VerticalAlignment="Top" Height="46" HorizontalAlignment="Center" Width="400" FontSize="20" Margin="0,515,0,0"/>
<Button Content="Show" Click="Button_Click" Margin="115,428,115,115"/>
</Grid>
</Window>
资源不但可以在XAML中访问,在C#中也可以访问,下面是Button.Click的事件处理器:
private void Button_Click(object sender, RoutedEventArgs e)
{
string str=this.FindResource("stringHello") as string;
this.textBox1.Text=str;
}
调用一个拥有Resources属性的对象的FindResource方法就可以在它的资源字典中检索资源,检索到资源后再把它回复成正确的数据类型,点击按钮后,可见第二个文本框显示出同样的字符串:
点击show按钮后
第二部分、商场收银系统
第一步、创建新项目
第二步、新建组件、创建类库——模块化
先删除自带的UserControl1.xaml,再新建一个
使用Canvas控件
Canvas控件可以自由对控件的位置进行安排,对Canvas的子元素应用HorizontalAlignment和VerticalAlignment属性不能改变这些元素的位置;可使用Margin属性来定位元素,但也可使用Canvas类公开的Canvas.Left、Canvas.Top、Canvas.Right和Canvas.Bottom附加属性(Top和Left属性的优先级高于Bottom和Right属性,例如,如果同时指定Top和Bottom属性,Bottom属性会被忽略掉)
UI完成后:使用的控件:Rectangle、Label、Button、TextBox、ListBox、ComboBox
MoneyCalculator.xaml代码如下:
<UserControl x:Class="ControlLibrary.MoneyCalculator"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="450" >
<Canvas>
<Canvas.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFCDB6E6" Offset="0"/>
<GradientStop Color="#FF611CAB" Offset="0.817"/>
</LinearGradientBrush>
</Canvas.Background>
<Rectangle Width="350" Height="400" Stroke="Transparent" Canvas.Left="25" Canvas.Top="25">
<!--Content 标签的内容,不是对象的内容-->
<Rectangle.Fill>
<!--这个也是标签,对象类型.对象属性名,不可以去掉"对象类型.",XAML编译器会声明对应类的实例,以为想声明Fill类的对象-->
<!--对象属性的内容-->
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<!--linear 线性 Gradient渐变 Brush笔刷,笔刷开始点相对值0,0左上角-->
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<!--集合-->
<GradientStop Offset="0.2" Color="BlueViolet"/>
<!--启动到终点之间连线20%-->
<GradientStop Offset="0.7" Color="DarkViolet"/>
<GradientStop Offset="1.0" Color="Purple"/>
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Label Content="单价:" Canvas.Left="40" Canvas.Top="33" HorizontalAlignment="Center" VerticalAlignment="Top"/>
<Label Content="数量:" Canvas.Left="40" Canvas.Top="67" HorizontalAlignment="Center" VerticalAlignment="Top"/>
<Label Content="优惠:" Canvas.Left="40" Canvas.Top="103" HorizontalAlignment="Center" VerticalAlignment="Top"/>
<Label Content="总计:" Canvas.Left="40" Canvas.Top="302" HorizontalAlignment="Center" VerticalAlignment="Top"/>
<Button x:Name="Set" Content="开始" Canvas.Left="258" Canvas.Top="53" HorizontalAlignment="Center" VerticalAlignment="Top" Width="68" Click="Set_Click"/>
<Button x:Name="Reset" Content="重置" Canvas.Left="258" Canvas.Top="84" HorizontalAlignment="Center" VerticalAlignment="Top" Width="68" Click="Reset_Click"/>
<TextBox x:Name="Price" Canvas.Left="102" TextWrapping="Wrap" Canvas.Top="38" Width="120" HorizontalAlignment="Center" VerticalAlignment="Top"/>
<TextBox x:Name="Number" Canvas.Left="102" TextWrapping="Wrap" Canvas.Top="72" Width="120" HorizontalAlignment="Center" VerticalAlignment="Top"/>
<ComboBox x:Name="Choose" Canvas.Left="102" Canvas.Top="105" Width="120" HorizontalAlignment="Center" VerticalAlignment="Top"/>
<ListBox x:Name="Detail" Height="143" Width="236" Canvas.Left="102" Canvas.Top="144" HorizontalAlignment="Center" VerticalAlignment="Top"/>
<TextBox x:Name="Total" Canvas.Left="102" TextWrapping="Wrap" Canvas.Top="306" Width="120" HorizontalAlignment="Center" VerticalAlignment="Top"/>
</Canvas>
</UserControl>
MoneyCalculator.xaml.cs页面代码如下:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ControlLibrary
{
/// <summary>
/// MoneyCalculator.xaml 的交互逻辑
/// </summary>
public partial class MoneyCalculator : UserControl
{
public MoneyCalculator()
{
InitializeComponent();
//在ComboBox中加下拉选项
Choose.Items.Add("正常收费");
Choose.Items.Add("满300返100");
Choose.Items.Add("打8折");
Choose.SelectedIndex = 0;
}
/// <summary>
/// Context上下文,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用
/// </summary>
class CashContext
{
//声明一个CashSuper对象(父类)
private CashSuper cs;
//通过构造方法,传入具体的收费策略(子类)
public CashContext(CashSuper csuper)
{
//初始化时,传入具体的策略对象
this.cs = csuper;
}
//上下文接口
//根据收费策略的不同,获得计算结果
//输入参数为单种产品的总原价(单价乘以个数)
public double GetResult(double money)
{
//根据具体的策略对象,调用其算法的方法
return cs.acceptCash(money);
}
}
/// <summary>
/// (父类)现金收取超类的抽象方法,收取现金,参数为原价,返回为当前价
/// 策略类Strategy,定义所有支持的算法的公共接口
/// </summary>
public abstract class CashSuper
{
public abstract double acceptCash(double money);
}
/// <summary>
/// 集合实现IDictionary接口(基类DictionaryBase)
/// 通过键访问索引符
/// </summary>
public class CashSupers : DictionaryBase
{
public void Add(string newID, CashSuper newCashSuper)
{
Dictionary.Add(newID, newCashSuper);
}
public void Remove(string cashSuperID)
{
Dictionary.Remove(cashSuperID);
}
public CashSupers()
{
}
public CashSuper this[string cashSuperID]
{
get
{
return (CashSuper)Dictionary[cashSuperID];
}
set
{
Dictionary[cashSuperID] = value;
}
}
}
/// <summary>
/// 正常收费子类
/// 具体策略类,封装了具体的算法或行为,继承于Strategy
/// </summary>
class CashNormal : CashSuper
{
/// <summary>
/// 正常收费,原价返回
/// </summary>
/// <param name="money"></param>
/// <returns></returns>
public override double acceptCash(double money)
{
return money;
}
}
/// <summary>
/// 打折收费子类
/// 打折收费,初始化时,必需要输入折扣率,如打八折,就是0.8
/// 具体策略类,封装了具体的算法或行为,继承于Strategy
/// </summary>
class CashRebate : CashSuper
{
private double moneyRebate = 1d;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="moneyRebate"></param>
public CashRebate(string moneyRebate)
{
this.moneyRebate = double.Parse(moneyRebate);
}
public override double acceptCash(double money)
{
return money * moneyRebate;
}
}
/// <summary>
/// 返利收费子类
/// 返利收费,初始化时必须要输入返利条件和返利值,比如满300反100,则moneyCondition为300,moneyReturn为100
/// 具体策略类,封装了具体的算法或行为,继承于Strategy
/// </summary>
class CashReturn : CashSuper
{
private double moneyCondition = 0.0d;
private double moneyReturn = 0.0d;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="moneyCondition"></param>
/// <param name="moneyReturn"></param>
public CashReturn(string moneyCondition, string moneyReturn)
{
this.moneyCondition = double.Parse(moneyCondition);
this.moneyReturn = double.Parse(moneyReturn);
}
public override double acceptCash(double money)
{
double result = money;
//若大于返利条件,则需要减去返利值
if (money >= moneyCondition)
{
result = money - Math.Floor(money / moneyCondition) * moneyReturn; //看符合多少次返利
}
return result;
}
}
/// <summary>
/// 声明一个double变量total来计算总计
/// </summary>
double total = 0.0d;
private void Set_Click(object sender, RoutedEventArgs e)
{
CashContext context = null;
CashSupers cashSuperList = new CashSupers();
cashSuperList.Add("正常收费", new CashNormal());
cashSuperList.Add("满300返100", new CashReturn("300", "100"));
cashSuperList.Add("打8折", new CashRebate("0.8"));
//利用策略模式根据下拉选择框,生成相应的对象,实例化策略类、某个子类
//实例化不同的策略,最终在调用context.GetResult();时,所获得的结果就不尽相同
context = new CashContext(cashSuperList[Choose.SelectedItem.ToString()]);
double totalPrices = 0d;
if (Price.Text == "" || Convert.ToDouble(Price.Text) == 0)
{
MessageBox.Show("请输入货物的单价");
}
else if (Number.Text == "" || Convert.ToDouble(Number.Text) == 0)
{
MessageBox.Show("请输入货物的数量");
}
else if (context != null)
{
totalPrices = context.GetResult(Convert.ToDouble(Price.Text) * Convert.ToDouble(Number.Text));
//将每个商品合计计入总计
total = total + totalPrices;
//在列表框中显示信息
//通过多台可以得到收取费用的结果
Detail.Items.Add("单价:" + Price.Text + "数量:" + Number.Text + "合计:" + totalPrices.ToString());
Total.Text = total.ToString(); //也可以写为 this.Total.Text = total.ToString();
}
}
private void Reset_Click(object sender, RoutedEventArgs e)
{
//清空单价和数量
Price.Text = "";
Number.Text = "";
//清空优惠选项
Choose.SelectedIndex = 0;
//清空明细列表
Detail.Items.Clear();
//清空总计数据
total = 0;
Total.Text = "";
}
}
}
第三步、主界面引用
上面代码创建的类库的命名空间和类名如下:
需要这界面所在工程引用类库
添加完成
在MainWindow.xaml中添加类库的命名空间
MainWindow.xaml代码如下:
<Window x:Class="ShopWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cl="clr-namespace:ControlLibrary;assembly=ControlLibrary"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:ShopWpf"
Title="商场收银系统" Height="600" Width="450" WindowStartupLocation="CenterScreen">
<!--local:因为ShopWpf命名空间包含在当前程序集中,一般将当前程序集包含的命名空间映射为local的名称空间-->
<!--启动在屏幕正中央-->
<Window.Resources>
<!--通过window的资源声明出来,添加资源,资源字典,通过索引检索,属性标签形式,添加字符串,用于标签扩展-->
<sys:String x:Key="stringHello">友谊商店欢迎您的到来
</sys:String>
<!--Staff对象作为Window资源声明出来-->
<local:Staff x:Key="staff" Name="Alice" Telephone="10000000" Familymember="Tom"/>
<!--Staff对象检索存在于命名空间中Key对象-->
<!--通过标签形式声明一个Staff对象-->
</Window.Resources>
<Grid>
<Path Data="M 0,0 L 0,65 L 65,0 Z" Stroke="Transparent" Fill="HotPink"/>
<!--ResourceKey=可不写-->
<TextBlock Text="{StaticResource ResourceKey=stringHello}" TextAlignment="Center" VerticalAlignment="Top" Height="46" HorizontalAlignment="Center" Width="400" FontSize="30" Margin="0,21,0,0"/>
<TextBlock Text="联系电话:88888888" TextAlignment="Center" VerticalAlignment="Top" Height="46" HorizontalAlignment="Center" Width="400" FontSize="20" Margin="0,515,0,0"/>
<cl:MoneyCalculator x:Name="Calculator" Margin="25,65,25,70"/>
<Button Content="登录" HorizontalAlignment="Left" VerticalAlignment="Top" Height="46" Background="Transparent" BorderBrush="Transparent" RenderTransformOrigin="0.5,0.5" Margin="-28,-7,0,0" Width="88" Click="Button_Click">
<Button.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-45"/>
<TranslateTransform/>
</TransformGroup>
</Button.RenderTransform>
</Button>
</Grid>
</Window>
MainWindow.xaml.cs页面代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ShopWpf
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//先把Window资源检索出来,窗体自己的方法FindResource,把字典给方法,返回类型为object,要转换为Staff
Staff staff = this.FindResource("staff") as Staff;
if (staff != null)
{
MessageBox.Show("当前员工姓名:"+ staff.Name + "\n" +
"员工号码:" + staff.Telephone + "\n" +
"员工家庭成员:" + staff.Familymember.Name); //staff的Name属性本身就是字符串类型
}
}
}
//NameToStaffTypeConverter类以特性形式附加到Staff类上去
[TypeConverterAttribute(typeof(NameToStaffTypeConverter))]
public class Staff
{
public string Name { get; set; }
public string Telephone { get; set; }
public Staff Familymember { get; set; } //职员的家庭成员也有名字和电话号码
}
public class NameToStaffTypeConverter : TypeConverter //定义TypeConverter的派生类
{ //给出staff中的Familymember一个字符串就可以基于这个字符串就可以声明一个Staff的对象并且把这个字符串赋值给Name属性
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) //重写方法
{
string name = value.ToString();
Staff familymember = new Staff();
familymember.Name = name;
return familymember;
}
}
}
生成的UI: