在后台代码中动态生成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 < 3)
            {
                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 = 0 };
                        vm.UserCategoryItemList.Add(item1);
                        UserCategoryItem item2 = new UserCategoryItem { CurrentCategoryItem = new CategoryItem { Name = "热点", Category = "news_hot" }, SortOrder = 1 };
                        vm.UserCategoryItemList.Add(item2);
                        UserCategoryItem item3 = new UserCategoryItem { CurrentCategoryItem = new CategoryItem { Name = "社会", Category = "news_society" }, SortOrder = 2 };
                        vm.UserCategoryItemList.Add(item3);
                        UserCategoryItem item4 = new UserCategoryItem { CurrentCategoryItem = new CategoryItem { Name = "娱乐", Category = "news_entertainment" }, SortOrder = 3 };
                        vm.UserCategoryItemList.Add(item4);
                        UserCategoryItem item5 = new UserCategoryItem { CurrentCategoryItem = new CategoryItem { Name = "体育", Category = "news_sports" }, SortOrder = 4 };
                        vm.UserCategoryItemList.Add(item5);
                        FileHelper.Save<List<UserCategoryItem>>(Constants.UserCategoryItemListDataFileName, vm.UserCategoryItemList.ToList());
                    }

                    for (int i = 0; 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(0, -12, 0, 0);
                        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(12, 0, 0, 0);
                        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项都用绑定的方式。

时间: 2024-10-20 11:14:14

在后台代码中动态生成pivot项并设置EventTrigger和Action的绑定的相关文章

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

很多文章都是好介绍C# 后台cs和js如何交互,cs调用js方法(js方法必须是页面上存在的,已经定义好的),js调用cs方法, 但如果想用cs里面执行动态生成的js代码,如何实现呢? 思路大致是这样的,cs动态插入js到html上,cs执行html插入的js方法代码. 封装好的方法: /// <summary> /// webbrowser执行脚本 /// </summary> /// <param name="web">传入WebBrowser 

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

原文:在后台代码中引入XAML的方法 本文将介绍三种方法用于在后台代码中动态加载XAML,其中有两种方法是加载已存在的XAML文件,一种方法是将包含XAML代码的字符串转换为WPF的对象. 一.在资源字典中载入项目内嵌资源中的XAML文件 Application.Current.Resources.MergedDictionaries.Insert(0, Application.LoadComponent(new Uri("abc/Index.xaml", UriKind.Relati

element-UI,根据后台数据、动态生成el-checkbox-group,点击提交获取绑定checked项以及实现显示默认checked项

<template> <div id="Demo"> <el-form ref="form" label-width="100px"> <el-form-item label="设备名称"> <div class="check-group" v-for="(item, index) in equipments" :key="

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

今天由于公司项目需求,须要实现一种类似tab的选项卡,当时直接想到的就是使用RadioGroup和RadioButton来实现. 这种方法全然没问题.可是在后来的开发过程中,却遇到了一些困扰非常久的小困难.大概需求是:在代码中.动态的获取tab的个数,然后初始化RadioGroup,每个tab相应一个RadioButton,即加入一个tab就要向RadioGroup中add一个RadioButton,然后在button选中时要更改文字颜色.由于是动态加入,所以无法在xml中配置了RadioBut

在Vue项目中动态生成二维码 阿星小栈

一.使用jquery.qrcode生成二维码 1.首先在页面中加入jquery库文件和qrcode插件 <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="jquery.qrcode.min.js"></script> 2.在页面中需要显示二维码的

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

上文提到了引用字符串资源具有两种方式,分别是在XAML元素中和在后台代码中引用资源文件中的字符串资源.在第一小节已经介绍了如何在XAML元素中引用字符串资源,本小节将讲解在后台代码中引用字符串资源的相关知识点. 下面通过一个示例直接讲述如何在后台代码中引用资源文件中的字符串资源.新建一个Windows应用商店的空白应用程序项目,并命名为StringResourcesInCode.在项目中新建一个名为"Strings"的文件夹,在"Strings"文件夹下新建名为&q

Java中动态生成当前日期的文件

1.Java中动态生成当前日期的文件名称并且将控制台的输出信息输入到文件中     public static void SaveClonseToFile() throws IOException, FileNotFoundException {         File f = new File(getCurrentDateFileName() + ".txt");         f.createNewFile();         FileOutputStream fileOut

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

在用ASP.NET WebForm开发一个项目时,遇到如下的一个情况 页面上有一个Textbox控件,还有2个Label 控件. 当Textbox控件中的值更改时,两个Label控件上的值做相应的更改, 这一点是通过页面中嵌入的JavaScript来实现的. 但是,Label控件上的值更改后,在后端.cs代码中,通过Label.Text 并不能取到更改后的值. order.aspx页面代码如下: <%@ Page Language="C#" AutoEventWireup=&qu

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

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