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

Silverlight MVVM 贴近实战(七)

这个行业里,山外有山,人外有人,忽然觉得自己是个菜鸟。

今天我们通过用户管理模块来系统的讲述关于Action,Trigger的使用。首先还是先上一张图,调一下胃口。

这个图中的Grid怎会变成如此摸样,是的,在这里我们用到了一点点3D的效果。首先我们先从前台代码入手。

 
 
  1. <controls:ChildWindow x:Class="MISInfoManage.UserManageView" 
  2. @H_404_32@            /*此处省略部分代码*/              xmlns:resource="clr-namespace:MISInfoManage.Resources"  @H_404_32@  @H_404_32@            xmlns:trigger="clr-namespace:MISInfoManage.Trigger" 
  3.            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"> 
  4. @H_404_32@ /*此处省略部分代码*/    @H_404_32@      <Grid x:Name="LayoutRoot" Margin="2">  @H_404_32@         <Grid.RowDeFinitions> 
  5.             <RowDeFinition Height="65"/> 
  6. @H_404_32@             <RowDeFinition Height="297"/> 
  7.             <RowDeFinition Height="Auto"/> 
  8. @H_404_32@         </Grid.RowDeFinitions> 
  9.         <sdk:DataGrid Grid.Row="0" Grid.Column="0" Height="300" Width="540"   
  10. @H_404_32@                          /*此处省略部分代码*/   >  @H_404_32@    
  11.             <sdk:DataGrid.Projection> 
  12. @H_404_32@                 <PlaneProjection RotationX="0" RotationY="10" RotationZ="0"></PlaneProjection> 
  13.             </sdk:DataGrid.Projection> 
  14. @H_404_32@             <sdk:DataGrid.Effect> 
  15.                 <DropShadowEffect BlurRadius="5" Color="Black" ShadowDepth="8" Opacity="0.8"/> 
  16. @H_404_32@             </sdk:DataGrid.Effect> 
  17.             <i:Interaction.Triggers> 
  18. @H_404_32@                 <i:EventTrigger EventName="SelectionChanged"> 
  19.                     <trigger:SelectChangeTargetTrigger TargetName="txtUserNo"> 
  20. @H_404_32@                     </trigger:SelectChangeTargetTrigger> 
  21.                     <trigger:SelectChangeTargetTrigger TargetName="cmbType"> 
  22. @H_404_32@                     </trigger:SelectChangeTargetTrigger> 
  23.                     <trigger:SelectChangeTargetTrigger TargetName="cmbState"> 
  24. @H_404_32@                     </trigger:SelectChangeTargetTrigger> 
  25.                 </i:EventTrigger> 
  26. @H_404_32@             </i:Interaction.Triggers> 
  27.             <sdk:DataGrid.Columns> 
  28. @H_404_32@          /*此处省略部分代码*/               </sdk:DataGrid.Columns>  @H_404_32@  @H_404_32@         </sdk:DataGrid> 
  29.         <sdk:DataPager x:Name="dataPager" 
  30. @H_404_32@                        Grid.Row="1" BorderThickness="1" 
  31.                        BorderBrush="Black" 
  32. @H_404_32@                        displayMode="FirstLastPrevIoUsNextNumeric" 
  33.                        PageSize="10"> 
  34. @H_404_32@         </sdk:DataPager> 
  35.         <Border BorderThickness="1" Margin="0,5,5" Background="Silver" BorderBrush="Black" Grid.Row="2" Grid.Column="0"> 
  36. @H_404_32@             /*此处省略部分代码*/                           <Image Source="Images/Windows.png" Opacity="0.7" Grid.Row="0" Grid.Column="0"/>  @H_404_32@     @H_404_32@ 
  37.                         <TextBox x:Name="txtUserNo" Foreground="Silver" BorderThickness="0" Grid.Row="0" Grid.Column="1" Text="{Binding UserNo,Mode=OneWay}"> 
  38. @H_404_32@                             <i:Interaction.Triggers> 
  39.                                <i:EventTrigger EventName="GotFocus"> 
  40. @H_404_32@                                    <trigger:FocusTrigger></trigger:FocusTrigger> 
  41.                                </i:EventTrigger> 
  42. @H_404_32@                                 <i:EventTrigger EventName="LostFocus"> 
  43.                                     <trigger:LostFocusTrigger> 
  44. @H_404_32@                                     </trigger:LostFocusTrigger> 
  45.                                 </i:EventTrigger> 
  46. @H_404_32@                             </i:Interaction.Triggers> 
  47.                         </TextBox> 
  48. @H_404_32@                     </Grid> 
  49.                 </Border> 
  50. @H_404_32@                /*此处省略部分代码*/                   <ComboBox x:Name="cmbType" Grid.Row="1" Grid.Column="1"  @H_404_32@     @H_404_32@  @H_404_32@                           Background="AliceBlue"   
  51.                           HorizontalAlignment="Left" Margin="2,0" Width="200" 
  52. @H_404_32@                           ItemsSource="{Binding UserTypeList,Mode=OneWay}"   
  53.                           SelectedItem="{Binding UserType}"> 
  54. @H_404_32@                     <ComboBox.ItemTemplate> 
  55.                         <DataTemplate> 
  56. @H_404_32@                             <StackPanel Orientation="Horizontal"> 
  57.                                 <Image Source="{Binding UserTypeImage}" Height="22" Stretch="UniformToFill"></Image> 
  58. @H_404_32@                                 <TextBlock Text="{Binding UserTypeName,Mode=TwoWay}" FontWeight="Bold" Margin="2,0"/> 
  59.                             </StackPanel> 
  60. @H_404_32@                         </DataTemplate> 
  61.                     </ComboBox.ItemTemplate> 
  62. @H_404_32@                 </ComboBox> 
  63.                /*此处省略部分代码*/               </Grid> 
  64.  
  65. @H_404_32@         </Border> 
  66.     </Grid> 
  67. @H_404_32@ </controls:ChildWindow> 

