扯面工程师,配菜工程师,门迎工程师,当今世界工程师可真多啊。
今天我们把系统参数管理模块翻译成Silverlight项目。首先请看两张图
再看看翻译好的图
其实我们看到了第二张图用到了treeVIEw,Popup,这节主要讲的还是MVVM,不过和以往有所不同。先看看前台代码
<controls:ChilDWindow x:Class="MISInfoManage.CodeManageVIEw" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/Expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:toolkit="clr-namespace:System.windows.Controls;assembly=System.windows.Controls" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:resource="clr-namespace:MISInfoManage.Resources" xmlns:controls="clr-namespace:System.windows.Controls;assembly=System.windows.Controls" xmlns:Primitives="clr-namespace:System.windows.Controls.Primitives;assembly=System.windows" mc:Ignorable="d" WIDth="700" Height="400" FontSize="13" Title="系统参数管理"> <controls:ChilDWindow.Resources> <resource:CodeManageResource x:Key="CodeManageResource"/> <Style x:Key="ColumnheaderStyle" targettype="sdk:DataGrIDColumnheader"> <Setter Property="Height" Value="25"></Setter> </Style> </controls:ChilDWindow.Resources> <GrID x:name="LayoutRoot" Background="White"> <GrID.RowDeFinitions> <RowDeFinition Height="*"></RowDeFinition> </GrID.RowDeFinitions> <GrID.ColumnDeFinitions> <ColumnDeFinition WIDth="auto"></ColumnDeFinition> <ColumnDeFinition WIDth="*"></ColumnDeFinition> <ColumnDeFinition WIDth="0"></ColumnDeFinition> </GrID.ColumnDeFinitions> <border borderBrush="AliceBlue" WIDth="150" GrID.Row="0" GrID.Column="0" borderThickness="1" CornerRadius="2" margin="0,10,0"> <toolkit:TreeVIEw x:name="treeVIEwCode"></toolkit:TreeVIEw> </border> <sdk:DataGrID GrID.Row="0" GrID.Column="1" borderBrush="Black" borderThickness="1" IsReadonly="True" x:name="dgCodeList" autoGenerateColumns="False" AlternatingRowBackground="Gray" CanUserReorderColumns="True" VerticalScrollbarVisibility="auto" HorizontalScrollbarVisibility="auto" SelectionMode="Single" SelectedItem="{Binding CodeEntity,Mode=TwoWay}" ItemsSource="{Binding CodeList,Mode=OneWay}" CanUserSortColumns="True"> <sdk:DataGrID.Columns> <sdk:DataGrIDTemplateColumn header="选择"> <sdk:DataGrIDTemplateColumn.CellTemplate> <DataTemplate> <CheckBox HorizontalAlignment="Center"></CheckBox> </DataTemplate> </sdk:DataGrIDTemplateColumn.CellTemplate> </sdk:DataGrIDTemplateColumn> <sdk:DataGrIDTextColumn Binding="{Binding data,Mode=OneWay}" headerStyle="{StaticResource ColumnheaderStyle}" header="数据值"/> <sdk:DataGrIDTextColumn Binding="{Binding ename,Mode=OneWay}" headerStyle="{StaticResource ColumnheaderStyle}" header="英文代码"/> <sdk:DataGrIDTextColumn Binding="{Binding cname,Mode=OneWay}" headerStyle="{StaticResource ColumnheaderStyle}" header="中文代码"/> <sdk:DataGrIDTextColumn Binding="{Binding display_content,Mode=OneWay}" headerStyle="{StaticResource ColumnheaderStyle}" header="显示值"/> <sdk:DataGrIDTemplateColumn header=" *** 作"> <sdk:DataGrIDTemplateColumn.CellTemplate> <DataTemplate> <StackPanel> <StackPanel.Resources> <Style x:Key="buttonStyle" targettype="button"> <Setter Property="Template"> <Setter.Value> <ControlTemplate targettype="button"> <border CornerRadius="2" borderThickness="1" borderBrush="Red"> <StackPanel OrIEntation="Horizontal" Background="Turquoise"> <StackPanel.Effect> <DropShadowEffect color="Black" Direction="270" ShadowDepth="5" BlurRadius="5" Opacity="0.5"> </DropShadowEffect> </StackPanel.Effect> <Image Source="/MISInfoManage;component/Images/drag.png" Height="25" WIDth="60"/> <TextBlock Text="修改" Foreground="brown" FontWeight="Bold"></TextBlock> </StackPanel> </border> </ControlTemplate> </Setter.Value> </Setter> </Style> </StackPanel.Resources> <button Content="button1" Style="{StaticResource buttonStyle}"/> </StackPanel> </DataTemplate> </sdk:DataGrIDTemplateColumn.CellTemplate> </sdk:DataGrIDTemplateColumn> </sdk:DataGrID.Columns> </sdk:DataGrID> <Primitives:Popup x:name="CodeInfoPop" GrID.Row="0" GrID.Column="2"> <StackPanel WIDth="200"> <StackPanel.Style> <Style targettype="StackPanel"> <Setter Property="Background" Value="brown"></Setter> </Style> </StackPanel.Style> <StackPanel.Effect> <DropShadowEffect color="Black" Direction="300" ShadowDepth="10" BlurRadius="5" Opacity="0.6"> </DropShadowEffect> </StackPanel.Effect> <StackPanel OrIEntation="Horizontal"> <TextBlock Text="{Binding Tb_Ename,Source={StaticResource CodeManageResource}}"/> <TextBlock Text="{Binding CodeEntity.ename}" margin="5,0"/> </StackPanel> <StackPanel OrIEntation="Horizontal"> <TextBlock Text="{Binding Tb_CNm,Source={StaticResource CodeManageResource}}"/> <TextBlock Text="{Binding CodeEntity.cname}" margin="5,0"/> </StackPanel> <StackPanel OrIEntation="Horizontal"> <TextBlock Text="{Binding Tb_display,Source={StaticResource CodeManageResource}}"/> <TextBlock Text="{Binding CodeEntity.display_content}" margin="5,0"/> </StackPanel> </StackPanel> </Primitives:Popup> </GrID> </controls:ChilDWindow>
最普遍的布局方式GrID+StackPanel。记得上次好像我在写博客的时候,给每个控件都设置了FontSize,其实这个是没有必要的,只需要在controls:ChilDWindow节点中设置,那么整个页面的控件的FontSize都起作用。再往下看,有这样的一些节点
<Style x:Key="buttonStyle" targettype="button">...</Style>里面有这么一段代码
<ControlTemplate targettype="button"> <border CornerRadius="2" borderThickness="1" borderBrush="Red"> <StackPanel OrIEntation="Horizontal" Background="Turquoise"> <StackPanel.Effect> <DropShadowEffect color="Black" Direction="270" ShadowDepth="5" BlurRadius="5" Opacity="0.5"> </DropShadowEffect> </StackPanel.Effect> <Image Source="/MISInfoManage;component/Images/drag.png" Height="25" WIDth="60"/> <TextBlock Text="修改" Foreground="brown" FontWeight="Bold"></TextBlock> </StackPanel> </border> </ControlTemplate>
这个是定义一个button的控件模版。在这里我们给StackPanel定义了一个特效DropShadowEffect ,一个阴影效果。在这个模板中我放置了一个图片和一个文本,大家看看上面的图就知道了。整个一按钮变成如此摸样,所以在我们做开发的时候,可以通过设置ControlTemplate来定制我们按钮或者其他控件的模版。在按钮中,我们只需要设置Style="{StaticResource buttonStyle}"即可。再往下走,有这么一段代码
<Primitives:Popup x:name="CodeInfoPop" GrID.Row="0" GrID.Column="2">这个节点正是定义我们的Popup,当DataGrID的SelectionChanged触发时,d出Popup。注意Popup这里需要引用System.windows.Controls.Primitives。好了前台没什么,就这么些。我们看看页面后台,代码如下
namespace MISInfoManage { public partial class CodeManageVIEw : ChilDWindow { CodeManageModel codeManage; public CodeManageVIEw() { InitializeComponent(); codeManage = new CodeManageModel(this); this.LayoutRoot.DataContext = codeManage; } } }
我勒了个去,怎么就这么点代码,我告诉你,就这么点代码。我们这次使用了Behavior,那么就不会出现页面后台事件。看看viewmodel到底都干了些什么。
namespace MISInfoManage.viewmodels { public class CodeManageModel : INotifyPropertyChanged { public ChilDWindow userControl; CodeManageServiceClIEnt clIEnt; SelectionChangedBehavior mouseRightbuttonBrhavior; public CodeManageModel() { clIEnt = new CodeManageServiceClIEnt(); this.GetCodesList((obj, args) => { this.CodesList = args.Result; this.BuildTree(); }); } public CodeManageModel(ChilDWindow userControl) : this() { this.userControl = userControl; this.mouseRightbuttonBrhavior = new SelectionChangedBehavior(this); mouseRightbuttonBrhavior.Attach((userControl as CodeManageVIEw).dgCodeList); this.SetContextMenu(); } private List<Codes> codesList; public List<Codes> CodesList { get { return codesList; } set { codesList = value; NotifyPropertyChange("CodesList"); } } private List<Codes> codeList; public List<Codes> CodeList { get { return codeList; } set { codeList = value; NotifyPropertyChange("CodeList"); } } private Codes codeEntity; public Codes CodeEntity { set { codeEntity = value; NotifyPropertyChange("CodeEntity"); } get { return codeEntity; } } public voID GetCodesList(EventHandler<GetCodeListCompletedEventArgs> handler) { clIEnt.GetCodeListCompleted += handler; clIEnt.GetCodeListAsync(); } public voID GetCodeListByCondition(string ename, EventHandler<GetCodeListByConditionCompletedEventArgs> handler) { clIEnt.GetCodeListByConditionCompleted += handler; clIEnt.GetCodeListByConditionAsync(ename); } public voID BuildTree() { TreeVIEwItem mainitem = new TreeVIEwItem(); mainitem.header = "系统参数"; mainitem.IsExpanded = true; List<Codes> codeList = null; if (this.CodesList != null && this.CodesList.Count > 0) { codeList = this.CodesList.distinct<Codes>(new EqualityCompare()).ToList(); codeList.ForEach(c => { TreeVIEwItem treeVIEwItem = new TreeVIEwItem(); StackPanel stackPanel = new StackPanel(); stackPanel.OrIEntation = OrIEntation.Horizontal; TextBlock textBlock = new TextBlock(); textBlock.Text = c.cname; textBlock.Tag = c.ename; textBlock.MouseleftbuttonDown += this.LoadCodeByID; Image image = new Image(); image.WIDth = 12; image.Height = 12; image.margin = new Thickness(0, 0, 5, 0); image.source = new BitmAPImage(new Uri("../Images/windows.jpg", UriKind.relative)); stackPanel.Children.Add(image); stackPanel.Children.Add(textBlock); treeVIEwItem.header = stackPanel; mainitem.Items.Add(treeVIEwItem); }); (this.userControl as CodeManageVIEw).treeVIEwCode.Items.Add(mainitem); } } private voID LoadCodeByID(object sender, MousebuttonEventArgs e) { TextBlock textBlock = sender as TextBlock; string ename = textBlock.Tag.ToString(); this.GetCodeListByCondition(ename, (obj, args) => { this.CodeList = args.Result; }); } private voID SetContextMenu() { ContextMenu contextMenu = new ContextMenu(); MenuItem menuItem = new MenuItem(); menuItem.Tag = "Modify"; TextBlock textBlock = new TextBlock(); textBlock.Text = "修改"; menuItem.header = textBlock; contextMenu.Items.Add(menuItem); menuItem = new MenuItem(); textBlock = new TextBlock(); textBlock.Text = "添加"; menuItem.Tag = "Add"; menuItem.header = textBlock; contextMenu.Items.Add(menuItem); menuItem = new MenuItem(); textBlock = new TextBlock(); textBlock.Text = "关闭"; menuItem.Tag = "Close"; menuItem.header = textBlock; menuItem.Click += delegate(object sender, RoutedEventArgs e) { (userControl as CodeManageVIEw).Close(); }; contextMenu.Items.Add(menuItem); ContextMenuService.SetContextMenu((this.userControl as CodeManageVIEw).dgCodeList, contextMenu); } public event PropertyChangedEventHandler PropertyChanged; private voID NotifyPropertyChange(string property) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(property)); } } } public class EqualityCompare : IEqualityComparer<Codes> { public bool Equals(Codes code1, Codes code2) { return code1.ename.Equals(code2.ename); } public int GetHashCode(Codes code) { return code.ename.GetHashCode(); } } }
首先进入构造函数,初始化我们的TreeVIEw,初始化TreeVIEw的时候有这么个代码codeList = this.CodesList.distinct<Codes>(new EqualityCompare()).ToList();去除List<T>重复。我们知道对象的值都一样,不代表对象一样。所以我们需要实现IEqualityComparer<T>接口,Equals方法确定你要distinct的规则,在这里就是Ename不相等。GetHashCode必须返回Ename的HashCode。再往下走,这么一段代码
this.mouseRightbuttonBrhavior = new SelectionChangedBehavior(this); mouseRightbuttonBrhavior.Attach((userControl as CodeManageVIEw).dgCodeList);
在这里使用到了Behavior,我们为DataGrID定义了一个行为,我们来看看这个行为
namespace MISInfoManage.Behavior { public class SelectionChangedBehavior : Behavior<DataGrID> { CodeManageModel _codeManageModel; public SelectionChangedBehavior():base() {} public SelectionChangedBehavior(CodeManageModel codeManageModel) : this() { _codeManageModel = codeManageModel; } protected overrIDe voID OnAttached() { base.OnAttached(); this.Associatedobject.SelectionChanged += Associatedobject_SelectionChanged; this.Associatedobject.MouseMove += Associatedobject_MouseMove; } protected overrIDe voID OnDetaching() { base.OnDetaching(); this.Associatedobject.SelectionChanged -= Associatedobject_SelectionChanged; this.Associatedobject.MouseMove -= Associatedobject_MouseMove; } private voID Associatedobject_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (_codeManageModel.CodeEntity != null) { Popup popup = (this._codeManageModel.userControl as CodeManageVIEw).CodeInfoPop; popup.HorizontalOffset = 20; popup.VerticalOffset = 70; popup.IsOpen = true; } } private voID Associatedobject_MouseMove(object sender,MouseEventArgs e) { Popup popup = (this._codeManageModel.userControl as CodeManageVIEw).CodeInfoPop; popup.IsOpen = false; } } }
在这里我只说一个基类,其他的就不往出贴了,大家自己看
namespace System.windows.Interactivity { // Summary: // Encapsulates state information and zero or more ICommands into an attachable // object. // // Type parameters: // T: // The type the System.windows.Interactivity.Behavior<T> can be attached to. // // Remarks: // Behavior is the base class for provIDing attachable state and commands to // an object. The types the Behavior can be attached to can be controlled by // the generic parameter. OverrIDe OnAttached() and OnDetaching() methods to // hook and unhook any necessary handlers from the Associatedobject. public abstract class Behavior<T> : Behavior where T : System.windows.DependencyObject { // Summary: // Initializes a new instance of the System.windows.Interactivity.Behavior<T> // class. protected Behavior(); // Summary: // Gets the object to which this System.windows.Interactivity.Behavior<T> is // attached. protected T Associatedobject { get; } } }
这里的的Associatedobject就是泛型T,并且它是System.windows.DependencyObject类型的。Behavior类是个抽象类,具有Attach,Detach,OnAttached,OnDetaching方法。OnAttached在Attach方法调用以后生效。所以这段代码就实现了DataGrID的SelectionChanged和MouseMove事件,在SelectionChanged以后d出Popup,MouseMove以后隐藏Popup。这种方式是不是很有效的实现了页面UI和逻辑的分离。再往下走,有个SetContextMenu方法,正是给DataGrID附加一个d出菜单。在菜单构造好以后,需要调用ContextMenuService.SetContextMenu((this.userControl as CodeManageVIEw).dgCodeList,contextMenu);,第一个参数是一个DependencyObject类型的对象,第二个是ContextMenu对象。类似于这样的内置对象还有FocusManager,它的方法FocusManager.GetFocusedElement()可以直接找到页面获得焦点的元素。我们来看看这个菜单的效果,
当我们点击关闭的时候,将会关闭该页面。OK,今天就讲到这里,时间也不早了,洗洗睡。
总结以上是内存溢出为你收集整理的Silverlight MVVM 贴近实战(六)全部内容,希望文章能够帮你解决Silverlight MVVM 贴近实战(六)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)