locked
(WP8.1)关于Hub中添加ListView控件的数据绑定 RRS feed

  • 问题

  • 直接上代码:

     <Hub Header="Hub" x:Name="hub">
                <HubSection Header="HubSection 0">
                    <DataTemplate>
                        <Grid x:Name="hubsection">
                            <ListView x:Name="lv">
                                <ListView.ItemTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding StoryName}"/>
                                        
                                    </DataTemplate>
                                </ListView.ItemTemplate>
                            </ListView>
                        </Grid>
                    </DataTemplate>
                </HubSection>
                <HubSection Header="HubSection 1">
                    <DataTemplate>
                        <Grid/>
                    </DataTemplate>
                </HubSection>
            </Hub>

    现在的问题是,在后台不能用this.lv.ItemsSource和this.hubsection.DataContext来绑定数据;

    如何将数据绑定到ListView控件上?

    2016年1月29日 10:07

答案

  • 这个极有可能是你的代码逻辑为:进入该页面时加载数据,集合里的数据造成重复。

    P.S:你的 lv.ItemSource 应该是一个 ObservableCollection<T> (通常来说绑定到 ListView 的都是这个类型)。假定你的 lv.ItemSource ObservableCollection<MyData> _mySource;

    解决方法

    方法①在加载数据时,你的 _mySource 一般来说都要通过 _mySource.Add(data) 等操作添加数据,在所有向 _mySource 添加数据时都先判断数据是否已存在。为了方便,这里你可以写一些 ObservableCollection<T> 的扩展方法,比如我的项目中用的(仅供参考):

        /// <summary>
        /// 提供 <see cref="ObservableCollection{T}"/> 扩展方法的类。
        /// </summary>
        public static class ObservableCollectionExtension
        {
            /// <summary>
            /// 将整个 <see cref="ObservableCollection{T}"/> 添加到目标 <see cref="ObservableCollection{T}"/> 中。
            /// </summary>
            /// <typeparam name="T">集合中的元素类型。</typeparam>
            /// <param name="source"><see cref="ObservableCollection{T}"/> 源。</param>
            /// <param name="target">目标 <see cref="ObservableCollection{T}"/>。</param>
            public static void AddTo<T>(this ObservableCollection<T> source, ObservableCollection<T> target)
            {
                foreach (var item in source)
                {
                    if (item != null && !target.Contains(item))
                    {
                        target.Add(item);
                    }
                }
            }
    
            /// <summary>
            /// 将指定集合的元素插入到 <see cref="ObservableCollection{T}"/> 的指定索引处。
            /// </summary>
            /// <typeparam name="T">集合中的元素类型。</typeparam>
            /// <param name="source"><see cref="ObservableCollection{T}"/> 源。</param>
            /// <param name="collection">应将其元素添加到 <see cref="ObservableCollection{T}"/> 的指定索引处的集合。</param>
            public static void InsertRange<T>(this ObservableCollection<T> source, int index, IEnumerable<T> collection)
            {
                foreach (var item in collection)
                {
                    if (item != null && !source.Contains(item))
                    {
                        source.Insert(index++, item);
                    }
                }
            }
    
            /// <summary>
            /// 清除集合中的所有 <see cref="null"/> 对象。
            /// </summary>
            /// <typeparam name="T">集合中的元素类型。</typeparam>
            /// <param name="source"><see cref="ObservableCollection{T}"/> 源。</param>
            public static void ClearNull<T>(this ObservableCollection<T> source)
            {
                int index = 0;
                foreach (var item in source)
                {
                    if (item == null)
                    {
                        source.RemoveAt(index);
                    }
                    index++;
                }
            }
        }
    

    当然,你也可以选择不这样做,直接每次添加完数据后再清理掉重复的数据:

    _mySource.Distinct(); //这是.Net 自带的扩展方法,用于去除集合中重复的元素。

    注意注意注意:如果你的数据是自定义的类(或者结构体),那么你一定一定要记得给这个类(结构体)重写 Equals(obj)、GetHashCode(),不然这个 Distinct() 方法不一定能真正去除重复的元素,因为它不知道怎么样去判断元素之间是不是一样的。

    比如你的数据是一个 Person 类。成员有:String Name;     String Id;     uint Age;

    public override bool Equals(object obj)
    {
            return this.Id == ((Person)obj).Id;
    }
    
    public override int GetHashCode()
    {
            return this.Id.GetHashCode();
    }
    
    // 作为习惯,ToString 也重写了。
    public override string ToString()
    {
            return this.Name;
    }

    方法②:进入该页面时,在加载数据前先清空 _mySource

    • 已标记为答案 learn WP 2016年2月10日 9:39
    2016年2月4日 14:16

