【问题标题】:Object property databinding to a collection item based on a Name of an object对象属性数据绑定到基于对象名称的集合项
【发布时间】:2011-06-24 09:26:12
【问题描述】:

是否可以实现以下 WPF (Silverlight) 数据绑定方案?

一个页面上有许多CustomControls:

<Grid x:Name="grid1">
  ...
  <My:CustCntr x:Name="name1" Property1="{Binding Property1}" />
  <My:CustCntr x:Name="name2" Property1="{Binding Property1}" />
  <My:CustCntr x:Name="name3" Property1="{Binding Property1}" />
  ...
</Grid>

Grid 的 DataContext 是一个 ObservableCollection:

grid1.DataContext = myCollection;
...
ObservableCollection<MyEntity> myCollection= new ObservableCollection<MyEntity>();
...

MyEntity 类具有属性NameProperty1

 MyEntity me1 = new MyEntity { Name = "name1", Property1 = "5" };      
 MyEntity me2 = new MyEntity { Name = "name2", Property1 = "6" };
 MyEntity me3 = new MyEntity { Name = "name3", Property1 = "7" }; 
 ... 
 myCollection.Add(me1); 
 myCollection.Add(me2);
 myCollection.Add(me3); 
 ...    

我能否将每个 CustomControl 中的 Property1 数据绑定到 myCollection 的相应项,其中 CustomControl 的 Name 等于集合项的 Name 字段的值?

【问题讨论】:

  • 我对 ItemsControl 有所了解,但我需要更多信息: 1. 如何使用 x:Name 属性? 2. Grid控件是必须的还是可以用StackPanel代替?
  • @vorrtex 1. CustomControls 的 x:Name 属性用于在代码中识别和处理它们。 2. 我明白你的意思。不,布局可能比仅使用这样的 Grid 复杂得多。所以,用 StackPanel 代替它是不可能的。
  • 是否需要 Xaml 绑定或者后面的代码可以吗?因为我在 Xaml 中看不到任何这样做的方法
  • @Meleak 我现在正在代码中更新它们,使用FrameworkElement.FindName(string name) 构造。只是想以更 WPF 的方式对其进行优化。所以,如果它是一种数据绑定方式,那么我认为它可以在代码中。
  • 所以页面上的控件数量是恒定的,对吧?因为否则使用 Name 属性是没有意义的。在这种情况下,我可以使用 linq 在代码隐藏中设置绑定。

标签: c# wpf silverlight data-binding observablecollection


【解决方案1】:

通常情况下,如果您有想要在 UI 上显示的集合,您会使用ItemsControlListBox 等,并将 ItemsSource 设置为集合。示例

<ItemsControl Name="itemsControl1"
              ItemsSource="{Binding MyCollection}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <My:CustCntr Property1="{Binding Property1}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

现在每个CustCntr 的DataContext 将是MyEntity 的一个实例,并且绑定将设置在CustCntr.Property1MyEntity.Property1 之间


也就是说,我不确定您当前实现的原因,所以如果您想根据名称创建绑定,我认为您将不得不求助于代码

Xaml

<Grid Name="grid1" Loaded="Grid_Loaded">
    <My:CustCntr x:Name="name1" />
    <My:CustCntr x:Name="name2" />
    <My:CustCntr x:Name="name3" />
    <!--...-->
</Grid>

背后的代码

public ObservableCollection<MyEntity> MyCollection
{
    get;
    private set;
}

更新
每次在代码中修改集合时调用此方法 SetBindings。此外,请使用 Grid 的 Loaded 事件来设置第一次加载时的所有绑定。

private void Grid_Loaded(object sender, RoutedEventArgs e)
{
    SetBindings();
}
private void SetBindings()
{
    foreach (UIElement element in grid1.Children)
    {
        if (element is CustCntr)
        {
            CustCntr custCntr = element as CustCntr;
            foreach (MyEntity myEntity in MyCollection)
            {
                if (custCntr.Name == myEntity.Name)
                {
                    Binding property1Binding = new Binding("Property1");
                    property1Binding.Source = myEntity;
                    property1Binding.Mode = BindingMode.TwoWay;
                    custCntr.SetBinding(CustCntr.Property1Property, property1Binding);
                    break;
                }
            }
        }
    }
}

【讨论】:

  • 有用的答案!我不知道在代码中设置 WPF 绑定的可能性。所以,这对我很有帮助。谢谢! +1。虽然,我尝试实现这种方法,但我的自定义控件只更新了一次 - 最初。当我进一步尝试更新源集合时,什么都没有发生,也没有更新控件。也许 property1Binding.Source = myEntity; 不足以让 Binding 记住集合中 custCntr.Name == myEntity.Name 所在的特定项目?
  • @rem:Property1 是依赖属性吗?否则,MyEntity 类是否实现了 INotifyPropertyChanged,Property1 是否在 setter 中引发 PropertyChanged?在这种情况下,绑定应该双向工作。如果您对源集合进行更改,例如添加/删除,那么您将在 UI 中的自定义控件与集合之间不匹配。您能否添加更多关于此的信息?
  • @Meleak 感谢您的帮助!是的,Property1 是一个依赖属性。正如您所建议的,MyEntity 实际上并没有实现INotifyPropertyChanged。我现在已经实现了它,但到目前为止还没有成功。因此,关于您关于自定义控件和集合之间可能不匹配的注释:事实上,现在通过删除所有项目并添加相同的项目集合但具有新值来更新集合。这可能是问题的原因吗?
  • @rem:好的,如果它是一个依赖属性,您不需要引发 PropertyChanged 事件,这样应该没问题。如果重新添加控件,它们应该再次引发 Loaded 事件。您可以通过在CustCntr_Loaded 事件处理程序中添加断点来验证这一点吗?它会被击中吗?此外,请确保源集合包含匹配项,然后再重新添加它们
  • @Meleak 抱歉,我之前的评论似乎有点不清楚。删除和重新添加的不是 CustomControls。 ObservableCollection MyCollection 被完全清除,然后用相同数量的记录重新填充,但使用新值。我怀疑可能是因为MyCollection DataBinding 的重新填充可能无法正常工作?
【解决方案2】:

不,那是不可能的。 但是,您可以使用 ItemsControl 对象(有多个控件继承自它),但那时设置设计可能会更加困难。不是针对单个控件,而是针对每个 CustCntr 的放置。

【讨论】: