微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Silverlight MVVM 贴近实战(六)

扯面工程师,配菜工程师,门迎工程师,当今世界工程师可真多啊。

今天我们把系统参数管理模块翻译成Silverlight项目。首先请看两张图

再看看翻译好的图

其实我们看到了第二张图用到了treeView,Popup,这节主要讲的还是MVVM,不过和以往有所不同。先看看前台代码

 
 
  1. <controls:ChildWindow x:Class="MISInfoManage.CodeManageView" 
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  4.     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
  5.     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  6.     xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" 
  7.     xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
  8.     xmlns:resource="clr-namespace:MISInfoManage.Resources" 
  9.     xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" 
  10.     xmlns:Primitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows" 
  11.     mc:Ignorable="d" Width="700" Height="400" FontSize="13" 
  12.     Title="系统参数管理"> 
  13.     <controls:ChildWindow.Resources> 
  14.         <resource:CodeManageResource x:Key="CodeManageResource"/> 
  15.         <Style x:Key="ColumnHeaderStyle" targettype="sdk:DataGridColumnHeader"> 
  16.             <Setter Property="Height" Value="25"></Setter> 
  17.         </Style> 
  18.     </controls:ChildWindow.Resources> 
  19.     <Grid x:Name="LayoutRoot" Background="White"> 
  20.         <Grid.RowDeFinitions> 
  21.             <RowDeFinition Height="*"></RowDeFinition> 
  22.         </Grid.RowDeFinitions> 
  23.         <Grid.ColumnDeFinitions> 
  24.             <ColumnDeFinition Width="Auto"></ColumnDeFinition> 
  25.             <ColumnDeFinition Width="*"></ColumnDeFinition> 
  26.             <ColumnDeFinition Width="0"></ColumnDeFinition> 
  27.         </Grid.ColumnDeFinitions> 
  28.         <Border BorderBrush="AliceBlue" Width="150" Grid.Row="0" Grid.Column="0" BorderThickness="1" CornerRadius="2" Margin="0,10,0"> 
  29.             <toolkit:TreeView x:Name="treeViewCode"></toolkit:TreeView> 
  30.         </Border> 
  31.         <sdk:DataGrid Grid.Row="0" Grid.Column="1" 
  32.                           BorderBrush="Black" BorderThickness="1" 
  33.                           IsReadOnly="True" x:Name="dgCodeList" 
  34.                           AutoGenerateColumns="False" 
  35.                           AlternatingRowBackground="Gray" 
  36.                           CanUserReorderColumns="True" 
  37.                           VerticalScrollBarVisibility="Auto" 
  38.                           HorizontalScrollBarVisibility="Auto"   
  39.                           SelectionMode="Single" 
  40.                           SelectedItem="{Binding CodeEntity,Mode=TwoWay}" 
  41.                           ItemsSource="{Binding CodeList,Mode=OneWay}" 
  42.                           CanUserSortColumns="True"> 
  43.             <sdk:DataGrid.Columns> 
  44.                 <sdk:DataGridTemplateColumn Header="选择"> 
  45.                     <sdk:DataGridTemplateColumn.CellTemplate> 
  46.                         <DataTemplate> 
  47.                             <CheckBox HorizontalAlignment="Center"></CheckBox> 
  48.                         </DataTemplate> 
  49.                     </sdk:DataGridTemplateColumn.CellTemplate> 
  50.                 </sdk:DataGridTemplateColumn> 
  51.                 <sdk:DataGridTextColumn Binding="{Binding data,Mode=OneWay}" HeaderStyle="{StaticResource ColumnHeaderStyle}" Header="数据值"/> 
  52.                 <sdk:DataGridTextColumn Binding="{Binding ename,Mode=OneWay}" HeaderStyle="{StaticResource ColumnHeaderStyle}" Header="英文代码"/> 
  53.                 <sdk:DataGridTextColumn Binding="{Binding cname,Mode=OneWay}" HeaderStyle="{StaticResource ColumnHeaderStyle}" Header="中文代码"/> 
  54.                 <sdk:DataGridTextColumn Binding="{Binding display_content,Mode=OneWay}" HeaderStyle="{StaticResource ColumnHeaderStyle}" Header="显示值"/> 
  55.                 <sdk:DataGridTemplateColumn Header="操作"> 
  56.                     <sdk:DataGridTemplateColumn.CellTemplate> 
  57.                         <DataTemplate> 
  58.                             <StackPanel> 
  59.                                 <StackPanel.Resources> 
  60.                                     <Style x:Key="buttonStyle" targettype="Button"> 
  61.                                         <Setter Property="Template"> 
  62.                                             <Setter.Value> 
  63.                                                 <ControlTemplate targettype="Button"> 
  64.                                                     <Border CornerRadius="2" BorderThickness="1" BorderBrush="Red"> 
  65.                                                         <StackPanel Orientation="Horizontal" Background="Turquoise"> 
  66.                                                             <StackPanel.Effect> 
  67.                                                                 <DropShadowEffect Color="Black" Direction="270" ShadowDepth="5"   
  68.                                                                     BlurRadius="5" Opacity="0.5"> 
  69.                                                                 </DropShadowEffect> 
  70.                                                             </StackPanel.Effect> 
  71.                                                             <Image Source="/MISInfoManage;component/Images/drag.png" Height="25" Width="60"/> 
  72.                                                             <TextBlock Text="修改" Foreground="brown" FontWeight="Bold"></TextBlock> 
  73.                                                         </StackPanel> 
  74.                                                     </Border> 
  75.                                                 </ControlTemplate> 
  76.                                             </Setter.Value> 
  77.                                         </Setter> 
  78.                                     </Style> 
  79.                                 </StackPanel.Resources> 
  80.                                 <Button Content="Button1"  Style="{StaticResource buttonStyle}"/> 
  81.                             </StackPanel> 
  82.                         </DataTemplate> 
  83.                     </sdk:DataGridTemplateColumn.CellTemplate> 
  84.                 </sdk:DataGridTemplateColumn> 
  85.             </sdk:DataGrid.Columns> 
  86.         </sdk:DataGrid> 
  87.         <Primitives:Popup x:Name="CodeInfoPop" Grid.Row="0" Grid.Column="2"> 
  88.             <StackPanel Width="200"> 
  89.                 <StackPanel.Style> 
  90.                     <Style targettype="StackPanel"> 
  91.                         <Setter Property="Background" Value="brown"></Setter> 
  92.                     </Style> 
  93.                 </StackPanel.Style> 
  94.                 <StackPanel.Effect> 
  95.                     <DropShadowEffect 
  96.                     Color="Black" Direction="300" ShadowDepth="10" BlurRadius="5" Opacity="0.6"> 
  97.                     </DropShadowEffect> 
  98.                 </StackPanel.Effect> 
  99.                 <StackPanel Orientation="Horizontal"> 
  100.                     <TextBlock Text="{Binding Tb_Ename,Source={StaticResource CodeManageResource}}"/> 
  101.                     <TextBlock Text="{Binding CodeEntity.ename}" Margin="5,0"/> 
  102.                 </StackPanel> 
  103.                 <StackPanel Orientation="Horizontal"> 
  104.                     <TextBlock Text="{Binding Tb_CNm,Source={StaticResource CodeManageResource}}"/> 
  105.                     <TextBlock Text="{Binding CodeEntity.cname}" Margin="5,0"/> 
  106.                 </StackPanel> 
  107.                 <StackPanel Orientation="Horizontal"> 
  108.                     <TextBlock Text="{Binding Tb_display,Source={StaticResource CodeManageResource}}"/> 
  109.                     <TextBlock Text="{Binding CodeEntity.display_content}" Margin="5,0"/> 
  110.                 </StackPanel> 
  111.             </StackPanel> 
  112.         </Primitives:Popup> 
  113.     </Grid> 
  114. </controls:ChildWindow> 