全部回复

  • 能通过前台实现绑定的我都不喜欢在后台绑定!!!x3

    注意:<DataTemplate> 中的成员是无法在后台访问的,你可以在 <DataTemplate> 的上级绑定数据源,类似这样(注意,现在我已经不用 WP8/8.1 了,所以这样写失败了记得通知我!!!):

    <Hub Header="Hub" x:Name="hub">
                <HubSection Header="HubSection 0" DataContext="{Binding xxx}">
                    <DataTemplate>
                        <Grid x:Name="hubsection">
                            <ListView x:Name="lv">
                                <ListView.ItemTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding StoryName}"/>
                                        
                                    </DataTemplate>
                                </ListView.ItemTemplate>
                            </ListView>
                        </Grid>
                    </DataTemplate>
                </HubSection>
                <HubSection Header="HubSection 1">
                    <DataTemplate>
                        <Grid/>
                    </DataTemplate>
                </HubSection>
            </Hub>



    2016年1月30日 3:39
  • 您好,

    如果你给Hub指定了数据上下文,并在它的DataTemplate中放了一个ListView,那么在给ListView指定数据源时需要从它的数据上下文中获取,在代码中也就是DataContext,而你给Hub指定了DataContext,那么你就得绑定这个数据上下文中的属性值作为ListView的数据源,下面是我的代码,供你参考:

    <Hub Header="Hub" x:Name="hub">
                <HubSection Header="HubSection 0">
                    <DataTemplate>
                        <Grid x:Name="hubsection">
                            <ListView x:Name="lv" ItemsSource="{Binding mysource}">
                                <ListView.ItemTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding StoryName}"/>
                                    </DataTemplate>
                                </ListView.ItemTemplate>
                            </ListView>
                        </Grid>
                    </DataTemplate>
                </HubSection>
                <HubSection Header="HubSection 1">
                    <DataTemplate>
                        <Grid/>
                    </DataTemplate>
                </HubSection>
            </Hub>
     public sealed partial class MainPage : Page
        {
            public ObservableCollection<Test> mysource { get; set; }
            public MainPage()
            {
                this.InitializeComponent();
                mysource = new ObservableCollection<Test>();
                mysource.Add(new Test() {StoryName="abc" });
                mysource.Add(new Test() { StoryName = "def" });
                hub.DataContext = this;
            }
        }
    
        public class Test
        {
             public string StoryName { get; set; }
        }



    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    2016年2月2日 6:03
  • 应用这种方法后,

    第一次载入Hub中心内的ListView控件,显示正常,如下:

    abc

    def

    导航到其它页面后,再返回后,会重复显示集合中的数据,如下:

    abc

    def

    abc

    def

    如果再进入其它页面然后再返回,又会多加载一次,一直累加,这是为什么?

    abc

    def

    ...

    2016年2月4日 12:14
  • 这个极有可能是你的代码逻辑为:进入该页面时加载数据,集合里的数据造成重复。

    P.S:你的 lv.ItemSource 应该是一个 ObservableCollection<T> (通常来说绑定到 ListView 的都是这个类型)。假定你的 lv.ItemSource ObservableCollection<MyData> _mySource;

    解决方法

    方法①在加载数据时,你的 _mySource 一般来说都要通过 _mySource.Add(data) 等操作添加数据,在所有向 _mySource 添加数据时都先判断数据是否已存在。为了方便,这里你可以写一些 ObservableCollection<T> 的扩展方法,比如我的项目中用的(仅供参考):

        /// <summary>
        /// 提供 <see cref="ObservableCollection{T}"/> 扩展方法的类。
        /// </summary>
        public static class ObservableCollectionExtension
        {
            /// <summary>
            /// 将整个 <see cref="ObservableCollection{T}"/> 添加到目标 <see cref="ObservableCollection{T}"/> 中。
            /// </summary>
            /// <typeparam name="T">集合中的元素类型。</typeparam>
            /// <param name="source"><see cref="ObservableCollection{T}"/> 源。</param>
            /// <param name="target">目标 <see cref="ObservableCollection{T}"/>。</param>
            public static void AddTo<T>(this ObservableCollection<T> source, ObservableCollection<T> target)
            {
                foreach (var item in source)
                {
                    if (item != null && !target.Contains(item))
                    {
                        target.Add(item);
                    }
                }
            }
    
            /// <summary>
            /// 将指定集合的元素插入到 <see cref="ObservableCollection{T}"/> 的指定索引处。
            /// </summary>
            /// <typeparam name="T">集合中的元素类型。</typeparam>
            /// <param name="source"><see cref="ObservableCollection{T}"/> 源。</param>
            /// <param name="collection">应将其元素添加到 <see cref="ObservableCollection{T}"/> 的指定索引处的集合。</param>
            public static void InsertRange<T>(this ObservableCollection<T> source, int index, IEnumerable<T> collection)
            {
                foreach (var item in collection)
                {
                    if (item != null && !source.Contains(item))
                    {
                        source.Insert(index++, item);
                    }
                }
            }
    
            /// <summary>
            /// 清除集合中的所有 <see cref="null"/> 对象。
            /// </summary>
            /// <typeparam name="T">集合中的元素类型。</typeparam>
            /// <param name="source"><see cref="ObservableCollection{T}"/> 源。</param>
            public static void ClearNull<T>(this ObservableCollection<T> source)
            {
                int index = 0;
                foreach (var item in source)
                {
                    if (item == null)
                    {
                        source.RemoveAt(index);
                    }
                    index++;
                }
            }
        }
    

    当然,你也可以选择不这样做,直接每次添加完数据后再清理掉重复的数据:

    _mySource.Distinct(); //这是.Net 自带的扩展方法,用于去除集合中重复的元素。

    注意注意注意:如果你的数据是自定义的类(或者结构体),那么你一定一定要记得给这个类(结构体)重写 Equals(obj)、GetHashCode(),不然这个 Distinct() 方法不一定能真正去除重复的元素,因为它不知道怎么样去判断元素之间是不是一样的。

    比如你的数据是一个 Person 类。成员有:String Name;     String Id;     uint Age;

    public override bool Equals(object obj)
    {
            return this.Id == ((Person)obj).Id;
    }
    
    public override int GetHashCode()
    {
            return this.Id.GetHashCode();
    }
    
    // 作为习惯,ToString 也重写了。
    public override string ToString()
    {
            return this.Name;
    }

    方法②:进入该页面时,在加载数据前先清空 _mySource

    • 已标记为答案 learn WP 2016年2月10日 9:39
    2016年2月4日 14:16
  • 谢谢你的回复
    2016年2月10日 9:43