在这里布局我们就不说了,相信看过前几篇的都明白。首先我们看有这么一段代码

 
 
  1. <sdk:DataGrid.Projection> 
  2. @H_404_32@                 <PlaneProjection RotationX="0" RotationY="10" RotationZ="0"></PlaneProjection> 
  3.             </sdk:DataGrid.Projection> 

这段代码是设置DataGrid的3D效果的,在这里我们设置其x轴的旋转角为0,Y轴旋转角为10,Z轴是0。怎么理解呢?这就好比空间一个三维坐标,X轴转动你想象成手指头抓住X轴的正方向,用手指去撵的让它转动。同理,Y轴和Z轴也是同样的道理。我们在这里设置正角,是让它逆时针转动,如果是负角则是顺时针。OK,我们接着看下面这样一段代码

 
 
  1. <i:Interaction.Triggers> 
  2. @H_404_32@                 <i:EventTrigger EventName="SelectionChanged"> 
  3.                     <trigger:SelectChangeTargetTrigger TargetName="txtUserNo"> 
  4. @H_404_32@                     </trigger:SelectChangeTargetTrigger> 
  5.                     <trigger:SelectChangeTargetTrigger TargetName="cmbType"> 
  6. @H_404_32@                     </trigger:SelectChangeTargetTrigger> 
  7.                     <trigger:SelectChangeTargetTrigger TargetName="cmbState"> 
  8. @H_404_32@                     </trigger:SelectChangeTargetTrigger> 
  9.                 </i:EventTrigger> 
  10. @H_404_32@             </i:Interaction.Triggers> 