最普遍的布局方式Grid+StackPanel。记得上次好像我在写博客的时候,给每个控件都设置了FontSize,其实这个是没有必要的,只需要在controls:ChildWindow节点中设置,那么整个页面的控件的FontSize都起作用。再往下看,有这样的一些节点

<Style x:Key="buttonStyle" targettype="Button">...</Style>里面有这么一段代码

 
 
  1. <ControlTemplate targettype="Button"> 
  2.                                                     <Border CornerRadius="2" BorderThickness="1" BorderBrush="Red"> 
  3.                                                         <StackPanel Orientation="Horizontal" Background="Turquoise"> 
  4.                                                             <StackPanel.Effect> 
  5.                                                                 <DropShadowEffect Color="Black" Direction="270" ShadowDepth="5"   
  6.                                                                     BlurRadius="5" Opacity="0.5"> 
  7.                                                                 </DropShadowEffect> 
  8.                                                             </StackPanel.Effect> 
  9.                                                             <Image Source="/MISInfoManage;component/Images/drag.png" Height="25" Width="60"/> 
  10.                                                             <TextBlock Text="修改" Foreground="brown" FontWeight="Bold"></TextBlock> 
  11.                                                         </StackPanel> 
  12.                                                     </Border> 
  13.                                                 </ControlTemplate> 

