这个行业里,山外有山,人外有人,忽然觉得自己是个菜鸟。
今天我们通过用户管理模块来系统的讲述关于Action,Trigger的使用。首先还是先上一张图,调一下胃口。
这个图中的GrID怎会变成如此摸样,是的,在这里我们用到了一点点3D的效果。首先我们先从前台代码入手。
<controls:ChilDWindow x:Class="MISInfoManage.UserManageVIEw" /*此处省略部分代码*/ xmlns:resource="clr-namespace:MISInfoManage.Resources" xmlns:trigger="clr-namespace:MISInfoManage.Trigger" xmlns:i="clr-namespace:System.windows.Interactivity;assembly=System.windows.Interactivity"> /*此处省略部分代码*/ <GrID x:name="LayoutRoot" margin="2"> <GrID.RowDeFinitions> <RowDeFinition Height="65"/> <RowDeFinition Height="297"/> <RowDeFinition Height="auto"/> </GrID.RowDeFinitions> <sdk:DataGrID GrID.Row="0" GrID.Column="0" Height="300" WIDth="540" /*此处省略部分代码*/ > <sdk:DataGrID.Projection> <PlaneProjection RotationX="0" RotationY="10" RotationZ="0"></PlaneProjection> </sdk:DataGrID.Projection> <sdk:DataGrID.Effect> <DropShadowEffect BlurRadius="5" color="Black" ShadowDepth="8" Opacity="0.8"/> </sdk:DataGrID.Effect> <i:Interaction.Triggers> <i:EventTrigger Eventname="SelectionChanged"> <trigger:SelectChangeTargetTrigger Targetname="txtUserNo"> </trigger:SelectChangeTargetTrigger> <trigger:SelectChangeTargetTrigger Targetname="cmbType"> </trigger:SelectChangeTargetTrigger> <trigger:SelectChangeTargetTrigger Targetname="cmbState"> </trigger:SelectChangeTargetTrigger> </i:EventTrigger> </i:Interaction.Triggers> <sdk:DataGrID.Columns> /*此处省略部分代码*/ </sdk:DataGrID.Columns> </sdk:DataGrID> <sdk:DataPager x:name="dataPager" GrID.Row="1" borderThickness="1" borderBrush="Black" displayMode="FirstLastPrevIoUsNextNumeric" PageSize="10"> </sdk:DataPager> <border borderThickness="1" margin="0,5,5" Background="Silver" borderBrush="Black" GrID.Row="2" GrID.Column="0"> /*此处省略部分代码*/ <Image Source="Images/windows.png" Opacity="0.7" GrID.Row="0" GrID.Column="0"/> <TextBox x:name="txtUserNo" Foreground="Silver" borderThickness="0" GrID.Row="0" GrID.Column="1" Text="{Binding UserNo,Mode=OneWay}"> <i:Interaction.Triggers> <i:EventTrigger Eventname="GotFocus"> <trigger:FocusTrigger></trigger:FocusTrigger> </i:EventTrigger> <i:EventTrigger Eventname="LostFocus"> <trigger:LostFocusTrigger> </trigger:LostFocusTrigger> </i:EventTrigger> </i:Interaction.Triggers> </TextBox> </GrID> </border> /*此处省略部分代码*/ <ComboBox x:name="cmbType" GrID.Row="1" GrID.Column="1" Background="AliceBlue" HorizontalAlignment="left" margin="2,0" WIDth="200" ItemsSource="{Binding UserTypeList,Mode=OneWay}" SelectedItem="{Binding UserType}"> <ComboBox.ItemTemplate> <DataTemplate> <StackPanel OrIEntation="Horizontal"> <Image Source="{Binding UserTypeImage}" Height="22" Stretch="UniformToFill"></Image> <TextBlock Text="{Binding UserTypename,Mode=TwoWay}" FontWeight="Bold" margin="2,0"/> </StackPanel> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox> /*此处省略部分代码*/ </GrID> </border> </GrID> </controls:ChilDWindow>
在这里布局我们就不说了,相信看过前几篇的都明白。首先我们看有这么一段代码
<sdk:DataGrID.Projection> <PlaneProjection RotationX="0" RotationY="10" RotationZ="0"></PlaneProjection> </sdk:DataGrID.Projection>
这段代码是设置DataGrID的3D效果的,在这里我们设置其x轴的旋转角为0,Y轴旋转角为10,Z轴是0。怎么理解呢?这就好比空间一个三维坐标,X轴转动你想象成手指头抓住X轴的正方向,用手指去撵的让它转动。同理,Y轴和Z轴也是同样的道理。我们在这里设置正角,是让它逆时针转动,如果是负角则是顺时针。OK,我们接着看下面这样一段代码
<i:Interaction.Triggers> <i:EventTrigger Eventname="SelectionChanged"> <trigger:SelectChangeTargetTrigger Targetname="txtUserNo"> </trigger:SelectChangeTargetTrigger> <trigger:SelectChangeTargetTrigger Targetname="cmbType"> </trigger:SelectChangeTargetTrigger> <trigger:SelectChangeTargetTrigger Targetname="cmbState"> </trigger:SelectChangeTargetTrigger> </i:EventTrigger> </i:Interaction.Triggers>
这段涉及到我开始提到的Action,在这里我们使用到了TargetedTriggerAction,也就是在DataGrID SelectionChanged事件触发的时候,会对这三个Targetname指定的UIElement进行UI的变化。我们看看这个SelectChangeTargetTrigger 。
namespace MISInfoManage.Trigger { public class SelectChangeTargetTrigger : TargetedTriggerAction<DependencyObject> { private DependencyObject element; public SelectChangeTargetTrigger() { } protected overrIDe voID OnAttached() { base.OnAttached(); if (Target != null) { element = Target; } } protected overrIDe voID OnDetaching() { base.OnDetaching(); element = null; } protected overrIDe voID OnTargetChanged(DependencyObject oldTarget, DependencyObject newTarget) { base.OnTargetChanged(oldTarget, newTarget); if (element == null) { element = newTarget; } } protected overrIDe voID Invoke(object parameter) { if ((this.Associatedobject as DataGrID).SelectedItem != null) { if (this.Target.GetType() == typeof(TextBox)) { TextBox textBox = (Target as TextBox); textBox.IsReadonly = true; if (textBox.name == "txtUserNo") { textBox.Foreground = new SolIDcolorBrush(colors.Black); } } if (this.GetType() == typeof(ComboBox)) { (Target as ComboBox).IsEnabled = false; } } } } }
在这里需要注意的是要引用System.windows.Interactivity命名空间。结合界面代码我们可以看出,当DataGrID的SelectionChanged事件触发以后,会调用Invoke方法,也就是遍历该TargetedTrigger下的目标元素,在这里是对文本框设置Readonly,对ComboBox设置IsEnabled。这样就有效的实现了UI与逻辑的分离,这个将放在viewmodel中做处理。再往下走我们发现这样一段代码
<border borderThickness="1" borderBrush="Black" GrID.Row="0" GrID.Column="1" WIDth="200"> <GrID> <GrID.RowDeFinitions> <RowDeFinition Height="auto"></RowDeFinition> </GrID.RowDeFinitions> <GrID.ColumnDeFinitions> <ColumnDeFinition WIDth="auto"></ColumnDeFinition> <ColumnDeFinition WIDth="*"></ColumnDeFinition> </GrID.ColumnDeFinitions> <Image Source="Images/windows.png" Opacity="0.7" GrID.Row="0" GrID.Column="0"/> <TextBox x:name="txtUserNo" Foreground="Silver" borderThickness="0" GrID.Row="0" GrID.Column="1" Text="{Binding UserNo,Mode=OneWay}"> <i:Interaction.Triggers> <i:EventTrigger Eventname="GotFocus"> <trigger:FocusTrigger></trigger:FocusTrigger> </i:EventTrigger> <i:EventTrigger Eventname="LostFocus"> <trigger:LostFocusTrigger> </trigger:LostFocusTrigger> </i:EventTrigger> </i:Interaction.Triggers> </TextBox> </GrID> </border>
这段代码是模拟了一个水印文本框效果,在这里使用到了Trigger,一个是FocusTrigger,一个是LostFocusTrigger,结合起来实现水印效果。我们看看这两个Trigger的代码
public class FocusTrigger:TriggerAction<TextBox> { protected overrIDe voID OnAttached() { base.OnAttached(); } protected overrIDe voID OnDetaching() { base.OnDetaching(); } protected overrIDe voID Invoke(object parameter) { if (this.Associatedobject.Text.Trim() == "请输入用户名") { this.Associatedobject.Text = string.Empty; this.Associatedobject.Foreground = new SolIDcolorBrush(colors.Black); } } }
这个是FocusTrigger,文本框获取焦点时,调用Invoke方法。这个时候当文本框的值是“请输入用户名”的时候,就清掉文本框,并且字体前景色设置为黑色。我们再看看LostFocusTrigger的代码
public class LostFocusTrigger : TriggerAction<TextBox> { protected overrIDe voID OnAttached() { base.OnAttached(); } protected overrIDe voID OnDetaching() { base.OnDetaching(); } protected overrIDe voID Invoke(object parameter) { if (string.IsNullOrWhiteSpace(this.Associatedobject.Text)) { this.Associatedobject.Foreground = new SolIDcolorBrush(colors.Gray); this.Associatedobject.Text = "请输入用户名"; } } }
当文本框失去焦点的时候,如果文本框值为空或者空白,那么文本框的值为“请输入用户名”,前景色改为Gray。OK,我们继续往下看
<ComboBox x:name="cmbType" GrID.Row="1" GrID.Column="1" Background="AliceBlue" HorizontalAlignment="left" margin="2,0"/> </StackPanel> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox>
在这里我们使用了ComboBox的项模板,在这里你可以自定义你想要的模版。在这里我放了一个图片和一个文本。如下图所示
怎么样,很不错吧。最后在这列我们重点看看分页。我这可是服务端分页。
<sdk:DataPager x:name="dataPager" GrID.Row="1" borderThickness="1" borderBrush="Black" displayMode="FirstLastPrevIoUsNextNumeric" PageSize="10"> </sdk:DataPager>
这个时候我就要把viewmodel的代码贴出来了,否则没法讲述清楚。
namespace MISInfoManage.viewmodels { public class UserManageviewmodel : INotifyPropertyChanged { private bool isFirstLoad; public UserManageVIEw userManageVIEw; DataPagerTrigger dataPagertrigger; List<int> List = new List<int>(); public UserManageviewmodel() { this.InitData(1, 10); } public UserManageviewmodel(UserManageVIEw userManageVIEw) : this() { isFirstLoad = true; this.userManageVIEw = userManageVIEw; this.dataPagertrigger = new DataPagerTrigger(this); this.AttachTrigger(); this.SetTitle(); this.UserNo = "请输入用户名"; } #region property /*此处省略部分代码*/ #endregion #region method private voID AttachTrigger() { this.dataPagertrigger.Attach(this.userManageVIEw.dataPager); } private voID SetTitle() { Image image = new Image(); image.source = new BitmAPImage(new Uri("../Images/drag.png", UriKind.relative)); image.Height = 30; image.WIDth = 20; TextBlock textBlock = new TextBlock(); textBlock.margin = new Thickness(5, 0, 0); textBlock.Text = "用户管理"; textBlock.FontSize = 14; textBlock.FontWeight = FontWeights.Bold; StackPanel stackPanel = new StackPanel(); stackPanel.OrIEntation = OrIEntation.Horizontal; stackPanel.Background = new RadialGradIEntBrush(colors.Gray, colors.brown); stackPanel.WIDth = this.userManageVIEw.WIDth; stackPanel.Children.Add(image); stackPanel.Children.Add(textBlock); this.userManageVIEw.Title = stackPanel; } private voID GetUserList(UserRequest request, EventHandler<GetUserListCompletedEventArgs> callback) { UserManageService.UserManageServiceClIEnt clIEnt = new UserManageServiceClIEnt(); clIEnt.GetUserListCompleted += callback; clIEnt.GetUserListAsync(request); } /*此处省略部分代码*/ private voID GetUserPagedCollection(int totalCount) { List.Clear(); for (int i = 0; i < totalCount; i++) { List.Add(i); } PagedCollectionVIEw pagedCollectionVIEw = new PagedCollectionVIEw(List); this.userManageVIEw.dataPager.source = pagedCollectionVIEw; isFirstLoad = false; } public voID GetDataByPage(int pageIndex, int pageSize) { UserRequest userRequest = new UserRequest() { PageIndex = pageIndex, PageSize = pageSize }; this.GetUserList(userRequest, (obj, args) => { if (args.Error == null) { this.UserResponse = args.Result; this.UserList = userResponse.UserList; if (isFirstLoad) { this.GetUserPagedCollection(this.UserResponse.RecordCount); } } }); } private voID InitData(int pageIndex, int pageSize) { this.GetDataByPage(pageIndex,pageSize); this.GetUserStateList(); this.GetUserTypeList(); } #endregion /*此处省略部分代码*/ } }
在viewmodel的代码中,我们发现了这样一段代码
this.dataPagertrigger = new DataPagerTrigger(this); this.AttachTrigger();
private voID AttachTrigger() { this.dataPagertrigger.Attach(this.userManageVIEw.dataPager); }
这段代码就是在初始化viewmodel的时候,将dataPager控件附加给dataPagertrigger。我们看看dataPagertrigger代码
public class DataPagerTrigger : TriggerBase<UIElement> { public UserManageviewmodel userManageviewmodel; public DataPagerTrigger(UserManageviewmodel userManageviewmodel) { this.userManageviewmodel = userManageviewmodel; } protected overrIDe voID OnAttached() { base.OnAttached(); if (this.Associatedobject is DataPager) { (this.Associatedobject as DataPager).PageIndexChanged += this.PageIndexChanged; } } protected overrIDe voID OnDetaching() { base.OnDetaching(); if (this.Associatedobject is DataPager) { (this.Associatedobject as DataPager).PageIndexChanged -= this.PageIndexChanged; } } private voID PageIndexChanged(object sender, EventArgs e) { DataPager dataPager = sender as DataPager; this.userManageviewmodel.GetDataByPage(dataPager.PageIndex, dataPager.PageSize); } }
这个类继承自TriggerBase,我们给其注册了一个PageIndexChanged 事件,当DataPager控件页码变化时,调用PageIndexChanged方法,在这个方法里调用userManageviewmodel的GetDataByPage方法。在GetDataByPage方法中先获取用户列表,判断如果是第一次加载,就给 DataPager控件附一个PagedCollectionVIEw类型的一个source,在这里通过模拟,可以有效的进行分页,因为目前我发现这个分页控件只能客户端分页。所以模拟一个List<int>,它的总条数==表的总记录。这样就实现了服务端分页,如果谁想要源码,可以加入群205217091。我们看看分页的效果
最后大家可能注意到d出界面的Title和以前的不一样,这里你可以自定义,如viewmodel中的SetTitle方法。好了,时间不早了,洗洗睡!
总结以上是内存溢出为你收集整理的Silverlight MVVM 贴近实战(七)全部内容,希望文章能够帮你解决Silverlight MVVM 贴近实战(七)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)