这段涉及到我开始提到的Action,在这里我们使用到了TargetedTriggerAction,也就是在DataGrid SelectionChanged事件触发的时候,会对这三个TargetName指定的UIElement进行UI的变化。我们看看这个SelectChangeTargetTrigger 。

 
 
  1. namespace MISInfoManage.Trigger  
  2. @H_404_32@{  
  3.     public class SelectChangeTargetTrigger : TargetedTriggerAction<DependencyObject>  
  4. @H_404_32@    {  
  5.         private DependencyObject element;  
  6. @H_404_32@         public SelectChangeTargetTrigger()  
  7.         { }  
  8. @H_404_32@ 
  9.         protected override void OnAttached()  
  10. @H_404_32@        {  
  11.             base.OnAttached();  
  12. @H_404_32@             if (Target != null)  
  13.             {  
  14. @H_404_32@                element = Target;  
  15.             }  
  16. @H_404_32@        }  
  17.  
  18. @H_404_32@         protected override void OnDetaching()  
  19.         {  
  20. @H_404_32@             base.OnDetaching();  
  21.             element = null;  
  22. @H_404_32@        }  
  23.  
  24. @H_404_32@         protected override void OnTargetChanged(DependencyObject oldTarget, DependencyObject newTarget)  
  25.         {  
  26. @H_404_32@             base.OnTargetChanged(oldTarget, newTarget);  
  27.             if (element == null)  
  28. @H_404_32@            {  
  29.                 element = newTarget;  
  30. @H_404_32@            }  
  31.         }  
  32. @H_404_32@ 
  33.         protected override void Invoke(object parameter)  
  34. @H_404_32@        {  
  35.             if ((this.Associatedobject as DataGrid).SelectedItem != null)  
  36. @H_404_32@            {  
  37.                 if (this.Target.GetType() == typeof(TextBox))  
  38. @H_404_32@                {  
  39.                     TextBox textBox = (Target as TextBox);  
  40. @H_404_32@                     textBox.IsReadOnly = true;  
  41.                     if (textBox.Name == "txtUserNo")  
  42. @H_404_32@                    {  
  43.                         textBox.Foreground = new SolidColorBrush(Colors.Black);  
  44. @H_404_32@                    }  
  45.                 }  
  46. @H_404_32@                 if (this.GetType() == typeof(ComboBox))  
  47.                 {  
  48. @H_404_32@                     (Target as ComboBox).IsEnabled = false;  
  49.                 }   
  50. @H_404_32@            }  
  51.         }  
  52. @H_404_32@    }  

在这里需要注意的是要引用System.Windows.Interactivity命名空间。结合界面代码我们可以看出,当DataGrid的SelectionChanged事件触发以后,会调用Invoke方法,也就是遍历该TargetedTrigger下的目标元素,在这里是对文本框设置Readonly,对ComboBox设置IsEnabled。这样就有效的实现了UI与逻辑的分离,这个将放在viewmodel中做处理。再往下走我们发现这样一段代码

 
 
  1. <Border BorderThickness="1" BorderBrush="Black" Grid.Row="0" Grid.Column="1"  Width="200"> 
  2. @H_404_32@                     <Grid> 
  3.                         <Grid.RowDeFinitions> 
  4. @H_404_32@                             <RowDeFinition Height="Auto"></RowDeFinition> 
  5.                         </Grid.RowDeFinitions> 
  6. @H_404_32@                         <Grid.ColumnDeFinitions> 
  7.                             <ColumnDeFinition Width="Auto"></ColumnDeFinition> 
  8. @H_404_32@                             <ColumnDeFinition Width="*"></ColumnDeFinition> 
  9.                         </Grid.ColumnDeFinitions> 
  10. @H_404_32@                         <Image Source="Images/Windows.png" Opacity="0.7" Grid.Row="0" Grid.Column="0"/> 
  11.                         <TextBox x:Name="txtUserNo" Foreground="Silver" BorderThickness="0" Grid.Row="0" Grid.Column="1" Text="{Binding UserNo,Mode=OneWay}"> 
  12. @H_404_32@                             <i:Interaction.Triggers> 
  13.                                <i:EventTrigger EventName="GotFocus"> 
  14. @H_404_32@                                    <trigger:FocusTrigger></trigger:FocusTrigger> 
  15.                                </i:EventTrigger> 
  16. @H_404_32@                                 <i:EventTrigger EventName="LostFocus"> 
  17.                                     <trigger:LostFocusTrigger> 
  18. @H_404_32@                                     </trigger:LostFocusTrigger> 
  19.                                 </i:EventTrigger> 
  20. @H_404_32@                             </i:Interaction.Triggers> 
  21.                         </TextBox> 
  22. @H_404_32@                     </Grid> 
  23.                 </Border> 

这段代码是模拟了一个水印文本框效果在这里使用到了Trigger,一个是FocusTrigger,一个是LostFocusTrigger,结合起来实现水印效果。我们看看这两个Trigger的代码

 
 
  1. public class FocusTrigger:TriggerAction<TextBox>  
  2. @H_404_32@    {  
  3.         protected override void OnAttached()  
  4. @H_404_32@        {  
  5.             base.OnAttached();  
  6. @H_404_32@        }  
  7.  
  8. @H_404_32@         protected override void OnDetaching()  
  9.         {  
  10. @H_404_32@             base.OnDetaching();  
  11.         }  
  12. @H_404_32@ 
  13.         protected override void Invoke(object parameter)  
  14. @H_404_32@        {  
  15.             if (this.Associatedobject.Text.Trim() == "请输入用户名")  
  16. @H_404_32@            {  
  17.                 this.Associatedobject.Text = string.Empty;  
  18. @H_404_32@                 this.Associatedobject.Foreground = new SolidColorBrush(Colors.Black);  
  19.             }  
  20. @H_404_32@        }  
  21.     } 

这个是FocusTrigger,文本框获取焦点时,调用Invoke方法。这个时候当文本框的值是“请输入用户名”的时候,就清掉文本框,并且字体前景色设置为黑色。我们再看看LostFocusTrigger的代码

 
 
  1. public class LostFocusTrigger : TriggerAction<TextBox>  
  2. @H_404_32@    {  
  3.         protected override void OnAttached()  
  4. @H_404_32@        {  
  5.             base.OnAttached();  
  6. @H_404_32@        }  
  7.  
  8. @H_404_32@         protected override void OnDetaching()  
  9.         {  
  10. @H_404_32@             base.OnDetaching();  
  11.         }  
  12. @H_404_32@ 
  13.         protected override void Invoke(object parameter)  
  14. @H_404_32@        {  
  15.             if (string.IsNullOrWhiteSpace(this.Associatedobject.Text))  
  16. @H_404_32@            {  
  17.                 this.Associatedobject.Foreground = new SolidColorBrush(Colors.Gray);  
  18. @H_404_32@                 this.Associatedobject.Text = "请输入用户名";  
  19.             }  
  20. @H_404_32@        }  
  21.     } 

当文本框失去焦点的时候,如果文本框值为空或者空白,那么文本框的值为“请输入用户名”,前景色改为Gray。OK,我们继续往下看

 
 
  1. <ComboBox x:Name="cmbType" Grid.Row="1" Grid.Column="1" 
  2. @H_404_32@                           Background="AliceBlue"   
  3.                           HorizontalAlignment="Left" Margin="2,0"/> 
  4.                             </StackPanel> 
  5. @H_404_32@                         </DataTemplate> 
  6.                     </ComboBox.ItemTemplate> 
  7. @H_404_32@                 </ComboBox> 

在这里我们使用了ComboBox的项模板,在这里你可以自定义你想要的模版。在这里我放了一个图片一个文本。如下图所示

怎么样,很不错吧。最后在这列我们重点看看分页。我这可是服务端分页

 
 
  1. <sdk:DataPager x:Name="dataPager" 
  2. @H_404_32@                        Grid.Row="1" BorderThickness="1" 
  3.                        BorderBrush="Black" 
  4. @H_404_32@                        displayMode="FirstLastPrevIoUsNextNumeric" 
  5.                        PageSize="10"> 
  6. @H_404_32@         </sdk:DataPager> 

这个时候我就要把viewmodel的代码贴出来了,否则没法讲述清楚。

 
 
  1. namespace MISInfoManage.viewmodels  
  2. @H_404_32@{  
  3.     public class UserManageviewmodel : INotifyPropertyChanged  
  4. @H_404_32@    {  
  5.         private bool isFirstLoad;  
  6. @H_404_32@         public UserManageView userManageView;  
  7.         DataPagerTrigger dataPagertrigger;  
  8. @H_404_32@         List<int> list = new List<int>();  
  9.         public UserManageviewmodel()  
  10. @H_404_32@        {  
  11.             this.InitData(1, 10);  
  12. @H_404_32@        }  
  13.  
  14. @H_404_32@         public UserManageviewmodel(UserManageView userManageView)  
  15.             : this()  
  16. @H_404_32@        {  
  17.             isFirstLoad = true;  
  18. @H_404_32@             this.userManageView = userManageView;  
  19.             this.dataPagertrigger = new DataPagerTrigger(this);  
  20. @H_404_32@             this.AttachTrigger();  
  21.             this.SetTitle();  
  22. @H_404_32@             this.UserNo = "请输入用户名";  
  23.         }  
  24. @H_404_32@ 
  25.         #region property  
  26. @H_404_32@ 
  27.        /*此处省略部分代码*/           #endregion  
  28. @H_404_32@    
  29.  
  30.  
  31. @H_404_32@        #region method  
  32.  
  33. @H_404_32@         private void AttachTrigger()  
  34.         {  
  35. @H_404_32@             this.dataPagertrigger.Attach(this.userManageView.dataPager);  
  36.         }  
  37. @H_404_32@ 
  38.         private void SetTitle()  
  39. @H_404_32@        {  
  40.             Image image = new Image();  
  41. @H_404_32@             image.source = new BitmapImage(new Uri("../Images/drag.png", UriKind.Relative));  
  42.             image.Height = 30;  
  43. @H_404_32@            image.Width = 20;  
  44.             TextBlock textBlock = new TextBlock();  
  45. @H_404_32@             textBlock.Margin = new Thickness(5, 0, 0);  
  46.             textBlock.Text = "用户管理";  
  47. @H_404_32@            textBlock.FontSize = 14;  
  48.             textBlock.FontWeight = FontWeights.Bold;  
  49. @H_404_32@             StackPanel stackPanel = new StackPanel();  
  50.             stackPanel.Orientation = Orientation.Horizontal;  
  51. @H_404_32@             stackPanel.Background = new RadialGradientBrush(Colors.Gray, Colors.brown);  
  52.             stackPanel.Width = this.userManageView.Width;  
  53. @H_404_32@            stackPanel.Children.Add(image);  
  54.             stackPanel.Children.Add(textBlock);  
  55. @H_404_32@             this.userManageView.Title = stackPanel;  
  56.         }  
  57. @H_404_32@ 
  58.         private void GetUserList(UserRequest request, EventHandler<GetUserListCompletedEventArgs> callback)  
  59. @H_404_32@        {  
  60.             UserManageService.UserManageServiceClient client = new UserManageServiceClient();  
  61. @H_404_32@            client.GetUserListCompleted += callback;  
  62.             client.GetUserListAsync(request);  
  63. @H_404_32@        }  
  64.  
  65. @H_404_32@        /*此处省略部分代码*/     @H_404_32@     @H_404_32@  @H_404_32@         private void GetUserPagedCollection(int totalCount)  
  66.         {  
  67. @H_404_32@            list.Clear();  
  68.             for (int i = 0; i < totalCount; i++)  
  69. @H_404_32@            {  
  70.                 list.Add(i);  
  71. @H_404_32@            }  
  72.             PagedCollectionView pagedCollectionView = new PagedCollectionView(list);  
  73. @H_404_32@             this.userManageView.dataPager.source = pagedCollectionView;  
  74.             isFirstLoad = false;  
  75. @H_404_32@        }  
  76.  
  77. @H_404_32@         public void GetDataByPage(int pageIndex, int pageSize)  
  78.         {  
  79. @H_404_32@             UserRequest userRequest = new UserRequest()  
  80.             {  
  81. @H_404_32@                PageIndex = pageIndex, 
  82.                 PageSize = pageSize  
  83. @H_404_32@            };  
  84.             this.GetUserList(userRequest, (obj, args) =>  
  85. @H_404_32@            {  
  86.                 if (args.Error == null)  
  87. @H_404_32@                {  
  88.                     this.UserResponse = args.Result;  
  89. @H_404_32@                     this.UserList = userResponse.UserList;  
  90.                     if (isFirstLoad)  
  91. @H_404_32@                    {  
  92.                         this.GetUserPagedCollection(this.UserResponse.RecordCount);  
  93. @H_404_32@                    }  
  94.                 }  
  95. @H_404_32@            });  
  96.         }  
  97. @H_404_32@ 
  98.         private void InitData(int pageIndex, int pageSize)  
  99. @H_404_32@        {  
  100.             this.GetDataByPage(pageIndex,pageSize);  
  101. @H_404_32@             this.GetUserStateList();  
  102.             this.GetUserTypeList();  
  103. @H_404_32@         }  
  104.  
  105. @H_404_32@        #endregion  
  106.  
  107. @H_404_32@         /*此处省略部分代码*/       }   @H_404_32@     @H_404_32@ 

viewmodel的代码中,我们发现了这样一段代码

 
 
  1. this.dataPagertrigger = new DataPagerTrigger(this);  
  2. @H_404_32@            this.AttachTrigger(); 
 
 
  1. private void AttachTrigger()  
  2. @H_404_32@       {  
  3.            this.dataPagertrigger.Attach(this.userManageView.dataPager);  
  4. @H_404_32@       } 

这段代码就是在初始化viewmodel的时候,将dataPager控件附加给dataPagertrigger。我们看看dataPagertrigger代码

 
 
  1. public class DataPagerTrigger : TriggerBase<UIElement>  
  2. @H_404_32@    {  
  3.         public UserManageviewmodel userManageviewmodel;  
  4. @H_404_32@         public DataPagerTrigger(UserManageviewmodel userManageviewmodel)  
  5.         {  
  6. @H_404_32@             this.userManageviewmodel = userManageviewmodel;  
  7.         }  
  8. @H_404_32@ 
  9.         protected override void OnAttached()  
  10. @H_404_32@        {  
  11.             base.OnAttached();  
  12. @H_404_32@             if (this.Associatedobject is DataPager)  
  13.             {  
  14. @H_404_32@                 (this.Associatedobject as DataPager).PageIndexChanged += this.PageIndexChanged;  
  15.             }  
  16. @H_404_32@        }  
  17.  
  18. @H_404_32@         protected override void OnDetaching()  
  19.         {  
  20. @H_404_32@             base.OnDetaching();  
  21.             if (this.Associatedobject is DataPager)  
  22. @H_404_32@            {  
  23.                 (this.Associatedobject as DataPager).PageIndexChanged -= this.PageIndexChanged;  
  24. @H_404_32@            }  
  25.         }  
  26. @H_404_32@ 
  27.         private void PageIndexChanged(object sender, EventArgs e)  
  28. @H_404_32@        {  
  29.             DataPager dataPager = sender as DataPager;  
  30. @H_404_32@             this.userManageviewmodel.GetDataByPage(dataPager.PageIndex, dataPager.PageSize);  
  31.         }  
  32. @H_404_32@    } 

这个类继承自TriggerBase,我们给其注册一个PageIndexChanged 事件,当DataPager控件页码变化时,调用PageIndexChanged方法在这方法调用userManageviewmodel的GetDataByPage方法。在GetDataByPage方法中先获取用户列表,判断如果是第一次加载,就给 DataPager控件附一个PagedCollectionView类型的一个source,在这里通过模拟,可以有效的进行分页,因为目前我发现这个分页控件只能客户端分页。所以模拟一个List<int>,它的总条数==表的总记录。这样就实现了服务端分页,如果谁想要源码,可以加入群205217091。我们看看分页效果

最后大家可能注意到弹出界面的Title和以前的不一样,这里你可以自定义,如viewmodel中的SetTitle方法。好了,时间不早了,洗洗睡!

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

相关推荐