最近在做今日头条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的绑定的更多相关文章

  1. winform WebBrowser控件中,cs后台代码执行动态生成的js

    很多文章都是好介绍C# 后台cs和js如何交互,cs调用js方法(js方法必须是页面上存在的,已经定义好的),js调用cs方法, 但如果想用cs里面执行动态生成的js代码,如何实现呢? 思路大致是这样 ...

  2. 在后台代码中引入XAML的方法

    本文将介绍三种方法用于在后台代码中动态加载XAML,其中有两种方法是加载已存在的XAML文件,一种方法是将包含XAML代码的字符串转换为WPF的对象. 一.在资源字典中载入项目内嵌资源中的XAML文件 ...

  3. 在带(继承)TextView的控件中,在代码中动态更改TextView的文字颜色

    今天由于公司项目需求,须要实现一种类似tab的选项卡,当时直接想到的就是使用RadioGroup和RadioButton来实现. 这种方法全然没问题.可是在后来的开发过程中,却遇到了一些困扰非常久的小 ...

  4. Windows Store App 全球化:在后台代码中引用字符串资源

    上文提到了引用字符串资源具有两种方式,分别是在XAML元素中和在后台代码中引用资源文件中的字符串资源.在第一小节已经介绍了如何在XAML元素中引用字符串资源,本小节将讲解在后台代码中引用字符串资源的相 ...

  5. Android代码中动态设置图片的大小(自动缩放),位置

    项目中需要用到在代码中动态调整图片的位置和设置图片大小,能自动缩放图片,用ImageView控件,具体做法如下: 1.布局文件 <RelativeLayout xmlns:android=&qu ...

  6. 客户端的javascript改变了asp.net webform页面控件的值,后台代码中如何获取修改后的值。

    客户端的javascript改变了asp.net webform页面控件的值,后台代码中如何获取修改后的值.     无论是什么的html控件,只要加上了runat="server" ...

  7. java代码中fastjson生成字符串和解析字符串的方法和javascript文件中字符串和json数组之间的转换方法

    1.java代码中fastjson生成字符串和解析字符串的方法 List<TemplateFull> templateFulls = new ArrayList<TemplateFu ...

  8. ASP.NET WebForm中JavaScript修改了页面上Label的值,如何在后台代码中获取

    在用ASP.NET WebForm开发一个项目时,遇到如下的一个情况 页面上有一个Textbox控件,还有2个Label 控件. 当Textbox控件中的值更改时,两个Label控件上的值做相应的更改 ...

  9. 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 ...

随机推荐

  1. 人人都是 DBA(I)SQL Server 体系结构

    在了解 SQL Server 数据库时,可以先从数据库的体系结构来观察.SQL Server 的体系结构中包含 4 个主要组成部分: 协议层(Protocols) 关系引擎(Relational En ...

  2. PSP记录个人项目耗时

    PSP2.1 Personal Software Process Stage Time Planning 计划 90 ·Estimate ·估计这个任务需要多长时间 90 Development 开发 ...

  3. 记录maven java.lang.String cannot be cast to XX error

    在项目开发中自定义了一个maven plugin,在本地能够很好的工作,但是在ci server上却无法正常工作报错为: --------------------------------------- ...

  4. 谈谈javascript语法里一些难点问题(一)

    1)    引子 前不久我建立的技术群里一位MM问了一个这样的问题,她贴出的代码如下所示: var a = 1; function hehe() { window.alert(a); var a = ...

  5. RabbitMQ(五) -- topics

    RabbitMQ(五) -- topics `rabbitmq`中的`topic exchange`将路由键和某模式进行匹配,从而类似于正则匹配的方式去接收喜欢的信息. topic exchange ...

  6. jQuery.width()和jQuery.css('width')的区别

    [TOC] 问题描述 使用jQuery修改一个div的宽度时,发现$($0).width('10rem')总是修改成不正确的值,然后使用$($0).css('width', '10rem')时却能正确 ...

  7. java Decompiler的bug

    java Decompiler 有一个明显的bug是, 之前的打开jar文件,会被缓存起来,如果再次打开同名jar文件(jar内容替换~!),会导致仍然显示原来内容! . 必须关闭Decompiler ...

  8. vs2013中的“任务列表”菜单

    以前在java项目中经常用到todo. 现在vs2013也完美支持了. 首先,对于目前不确定而尚需完善的代码,在前面加 //TODO:by who --注释文字,比如: //TODO:lhl--类目I ...

  9. .NetCore~Linux环境下部署

    NetCore正式版已经出现有段时候了,Windows下使用vs2015开发.netCore应用程序,然后通过dotnet程序开启WEB服务,用着很像node.js,当然我们不会于只局限于window ...

  10. Dubbo的使用及原理浅析.

    前面几个博文中关于SSM 框架已经搭建完成, 这里来讲下项目中使用到的Dubbo以及自己了解到的关于Dubbo的一些知识. Dubbo是什么? Dubbo是阿里巴巴SOA服务化治理方案的核心框架,每天 ...