这个是定义一个Button的控件模版。在这里我们给StackPanel定义了一个特效DropShadowEffect 一个阴影效果在这个模板中我放置了一个图片一个文本,大家看看上面的图就知道了。整个一按钮变成如此摸样,所以在我们做开发的时候,可以通过设置ControlTemplate来定制我们按钮或者其他控件的模版。在按钮中,我们只需要设置Style="{StaticResource buttonStyle}"即可。再往下走,有这么一段代码

<Primitives:Popup x:Name="CodeInfoPop" Grid.Row="0" Grid.Column="2">这个节点正是定义我们的Popup,当DataGrid的SelectionChanged触发时,弹出Popup。注意Popup这里需要引用System.Windows.Controls.Primitives。好了前台没什么,就这么些。我们看看页面后台代码如下

 
 
  1. namespace MISInfoManage  
  2. {  
  3.     public partial class CodeManageView : ChildWindow  
  4.     {  
  5.         CodeManageModel codeManage;  
  6.         public CodeManageView()  
  7.         {  
  8.             InitializeComponent();  
  9.             codeManage = new CodeManageModel(this);  
  10.             this.LayoutRoot.DataContext = codeManage;  
  11.         }  
  12.     }  

我勒了个去,怎么就这么点代码,我告诉你,就这么点代码。我们这次使用了Behavior,那么就不会出现页面后台事件。看看viewmodel到底都干了些什么。

 
 
  1. namespace MISInfoManage.viewmodels  
  2. {  
  3.     public class CodeManageModel : INotifyPropertyChanged  
  4.     {  
  5.         public ChildWindow userControl;  
  6.         CodeManageServiceClient client;  
  7.         SelectionChangedBehavior mouseRightButtonBrhavior;  
  8.         public CodeManageModel()  
  9.         {  
  10.             client = new CodeManageServiceClient();  
  11.             this.GetCodesList((obj, args) =>  
  12.             {  
  13.                 this.CodesList = args.Result;  
  14.                 this.BuildTree();  
  15.             });  
  16.         }  
  17.  
  18.         public CodeManageModel(ChildWindow userControl)  
  19.             : this()  
  20.         {  
  21.             this.userControl = userControl;  
  22.             this.mouseRightButtonBrhavior = new SelectionChangedBehavior(this);  
  23.             mouseRightButtonBrhavior.Attach((userControl as CodeManageView).dgCodeList);  
  24.             this.SetContextMenu();  
  25.         }  
  26.  
  27.         private List<Codes> codesList;  
  28.         public List<Codes> CodesList  
  29.         {  
  30.             get 
  31.             {  
  32.                 return codesList;  
  33.             }  
  34.             set 
  35.             {  
  36.                 codesList = value;  
  37.                 NotifyPropertyChange("CodesList");  
  38.             }  
  39.         }  
  40.  
  41.         private List<Codes> codeList;  
  42.         public List<Codes> CodeList  
  43.         {  
  44.             get 
  45.             {  
  46.                 return codeList;  
  47.             }  
  48.             set 
  49.             {  
  50.                 codeList = value;  
  51.                 NotifyPropertyChange("CodeList");  
  52.             }  
  53.         }  
  54.  
  55.         private Codes codeEntity;  
  56.         public Codes CodeEntity  
  57.         {  
  58.             set 
  59.             {  
  60.                 codeEntity = value;  
  61.                 NotifyPropertyChange("CodeEntity");  
  62.             }  
  63.             get 
  64.             {  
  65.                 return codeEntity;  
  66.             }  
  67.         }  
  68.  
  69.         public void GetCodesList(EventHandler<GetCodeListCompletedEventArgs> handler)  
  70.         {  
  71.             client.GetCodeListCompleted += handler;  
  72.             client.GetCodeListAsync();  
  73.         }  
  74.  
  75.         public void GetCodeListByCondition(string ename, EventHandler<GetCodeListByConditionCompletedEventArgs> handler)  
  76.         {  
  77.             client.GetCodeListByConditionCompleted += handler;  
  78.             client.GetCodeListByConditionAsync(ename);  
  79.         }  
  80.  
  81.         public void BuildTree()  
  82.         {  
  83.             TreeViewItem mainitem = new TreeViewItem();  
  84.             mainitem.Header = "系统参数";  
  85.             mainitem.IsExpanded = true;  
  86.             List<Codes> codeList = null;  
  87.             if (this.CodesList != null && this.CodesList.Count > 0)  
  88.             {  
  89.                 codeList = this.CodesList.distinct<Codes>(new EqualityCompare()).ToList();  
  90.                 codeList.ForEach(c =>  
  91.                 {  
  92.                     TreeViewItem treeViewItem = new TreeViewItem();  
  93.                     StackPanel stackPanel = new StackPanel();  
  94.                     stackPanel.Orientation = Orientation.Horizontal;  
  95.                     TextBlock textBlock = new TextBlock();  
  96.                     textBlock.Text = c.cname;  
  97.                     textBlock.Tag = c.ename;  
  98.                     textBlock.MouseLeftButtonDown += this.LoadCodeByID;  
  99.                     Image image = new Image();  
  100.                     image.Width = 12;  
  101.                     image.Height = 12;  
  102.                     image.Margin = new Thickness(0, 0, 5, 0);  
  103.                     image.source = new BitmapImage(new Uri("../Images/Windows.jpg", UriKind.Relative));  
  104.                     stackPanel.Children.Add(image);  
  105.                     stackPanel.Children.Add(textBlock);  
  106.                     treeViewItem.Header = stackPanel;  
  107.                     mainitem.Items.Add(treeViewItem);  
  108.                 });  
  109.                 (this.userControl as CodeManageView).treeViewCode.Items.Add(mainitem);  
  110.             }  
  111.         }  
  112.  
  113.         private void LoadCodeByID(object sender, MouseButtonEventArgs e)  
  114.         {  
  115.             TextBlock textBlock = sender as TextBlock;  
  116.             string ename = textBlock.Tag.ToString();  
  117.             this.GetCodeListByCondition(ename, (obj, args) =>  
  118.             {  
  119.                 this.CodeList = args.Result;  
  120.             });  
  121.         }  
  122.  
  123.         private void SetContextMenu()  
  124.         {  
  125.             ContextMenu contextMenu = new ContextMenu();  
  126.             MenuItem menuItem = new MenuItem();  
  127.             menuItem.Tag = "Modify";  
  128.             TextBlock textBlock = new TextBlock();  
  129.             textBlock.Text = "修改";  
  130.             menuItem.Header = textBlock;  
  131.             contextMenu.Items.Add(menuItem);  
  132.             menuItem = new MenuItem();  
  133.             textBlock = new TextBlock();  
  134.             textBlock.Text = "添加";  
  135.             menuItem.Tag = "Add";  
  136.             menuItem.Header = textBlock;  
  137.             contextMenu.Items.Add(menuItem);  
  138.             menuItem = new MenuItem();  
  139.             textBlock = new TextBlock();  
  140.             textBlock.Text = "关闭";  
  141.             menuItem.Tag = "Close";  
  142.             menuItem.Header = textBlock;  
  143.             menuItem.Click += delegate(object sender, RoutedEventArgs e)  
  144.             {  
  145.                 (userControl as CodeManageView).Close();  
  146.             };  
  147.             contextMenu.Items.Add(menuItem);  
  148.             ContextMenuService.SetContextMenu((this.userControl as CodeManageView).dgCodeList, contextMenu);  
  149.         }  
  150.  
  151.         public event PropertyChangedEventHandler PropertyChanged;  
  152.         private void NotifyPropertyChange(string property)  
  153.         {  
  154.             if (PropertyChanged != null)  
  155.             {  
  156.                 PropertyChanged(thisnew PropertyChangedEventArgs(property));  
  157.             }  
  158.         }  
  159.     }  
  160.  
  161.     public class EqualityCompare : IEqualityComparer<Codes>  
  162.     {  
  163.         public bool Equals(Codes code1, Codes code2)  
  164.         {  
  165.             return code1.ename.Equals(code2.ename);  
  166.         }  
  167.  
  168.         public int GetHashCode(Codes code)  
  169.         {  
  170.             return code.ename.GetHashCode();  
  171.         }  
  172.     }  

首先进入构造函数,初始化我们的TreeView,初始化TreeView的时候有这么个代码codeList = this.CodesList.distinct<Codes>(new EqualityCompare()).ToList();去除List<T>重复。我们知道对象的值都一样,不代表对象一样。所以我们需要实现IEqualityComparer<T>接口,Equals方法确定你要distinct的规则,在这里就是Ename不相等。GetHashCode必须返回Ename的HashCode。再往下走,这么一段代码

 
 
  1. this.mouseRightButtonBrhavior = new SelectionChangedBehavior(this);  
  2.             mouseRightButtonBrhavior.Attach((userControl as CodeManageView).dgCodeList); 

在这里使用到了Behavior,我们为DataGrid定义了一个行为,我们来看看这个行为

 
 
  1. namespace MISInfoManage.Behavior  
  2. {  
  3.     public class SelectionChangedBehavior : Behavior<DataGrid>  
  4.     {  
  5.         CodeManageModel _codeManageModel;  
  6.         public SelectionChangedBehavior():base()  
  7.         {}  
  8.         public SelectionChangedBehavior(CodeManageModel codeManageModel)  
  9.             : this()  
  10.         {  
  11.             _codeManageModel = codeManageModel;  
  12.         }  
  13.         protected override void OnAttached()  
  14.         {  
  15.             base.OnAttached();  
  16.             this.Associatedobject.SelectionChanged += Associatedobject_SelectionChanged;  
  17.             this.Associatedobject.MouseMove += Associatedobject_MouseMove;  
  18.         }  
  19.  
  20.         protected override void OnDetaching()  
  21.         {  
  22.             base.OnDetaching();  
  23.             this.Associatedobject.SelectionChanged -= Associatedobject_SelectionChanged;  
  24.             this.Associatedobject.MouseMove -= Associatedobject_MouseMove;  
  25.         }  
  26.  
  27.         private void Associatedobject_SelectionChanged(object sender, SelectionChangedEventArgs e)  
  28.         {  
  29.             if (_codeManageModel.CodeEntity != null)  
  30.             {  
  31.                 Popup popup = (this._codeManageModel.userControl as CodeManageView).CodeInfoPop;  
  32.                 popup.HorizontalOffset = 20;  
  33.                 popup.VerticalOffset = 70;  
  34.                 popup.IsOpen = true;  
  35.             }  
  36.         }  
  37.  
  38.         private void Associatedobject_MouseMove(object sender,MouseEventArgs e)  
  39.         {  
  40.             Popup popup = (this._codeManageModel.userControl as CodeManageView).CodeInfoPop;  
  41.             popup.IsOpen = false;  
  42.         }  
  43.     }  

在这里我只说一个基类,其他的就不往出贴了,大家自己看

 
 
  1. namespace System.Windows.Interactivity  
  2. {  
  3.     // Summary:  
  4.     //     Encapsulates state @R_708_4045@ion and zero or more ICommands into an attachable  
  5.     //     object.  
  6.     //  
  7.     // Type parameters:  
  8.     //   T:  
  9.     //     The type the System.Windows.Interactivity.Behavior<T> can be attached to.  
  10.     //  
  11.     // Remarks:  
  12.     //     Behavior is the base class for providing attachable state and commands to  
  13.     //     an object.  The types the Behavior can be attached to can be controlled by  
  14.     //     the generic parameter.  Override OnAttached() and OnDetaching() methods to  
  15.     //     hook and unhook any necessary handlers from the Associatedobject.  
  16.     public abstract class Behavior<T> : Behavior where T : System.Windows.DependencyObject  
  17.     {  
  18.         // Summary:  
  19.         //     Initializes a new instance of the System.Windows.Interactivity.Behavior<T>  
  20.         //     class.  
  21.         protected Behavior();  
  22.  
  23.         // Summary:  
  24.         //     Gets the object to which this System.Windows.Interactivity.Behavior<T> is  
  25.         //     attached.  
  26.         protected T Associatedobject { get; }  
  27.     }  

这里的的Associatedobject就是泛型T,并且它是System.Windows.DependencyObject类型的。Behavior类是个抽象类,具有Attach,Detach,OnAttached,OnDetaching方法。OnAttached在Attach方法调用以后生效。所以这段代码就实现了DataGrid的SelectionChanged和MouseMove事件,在SelectionChanged以后弹出Popup,MouseMove以后隐藏Popup。这种方式是不是很有效的实现了页面UI和逻辑的分离。再往下走,有个SetContextMenu方法,正是给DataGrid附加一个弹出菜单。在菜单构造好以后,需要调用ContextMenuService.SetContextMenu((this.userControl as CodeManageView).dgCodeList,contextMenu);,第一个参数是一个DependencyObject类型的对象,第二个是ContextMenu对象。类似于这样的内置对象还有FocusManager,它的方法FocusManager.GetFocusedElement()可以直接找到页面获得焦点的元素。我们来看看这个菜单效果

当我们点击关闭的时候,将会关闭页面。OK,今天就讲到这里,时间也不早了,洗洗睡。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