在后台代码中动态生成pivot项并设置EventTrigger和Action的绑定
最近在做今日头条WP的过程中,遇到需要动态生成Pivot项的问题。第一个版本是把几个频道写死在xaml里了,事件绑定也写在xaml里,每个频道绑定一个ObservableCollection<ArticleItem>。xaml中一个Pivot项的代码大体如下:
<phone:PivotItem Header="热点">
<Grid Margin="12,0,0,0" >
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<telerikPrimitives:RadDataBoundListBox UseOptimizedManipulationRouting="False"
DataVirtualizationMode="OnDemandAutomatic"
IsPullToRefreshEnabled="True"
EmptyContent=""
IsAsyncBalanceEnabled="True"
x:Name="radListBoxHot"
Margin="0"
CacheMode="BitmapCache" ItemsSource="{Binding ArticleItemListHot}" telerikCore:InteractionEffectManager.IsInteractionEnabled="True" ItemTemplate="{StaticResource ArticleItemDataTemplate}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="ItemTap">
<i:InvokeCommandAction Command="{Binding CommandNavToArticleDetail}" CommandParameter="{Binding SelectedItem, ElementName=radListBoxHot}" />
</i:EventTrigger>
<i:EventTrigger EventName="DataRequested">
<i:InvokeCommandAction Command="{Binding CommandDataRequestedArticle}" CommandParameter="Hot"/>
</i:EventTrigger>
<i:EventTrigger EventName="RefreshRequested" >
<i:InvokeCommandAction Command="{Binding CommandRefreshRequestedArticle}" CommandParameter="Hot"/>
</i:EventTrigger>
<ec:PropertyChangedTrigger Binding="{Binding IsUIBusy}">
<i:Interaction.Behaviors>
<ec:ConditionBehavior>
<ec:ConditionalExpression>
<ec:ComparisonCondition LeftOperand="{Binding IsUIBusy}" RightOperand="False"/>
</ec:ConditionalExpression>
</ec:ConditionBehavior>
</i:Interaction.Behaviors>
<action:StopPullToRefreshLoadingAction TargetObject="{Binding ElementName=radListBoxHot}"/>
</ec:PropertyChangedTrigger>
</i:Interaction.Triggers> <telerikPrimitives:RadDataBoundListBox.ItemAddedAnimation>
<telerikCore:RadFadeAnimation StartOpacity="0" InitialDelay="0:0:0.3" EndOpacity="1"
Duration="0:0:0.9">
<telerikCore:RadFadeAnimation.Easing>
<CubicEase EasingMode="EaseOut" />
</telerikCore:RadFadeAnimation.Easing>
</telerikCore:RadFadeAnimation>
</telerikPrimitives:RadDataBoundListBox.ItemAddedAnimation>
<telerikPrimitives:RadDataBoundListBox.ItemLoadingTemplate>
<DataTemplate>
<telerikPrimitives:RadBusyIndicator AnimationStyle="AnimationStyle9" IsRunning="{Binding IsUIBusy}" Content="努力加载ing..."/>
</DataTemplate>
</telerikPrimitives:RadDataBoundListBox.ItemLoadingTemplate>
<telerikPrimitives:RadDataBoundListBox.VirtualizationStrategyDefinition>
<telerikPrimitives:StackVirtualizationStrategyDefinition Orientation="Vertical"
/>
</telerikPrimitives:RadDataBoundListBox.VirtualizationStrategyDefinition>
</telerikPrimitives:RadDataBoundListBox> </Grid>
</phone:PivotItem>
ViewModel中要绑定几个command,实现点击项、下拉刷新、自动加载更多等,具体代码就不贴了,主要是根据CommandParameter来区分是触发哪个列表的事件。
这样实现的话,ViewModel中需要有n个ObservableCollection<ArticleItem>,代码重复的太多。
后来用户要求根据设置自定义首页频道,于是要改成后台代码生成的方式。因为首页枢轴里还有几个Pivot项不是文章列表,所以想在Page_Loaded事件中动态去生成所需的Pivot项,并手动设置绑定。
自定义频道的实体类:
/// <summary>
/// 用户固定在首页的自定义频道信息
/// </summary>
public class UserCategoryItem : BindableBase<UserCategoryItem>
{ public UserCategoryItem()
{
ArticleItemList = new ObservableCollection<ArticleListItem>();
TempArticleItemList = new List<ArticleListItem>();
} /// <summary>
/// 频道
/// </summary>
public CategoryItem CurrentCategoryItem
{
get { return _CurrentCategoryItemLocator(this).Value; }
set { _CurrentCategoryItemLocator(this).SetValueAndTryNotify(value); }
}
#region Property CategoryItem CurrentCategoryItem Setup
protected Property<CategoryItem> _CurrentCategoryItem = new Property<CategoryItem> { LocatorFunc = _CurrentCategoryItemLocator };
static Func<BindableBase, ValueContainer<CategoryItem>> _CurrentCategoryItemLocator = RegisterContainerLocator<CategoryItem>("CurrentCategoryItem", model => model.Initialize("CurrentCategoryItem", ref model._CurrentCategoryItem, ref _CurrentCategoryItemLocator, _CurrentCategoryItemDefaultValueFactory));
static Func<CategoryItem> _CurrentCategoryItemDefaultValueFactory = () => { return default(CategoryItem); };
#endregion /// <summary>
/// 上次获取数据最大时间
/// </summary>
public string MaxBehotTime
{
get { return _MaxBehotTimeLocator(this).Value; }
set { _MaxBehotTimeLocator(this).SetValueAndTryNotify(value); }
}
#region Property string MaxBehotTime Setup
protected Property<string> _MaxBehotTime = new Property<string> { LocatorFunc = _MaxBehotTimeLocator };
static Func<BindableBase, ValueContainer<string>> _MaxBehotTimeLocator = RegisterContainerLocator<string>("MaxBehotTime", model => model.Initialize("MaxBehotTime", ref model._MaxBehotTime, ref _MaxBehotTimeLocator, _MaxBehotTimeDefaultValueFactory));
static Func<string> _MaxBehotTimeDefaultValueFactory = () => { return default(string); };
#endregion /// <summary>
/// 最小获取时间
/// </summary>
public string MinBehotTime
{
get { return _MinBehotTimeLocator(this).Value; }
set { _MinBehotTimeLocator(this).SetValueAndTryNotify(value); }
}
#region Property string MinBehotTime Setup
protected Property<string> _MinBehotTime = new Property<string> { LocatorFunc = _MinBehotTimeLocator };
static Func<BindableBase, ValueContainer<string>> _MinBehotTimeLocator = RegisterContainerLocator<string>("MinBehotTime", model => model.Initialize("MinBehotTime", ref model._MinBehotTime, ref _MinBehotTimeLocator, _MinBehotTimeDefaultValueFactory));
static Func<string> _MinBehotTimeDefaultValueFactory = () => { return default(string); };
#endregion /// <summary>
/// 文章内容
/// </summary>
public ObservableCollection<ArticleListItem> ArticleItemList
{
get { return _ArticleItemListLocator(this).Value; }
set { _ArticleItemListLocator(this).SetValueAndTryNotify(value); }
}
#region Property ObservableCollection<ArticleListItem> ArticleItemList Setup
protected Property<ObservableCollection<ArticleListItem>> _ArticleItemList = new Property<ObservableCollection<ArticleListItem>> { LocatorFunc = _ArticleItemListLocator };
static Func<BindableBase, ValueContainer<ObservableCollection<ArticleListItem>>> _ArticleItemListLocator = RegisterContainerLocator<ObservableCollection<ArticleListItem>>("ArticleItemList", model => model.Initialize("ArticleItemList", ref model._ArticleItemList, ref _ArticleItemListLocator, _ArticleItemListDefaultValueFactory));
static Func<ObservableCollection<ArticleListItem>> _ArticleItemListDefaultValueFactory = () => { return new ObservableCollection<ArticleListItem>(); };
#endregion /// <summary>
/// 排序
/// </summary>
public int SortOrder
{
get { return _SortOrderLocator(this).Value; }
set { _SortOrderLocator(this).SetValueAndTryNotify(value); }
}
#region Property int SortOrder Setup
protected Property<int> _SortOrder = new Property<int> { LocatorFunc = _SortOrderLocator };
static Func<BindableBase, ValueContainer<int>> _SortOrderLocator = RegisterContainerLocator<int>("SortOrder", model => model.Initialize("SortOrder", ref model._SortOrder, ref _SortOrderLocator, _SortOrderDefaultValueFactory));
static Func<int> _SortOrderDefaultValueFactory = () => { return default(int); };
#endregion }
在程序首次运行时,如果用户还没有自定义频道,则自动添加默认的,否则从存储中读取,代码写在MainPage.xaml.cs里:
private void MVVMPage_Loaded(object sender, RoutedEventArgs e)
{
if (pivotMain.Items.Count < )
{
MainPage_Model vm = this.LayoutRoot.DataContext as MainPage_Model;
if (vm != null)
{
vm.IsUIBusy = true;
List<UserCategoryItem> listLocal = FileHelper.Open<List<UserCategoryItem>>(Constants.UserCategoryItemListDataFileName);
if(listLocal.Any())
{
listLocal.ForEach(x => vm.UserCategoryItemList.Add(x));
}
if(!vm.UserCategoryItemList.Any())
{
UserCategoryItem item1 = new UserCategoryItem { CurrentCategoryItem = new CategoryItem { Name = "推荐", Category = "" }, SortOrder = };
vm.UserCategoryItemList.Add(item1);
UserCategoryItem item2 = new UserCategoryItem { CurrentCategoryItem = new CategoryItem { Name = "热点", Category = "news_hot" }, SortOrder = };
vm.UserCategoryItemList.Add(item2);
UserCategoryItem item3 = new UserCategoryItem { CurrentCategoryItem = new CategoryItem { Name = "社会", Category = "news_society" }, SortOrder = };
vm.UserCategoryItemList.Add(item3);
UserCategoryItem item4 = new UserCategoryItem { CurrentCategoryItem = new CategoryItem { Name = "娱乐", Category = "news_entertainment" }, SortOrder = };
vm.UserCategoryItemList.Add(item4);
UserCategoryItem item5 = new UserCategoryItem { CurrentCategoryItem = new CategoryItem { Name = "体育", Category = "news_sports" }, SortOrder = };
vm.UserCategoryItemList.Add(item5);
FileHelper.Save<List<UserCategoryItem>>(Constants.UserCategoryItemListDataFileName, vm.UserCategoryItemList.ToList());
} for (int i = ; i < vm.UserCategoryItemList.Count; i++)
{
UserCategoryItem item = vm.UserCategoryItemList[i];
//userCategoryItem.CurrentCategoryItem = new CategoryItem { Category = "", Name = "推荐" };
//vm.UserCategoryItemList.Add(userCategoryItem);
//手工添加pivot项
PivotItem pivot = new PivotItem();
pivot.Header = item.CurrentCategoryItem.Name;
Grid grid = new Grid();
grid.Margin = new Thickness(, -, , );
pivot.Content = grid;
RadDataBoundListBox listBox = new RadDataBoundListBox();
listBox.Name = string.Format("listBox{0}", i);
listBox.UseOptimizedManipulationRouting = false;
listBox.DataVirtualizationMode = DataVirtualizationMode.OnDemandAutomatic;
listBox.IsPullToRefreshEnabled = true;
listBox.IsAsyncBalanceEnabled = true;
listBox.ItemsSource = item.ArticleItemList;
listBox.ItemTemplate = App.Current.Resources["ArticleItemDataTemplate"] as DataTemplate;
listBox.ItemLoadingTemplate = App.Current.Resources["CommonItemLoadingDataTemplate"] as DataTemplate;
//listBox.ListHeaderTemplate = App.Current.Resources["CommonListHeaderDataTemplate"] as DataTemplate;
listBox.SetValue(InteractionEffectManager.IsInteractionEnabledProperty, true);
//listBox.ItemAddedAnimation = App.Current.Resources["CommonItemAddesAnimation"] as RadAnimation;
listBox.VirtualizationStrategyDefinition = new StackVirtualizationStrategyDefinition { Orientation = System.Windows.Controls.Orientation.Vertical };
listBox.Margin = new Thickness(, , , );
listBox.EmptyContentTemplate = App.Current.Resources["CommonEmptyDataTemplate"] as DataTemplate;
//手动添加EventTrigger //设置目标属性
//BindingOperations.SetBinding(selectedItem, TextBlock.TextProperty, binding);
//var invokeCommandAction = new InvokeCommandAction { CommandParameter = "btnAdd" }; var triggers = Interaction.GetTriggers(listBox); //添加ItemTap事件绑定
//#region ItemTap //var itemTapInvokeCommandAction = new InvokeCommandAction(); //// create the command action and bind the command to it
//Binding itemTapParameterBinding = new Binding();
////设置源对象
//itemTapParameterBinding.Source = listBox;
////设置源属性
//itemTapParameterBinding.Path = new PropertyPath("SelectedItem");
////ElementName与Source只能用一个
////itemTapParameterBinding.ElementName = listBox.Name;
//BindingOperations.SetBinding(itemTapInvokeCommandAction, InvokeCommandAction.CommandParameterProperty, itemTapParameterBinding); //var itemTapEventBinding = new Binding { Path = new PropertyPath("CommandNavToArticleDetail") };
//BindingOperations.SetBinding(itemTapInvokeCommandAction, InvokeCommandAction.CommandProperty, itemTapEventBinding); //// create the event trigger and add the command action to it
//var itemTapEventTrigger = new System.Windows.Interactivity.EventTrigger { EventName = "ItemTap" };
//itemTapEventTrigger.Actions.Add(itemTapInvokeCommandAction); //// attach the trigger to the control
//triggers.Add(itemTapEventTrigger);
//#endregion //添加DataRequested事件绑定
#region DataRequested var dataRequestedInvokeCommandAction = new InvokeCommandAction(); // create the command action and bind the command to it
Binding dataRequestedParameterBinding = new Binding();
//设置源对象
dataRequestedParameterBinding.Source = item;
//设置源属性
dataRequestedParameterBinding.Path = new PropertyPath("CurrentCategoryItem");
//dataRequestedParameterBinding.ElementName = listBox.Name;
BindingOperations.SetBinding(dataRequestedInvokeCommandAction, InvokeCommandAction.CommandParameterProperty, dataRequestedParameterBinding); var dataRequestedEventBinding = new Binding { Path = new PropertyPath("CommandDataRequestedArticle") };
BindingOperations.SetBinding(dataRequestedInvokeCommandAction, InvokeCommandAction.CommandProperty, dataRequestedEventBinding); // create the event trigger and add the command action to it
var dataRequestedEventTrigger = new System.Windows.Interactivity.EventTrigger { EventName = "DataRequested" };
dataRequestedEventTrigger.Actions.Add(dataRequestedInvokeCommandAction); // attach the trigger to the control
triggers.Add(dataRequestedEventTrigger);
#endregion //添加RefreshRequested事件绑定
#region RefreshRequested var refreshRequestedInvokeCommandAction = new InvokeCommandAction(); // create the command action and bind the command to it
Binding refreshRequestedParameterBinding = new Binding();
//设置源对象
refreshRequestedParameterBinding.Source = item;
//设置源属性
refreshRequestedParameterBinding.Path = new PropertyPath("CurrentCategoryItem");
//refreshRequestedParameterBinding.ElementName = listBox.Name;
BindingOperations.SetBinding(refreshRequestedInvokeCommandAction, InvokeCommandAction.CommandParameterProperty, refreshRequestedParameterBinding); var refreshRequestedEventBinding = new Binding { Path = new PropertyPath("CommandRefreshRequestedArticle") };
BindingOperations.SetBinding(refreshRequestedInvokeCommandAction, InvokeCommandAction.CommandProperty, refreshRequestedEventBinding); // create the event trigger and add the command action to it
var refreshRequestedEventTrigger = new System.Windows.Interactivity.EventTrigger { EventName = "RefreshRequested" };
refreshRequestedEventTrigger.Actions.Add(refreshRequestedInvokeCommandAction); // attach the trigger to the control
triggers.Add(refreshRequestedEventTrigger);
#endregion #region 下拉刷新完成后停止
PropertyChangedTrigger stopPullToRefreshTrigger = new PropertyChangedTrigger(); Binding pullToRefreshBinding = new Binding();
pullToRefreshBinding.Path = new PropertyPath("IsUIBusy");
//stopPullToRefreshTrigger.SetValue(PropertyChangedTrigger.BindingProperty, pullToRefreshBinding);
//用下面这句不管用
BindingOperations.SetBinding(stopPullToRefreshTrigger, PropertyChangedTrigger.BindingProperty, pullToRefreshBinding); StopPullToRefreshLoadingAction stopPullToRefreshLoadingAction = new StopPullToRefreshLoadingAction();
Binding stopPullToRefreshTargetObjectBinding = new Binding();
stopPullToRefreshTargetObjectBinding.ElementName = listBox.Name;
//stopPullToRefreshLoadingAction.SetValue(StopPullToRefreshLoadingAction.TargetObjectProperty, stopPullToRefreshTargetObjectBinding);
//用下面这句不管用
BindingOperations.SetBinding(stopPullToRefreshLoadingAction, StopPullToRefreshLoadingAction.TargetObjectProperty, stopPullToRefreshTargetObjectBinding); stopPullToRefreshTrigger.Actions.Add(stopPullToRefreshLoadingAction); Binding pullToRefreshBinding2 = new Binding();
pullToRefreshBinding2.Path = new PropertyPath("IsUIBusy");
ComparisonCondition condition = new ComparisonCondition();
BindingOperations.SetBinding(condition, ComparisonCondition.LeftOperandProperty, pullToRefreshBinding2);
condition.RightOperand = false;
condition.Operator = ComparisonConditionType.Equal;
ConditionalExpression expression = new ConditionalExpression();
expression.Conditions.Add(condition);
expression.ForwardChaining = ForwardChaining.And;
ConditionBehavior conditionBehavior = new ConditionBehavior();
conditionBehavior.Condition = expression;
conditionBehavior.Attach(stopPullToRefreshTrigger); triggers.Add(stopPullToRefreshTrigger); #endregion grid.Children.Add(listBox);
this.pivotMain.Items.Insert(i, pivot);
}
vm.IsUIBusy = false; }
}
}
这里主要是用到了在代码中设置绑定的方法,一般要先初始化一个Binding,设置其Path、ElementName、Source等属性,然后调用BindingOperations.SetBinding()方法来进行绑定。主要麻烦的部分是设置EventTrigger的绑定,上面的代码基本是xaml里的绑定用后台代码翻译了一遍。
但这种方式仍然不太好,下个版本再修改一下,改成全部Pivot项都用绑定的方式。
在后台代码中动态生成pivot项并设置EventTrigger和Action的绑定的更多相关文章
- winform WebBrowser控件中,cs后台代码执行动态生成的js
很多文章都是好介绍C# 后台cs和js如何交互,cs调用js方法(js方法必须是页面上存在的,已经定义好的),js调用cs方法, 但如果想用cs里面执行动态生成的js代码,如何实现呢? 思路大致是这样 ...
- 在后台代码中引入XAML的方法
本文将介绍三种方法用于在后台代码中动态加载XAML,其中有两种方法是加载已存在的XAML文件,一种方法是将包含XAML代码的字符串转换为WPF的对象. 一.在资源字典中载入项目内嵌资源中的XAML文件 ...
- 在带(继承)TextView的控件中,在代码中动态更改TextView的文字颜色
今天由于公司项目需求,须要实现一种类似tab的选项卡,当时直接想到的就是使用RadioGroup和RadioButton来实现. 这种方法全然没问题.可是在后来的开发过程中,却遇到了一些困扰非常久的小 ...
- Windows Store App 全球化:在后台代码中引用字符串资源
上文提到了引用字符串资源具有两种方式,分别是在XAML元素中和在后台代码中引用资源文件中的字符串资源.在第一小节已经介绍了如何在XAML元素中引用字符串资源,本小节将讲解在后台代码中引用字符串资源的相 ...
- Android代码中动态设置图片的大小(自动缩放),位置
项目中需要用到在代码中动态调整图片的位置和设置图片大小,能自动缩放图片,用ImageView控件,具体做法如下: 1.布局文件 <RelativeLayout xmlns:android=&qu ...
- 客户端的javascript改变了asp.net webform页面控件的值,后台代码中如何获取修改后的值。
客户端的javascript改变了asp.net webform页面控件的值,后台代码中如何获取修改后的值. 无论是什么的html控件,只要加上了runat="server" ...
- java代码中fastjson生成字符串和解析字符串的方法和javascript文件中字符串和json数组之间的转换方法
1.java代码中fastjson生成字符串和解析字符串的方法 List<TemplateFull> templateFulls = new ArrayList<TemplateFu ...
- ASP.NET WebForm中JavaScript修改了页面上Label的值,如何在后台代码中获取
在用ASP.NET WebForm开发一个项目时,遇到如下的一个情况 页面上有一个Textbox控件,还有2个Label 控件. 当Textbox控件中的值更改时,两个Label控件上的值做相应的更改 ...
- How do I duplicate a resource reference in code behind in WPF?如何在WPF后台代码中中复制引用的资源?
原文 https://stackoverflow.com/questions/28240528/how-do-i-duplicate-a-resource-reference-in-code-behi ...
随机推荐
- DeviceOne 让你一见钟情的App快速开发平台
接触 DeviceOne 要从15年11月开始说起了,因项目和产品时间需求接触了快速开发平台,DeviceOne是非常棒的一个平台,双向数据绑定,可以自定义指令,过滤器等等.总之非常好用完全超出了我们 ...
- Nim教程【十一】
引用类型和指针类型 不同的引用可以只想和修改相同的内存单元 在nim中有两种引用方式,一种是追踪引用,另一种是非追踪引用 非追踪引用也就是指针,指向手动在内存中分配的对象: 追踪引用指向一个垃圾收集的 ...
- Linux vim命令
介绍 vim命令和vi的操作基本一致,vim命令的参数很多,我在这里列出了一些平时需要用的一些参数,vim主要有两个界面一个是esc的操作界面还有一个是输入i的编辑界面. 移动光标 0 (零):将光标 ...
- 虚拟化平台cloudstack(8)——从UI开始
UI ucloudstack采用的是前后端分离的架构,就是说前端可以选择使用web.swing甚至其它的界面,都可以. 我们来看cloudstack的UI信息吧,所有的cloudstack的UI都在{ ...
- ios 向工程里添加Fonts
ios 向工程里添加Fonts 1.网上搜索字体文件(后缀名为.ttf,或.odf),假如你加入的字体为微软雅黑 2.把字体库导入到工程的resouce中 3.然后在你的工程的Info.plist文件 ...
- jsp模仿QQ空间说说的发表
1.在文本域中输入文字(可以不添加) 2.点击添加图片(可以不添加) 3.点击发表 4.发表成功,文字和图片是超链接,点击就可以查看全部内容 5.点击图片查看原图,没有图片则不显示查看原图的超链接 主 ...
- 自己封装个ajax
你是否发现项目中有很多页面只用到了框架不到十分之一的内容,还引了压缩后还有70多kb的jquery库 你是否发现项目中就用了两三个underscore提供的方法,其他大部分的你方法你甚至从来没有看过 ...
- 爱上MVC3~MVC+ZTree实现对树的CURD及拖拽操作
回到目录 上一讲中,我们学习了如何使用zTree对一棵大树(大数据量的树型结构的数据表,呵呵,名称有点绕,但说的是事实)进行异步加载,今天这讲,我们来说说,如何去操作这棵大树,无非就是添加子节点,删除 ...
- 正则表达式匹配/data/misc/wifi/wpa_supplicant.conf的WiFi名称与密码
正则表达式匹配/data/misc/wifi/wpa_supplicant.conf的WiFi名称与密码: String regex_name="ssid=\"(.*?)\&quo ...
- python 多线程网络编程 ( 二 )
背景 我在[第一篇文章中]已经介绍了如何实现一个多线程的todo应用,接下来我将会研究如何使这个服务器完成下面这几个功能. 1.使用正则表达式解析用户发送的请求数据: 2.使用ThreadLocal技 ...