zoukankan      html  css  js  c++  java
  • 在后台代码中动态生成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项都用绑定的方式。

  • 相关阅读:
    我最讨厌画图,这辈子我都不想再画图
    bzoj1218[HNOI2003]激光炸弹
    bzoj1196[HNOI2006]公路修建问题
    bzoj1588[HNOI2002]营业额统计
    bzoj2039[2009国家集训队]employ人员雇佣
    bzoj3874[Ahoi2014]宅男计划
    bzoj2282[Sdoi2011]消防
    bzoj1798[Ahoi2009]Seq 维护序列seq
    bzoj4003[JLOI2015]城池攻占
    bzoj2809[Apio2012]dispatching
  • 原文地址:https://www.cnblogs.com/yanxiaodi/p/4237576.html
Copyright © 2011-2022 走看看