【问题标题】:BindingCustom controls to List<T>BindingCustom 控件到 List<T>
【发布时间】:2013-11-23 18:25:20
【问题描述】:

我有一个自定义控件 - 联系人卡片:

<Grid>
    <Grid.Background>
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
            <GradientStop Color="#FFD8B8EA"/>
            <GradientStop Color="White" Offset="1"/>
        </LinearGradientBrush>
    </Grid.Background>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Image Source="images.jpg" />
    <StackPanel Grid.Column="1">
        <TextBlock Text="{Binding Path=name}" Foreground="Black" FontSize="20" />
        <TextBlock Text="{Binding Path=surname}" Foreground="Black" FontSize="20" />
    </StackPanel>
</Grid>

还有一个可以容纳 4 张卡片的容器(也是一个自定义用户控件):

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <StackPanel x:Name="FirstItem" Grid.Column="0" Grid.Row="0"/>
    <StackPanel x:Name="SecondItem" Grid.Column="0" Grid.Row="1"/>
    <StackPanel x:Name="ThirdItem" Grid.Column="1" Grid.Row="0"/>
    <StackPanel x:Name="FourthItem" Grid.Column="1" Grid.Row="1"/>
</Grid>

这是我的对象类:

class FullObject
{
    public string UpdateTime { get; set; }
    public List<Contact> contacts { get; set; }
    public List<Region> regions { get; set; }
}

我遇到的问题是列表

FullObject 数据来自 JSON 格式的服务,所以我这样做:

FullObjectt = JsonConvert.DeserializeObject<FullObject>(result);

然后用这样的卡片填充我的 FlipView:

FourItems FI = new FourItems();
        for (int i = 0; i < 4; i++)
        {
            ContactCard CC = new ContactCard();
            CC.DataContext = FullObjects.contacts[i];
            if (i == 0)
            {
                FI.FirstItem.Children.Add(CC);
            }
            else if (i == 1)
            {
                FI.SecondItem.Children.Add(CC);
            }
            else if (i == 2)
            {
                FI.ThirdItem.Children.Add(CC);
            }
            else
            {
                FI.FourthItem.Children.Add(CC);
                FlipView.Items.Add(FI);
            }
        }

看起来像这样:

当我收到通知时,我从服务器获得了一些联系人数据已更改的列表,其中仅包含更改的联系人。所以我会在我当前加载的 FullObject 中找到更改后的联系人并将其替换为新联系人:

我们以第一个联系人姓名已更改为例

I will do this:

Contact new = JsonConvert.DeserializeObject<Contact>(result);
FullObjectt.contacts[0]=new;

但在我重置数据上下文之前,我的卡数据不会改变。有没有办法在我这样做时让 ContactCard 更新数据?:

Contact new = JsonConvert.DeserializeObject<Contact>(result);
FullObjectt.contacts[0]=new;

我尝试将 List 更改为 ObservableCollection,但失败了,有人可以指导我吗?

编辑:

我已将 FullObject 类中的 List 更改为 ObservableCollection:

class FullObject : INotifyCollectionChanged 
{
    public string spTimestamp { get; set; }
    public ObservableCollection<Contact> contacts { get; set; }
    public string scTimestamp { get; set; }
    public List<Region> regions { get; set; }

}

然后点击按钮(只是为了测试):

private void Button_Click(object sender, RoutedEventArgs e)
    {
        FullObjects.contacts[0] = new Contact();
    }

而且它不会更新卡片...

【问题讨论】:

  • 您用INotifyPropertyChanged 标记了您的问题,所以我想您知道这一点。这就是答案,您应该通过引发 INPC 的 PropertyChanged 事件来通知 UI。
  • 但问题是我没有更改 FullObjectt.contacts[0] 属性,我用新对象替换了该对象,因此不会引发 PropertyChanged
  • ObservableCollection 应该可以正常工作。重新设置时是否遇到任何错误?
  • 说实话,我不知道如何重建我的代码以使其成为 ObservableCollection,我是否应该将 List 更改为 ObservableCollection,如下所示:class FullObject { public string spTimestamp { get;放; } 公共 ObservableCollection 联系人 { 获取;放; } 公共字符串 scTimestamp { 获取;放; } 公共列表 区域 { 获取;放; } }
  • 是的,就是这样。不工作吗?

标签: c# xaml data-binding datacontext inotifypropertychanged


【解决方案1】:

问题在于您创建 FourItems 视图的方式。在这一行 -

ContactCard CC = new ContactCard();
CC.DataContext = FullObjects.contacts[i];
if (i == 0)
{
   FI.FirstItem.Children.Add(CC);
}

您正在为 ContactCard 显式设置 DataContext,后来将其完全更改为新引用,除非您手动重置 DataContext,否则显然不会反映在 UI 上。

相反,您应该有一个ItemsControl 并将其ItemsSource 直接绑定到Contacts ObservableCollection。您可以定义 itemsControl 的ItemTemplate 来表示一个 ContactCard。这样,您将收到 CollectionChanged 可观察集合的通知,并且 UI 将自动更新。

View 持有四个控件(摆脱堆栈面板)-

<Grid>
   <ItemsControl x:Name="ContactItems">
       <ItemsControl.ItemsPanel>
          <ItemsPanelTemplate>
              <UniformGrid Columns="2"/>
          </ItemsPanelTemplate>
       </ItemsControl.ItemsPanel>
       <ItemsControl.ItemTemplate>
           <DataTemplate>
               <local:ContactCard/> <-- Declare local namespace in XAML where 
                                        ContactCard control is declared.
           </DataTemplate>
       </ItemsControl.ItemTemplate>
   </ItemsControl>
</Grid>

并且填充代码应该是这样的 -

FourItems FI = new FourItems();
FI.ContactItems.ItemsSource = FullObjects.contacts;
FlipView.Items.Add(FI);

现在,集合联系人中的任何更新都将被 ItemsControl 监听,因为它已绑定到它,并且您的 UI 将相应更新。确保联系人是ObservableCollection

【讨论】:

  • FI.ContactItems.ItemsSource = FullObjects.contacts;这是为了以防我的收藏中有 4 件物品,但如果我有 100 件以上?但我只想在 Flip Viev 的页面上显示
  • 您只能像这样绑定到您的收藏中的四个项目 - FullObjects.contacts.Take(4)。您也可以拥有另一个包装器 ObservableCollection,它只包含列表中的前四项。绑定 ItemSource 完全掌握在您手中。希望你能在这里得到精髓。
  • 但是当我设置 Take(4) 时它没有得到通知
  • @Cheese - 这只是一个想法。你必须像我之前提到的那样创建包装器ObservableCollection,如果你想有通知,它将有四个项目。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-16
  • 1970-01-01
  • 1970-01-01
  • 2019-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多