1

我有一个 MainWindow.xaml 文件:

<Window.Resources>

  <CollectionViewSource x:Key="cvs" 
    Source="{Binding Source={StaticResource ResourceKey=DetailsCollection}}" />

  <CollectionViewSource x:Key="DetailScopes">
    <CollectionViewSource.Source>
      <ObjectDataProvider 
        MethodName="GetValues" 
        ObjectType="{x:Type system:Enum}">
        <ObjectDataProvider.MethodParameters>
          <x:Type TypeName="entities:DetailScope" />
        </ObjectDataProvider.MethodParameters>
      </ObjectDataProvider>
    </CollectionViewSource.Source>
  </CollectionViewSource>

  <DataTemplate x:Key="AccountDetail"
    DataType="{x:Type entities:AccountDetail}">
    <DockPanel>
      <ComboBox 
        DockPanel.Dock="Left" 
        ItemsSource="{Binding Source={StaticResource ResourceKey=DetailScopes}}" 
        SelectedItem="{Binding Path=Scope}">
        <ComboBox.ItemTemplate>
          <DataTemplate>
            <TextBlock 
              Text="{Binding Converter={StaticResource DetailScopeConverter}}" />
          </DataTemplate>
        </ComboBox.ItemTemplate>
      </ComboBox>
      <TextBox Text="{Binding Path=Value}" />
    </DockPanel>
  </DataTemplate>

</Window.Resources>

...

<ListBox 
  ItemTemplate="{StaticResource ResourceKey=AccountDetail}" 
  ItemsSource="{Binding Source={StaticResource ResourceKey=cvs}}" />

及其代码隐藏类,我在其中定义了详细范围的过滤器:

public class MainWindow
{
    public MainWindow()
    {
        CollectionViewSource detailScopes;

        InitializeComponent();

        // Attach filter to the collection view source
        detailScopes = this.Resources["DetailScopes"] as CollectionViewSource;
        detailScopes.Filter += new FilterEventHandler(DetailScopesFilter);

        private void DetailScopesFilter(object sender, FilterEventArgs e)
        {
            DetailScope scope;

            scope = (DetailScope)e.Item;
            if (scope == DetailScope.Private ||
                scope == DetailScope.Business)
            {
                e.Accepted = true;
            }
            else
            {
                e.Accepted = false;
            }
        }
    }
}

接下来是AccountDetail类:

public class AccountDetail
{
  public string Value
  {
    get { return this.value; }
    set { this.value = value; }
  }
  public DetailScope Scope
  {
    get { return scope; }
    set { scope = value; }
  }

  private string value;
  private DetailScope scope;
}

最后,一个枚举:

public enum DetailScope
{
  Private, 
  Business, 
  Other
}

当我运行我的代码时,我得到一个列表框,其中填充了一堆帐户详细信息,每个都有自己的组合框,其中包含选定的范围和一个具有适当值的文本框。问题是组合框中的所有选定值都与为最后输入的详细信息设置的范围相匹配,并且更改任何组合框值都会更新所有这些值,就好像它们都绑定到相同的帐户详细信息一样。

当我ObjectDataProviderCollectionViewSourceDetailScopes 中取出并将其直接绑定到 AccountDetail 中的组合框ItemsSourceDataTemplate,问题就消失了。但是,我确实需要它,CollectionViewSource因为我正在对其应用一些过滤,而我无法将过滤应用于ObjectDataProvider.

有人可以解释为什么会发生这种情况以及我实际上应该如何连接CollectionViewSourceObjectDataProvider?谢谢你。

4

1 回答 1

5

.

您的代码的问题是每个 ComboBox 都使用相同的 CollectionViewSource 实例;这意味着,具有键“DetailScopes”的资源由所有ComboBox 共享,因此每当您从特定 ComboBox 中选择一个值时,它会自动在所有 ComboBox 中选择相同的值。这是因为共享的基础集合会跟踪所选项目,并且由于它在从一个 ComboBox 中选择时发生变化,所以 CollectionViewSource 会将更改通知给 ALL ComboBox

所以解决方案非常简单。使 DetailScopes 资源不可共享所需的一切

这是修复:

<!-- Please note this x:Shared="False" just after x:Key="DetailsScopes" --->

<CollectionViewSource x:Key="DetailScopes"  x:Shared="False"> 
    <CollectionViewSource.Source>
      <ObjectDataProvider 
        MethodName="GetValues" 
        ObjectType="{x:Type system:Enum}">
        <ObjectDataProvider.MethodParameters>
          <x:Type TypeName="entities:DetailScope" />
        </ObjectDataProvider.MethodParameters>
      </ObjectDataProvider>
    </CollectionViewSource.Source>
  </CollectionViewSource>

希望它能解决你的问题!

但是,这种解决方案会导致另一个问题。让我引用 MSDN 中的一些内容,以便您了解 x:Shared 的作用。

x:共享属性

当设置为 false 时,修改 WPF 资源检索行为,以便对属性资源的请求为每个请求创建一个新实例,而不是为所有请求共享同一个实例。

由于 x:Shared 会导致在您尝试访问它时创建资源的新实例(新副本),这意味着 Filter 处理程序方法仅附加到您在代码隐藏中获得的实例,而不是所有实例。

因此,为了使您的处理程序正常工作,您需要从 XAML 本身附加处理程序,如下所示:

<!-- Now please note Filter="DetailsScopesFilter" --->

<CollectionViewSource x:Key="DetailScopes"  x:Shared="False"  Filter="DetailScopesFilter"> 
    <CollectionViewSource.Source>
      <ObjectDataProvider 
        MethodName="GetValues" 
        ObjectType="{x:Type system:Enum}">
        <ObjectDataProvider.MethodParameters>
          <x:Type TypeName="entities:DetailScope" />
        </ObjectDataProvider.MethodParameters>
      </ObjectDataProvider>
    </CollectionViewSource.Source>
  </CollectionViewSource>

希望它能解决你所有的问题。如果您仍然面临任何问题,请告诉我。:-)

哦,顺便说一句,不再需要以下代码隐藏。所以请删除它。

    // Attach filter to the collection view source
    detailScopes = this.Resources["DetailScopes"] as CollectionViewSource;
    detailScopes.Filter += new FilterEventHandler(DetailScopesFilter);

.

于 2010-12-01T10:57:45.450 回答