1

У меня есть MainWindow.xaml файл:WPF привязка данных: CollectionViewSource и ObjectDataProvider вопрос

<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 
} 

Когда я запускаю мой код, я получаю окно списка населенное с кучей деталей счетов, каждый из которых имеют свой собственное поле со списком с выбранной областью и текстовым полем с соответствующим значением. Проблема в том, что все выбранные значения в комбинированных ячейках соответствуют объему, заданному для последней введенной детали, и изменению любого из значений со списком всех их обновлений, как будто все они связаны с одной и той же деталью учетной записи.

Когда я вынуть ObjectDataProvider из CollectionViewSource DetailScopes и связать его непосредственно, проблема исчезла коробка комбо ItemsSource в DataTemplate AccountDetail. Тем не менее, мне нужно это внутри CollectionViewSource, потому что я применяю к нему некоторую фильтрацию, и я не могу применить фильтрацию к ObjectDataProvider.

Не могли бы вы объяснить, почему это происходит, и как я на самом деле должен подключаться CollectionViewSource и ObjectDataProvider? Спасибо.

ответ

5

.

Проблема с вашим кодом в том, что каждый ComboBox использует тот же экземпляр CollectionViewSource; это означает, что ресурс с ключом «DetailScopes» равен , общим для всех ComboBox, поэтому всякий раз, когда вы выбираете одно значение из определенного ComboBox, он автоматически выбирает одно и то же значение во всем ComboBox. Это связано с тем, что основная коллекция, которая является общей, отслеживает выбранный элемент, и поскольку она изменяется при выборе из одного ComboBox, CollectionViewSource уведомляет об изменении для ALL ComboBox.

Таким образом, решение очень простое. Все, что вам нужно, чтобы сделать DetailScopes ресурсом unsharable.

Вот исправление:

<!-- 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.

х: Shared Атрибут

Если установлено значение ложно, изменяет МОФ ресурс-поисковых поведение так, что запросы на приписываемой ресурса создать новый экземпляр для каждого запроса вместо обмена такой же экземпляр для всех запросов .

Поскольку x: Общие причины для создания нового экземпляра (новой копии) ресурса всякий раз, когда вы пытаетесь получить к нему доступ, то есть метод обработчика фильтра привязан только к экземпляру, который вы получаете в коде - не все случаи.

Так что для того, чтобы работать обработчик должным образом, вам необходимо прикрепить обработчик из самого 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); 

.

+0

Спасибо, что решила проблему. Также это вызвало другое: мой фильтр больше не работает. Он выполняется, но, похоже, он не применяется к выборам со списком. Есть идеи? – Boris 2010-12-01 11:20:42

Смежные вопросы