WPF associazione dei dati: CollectionViewSource e ObjectDataProvider problema
-
29-09-2019 - |
Domanda
Ho un file 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}}" />
e la sua classe code-behind, dove ho definito il filtro per il dettaglio Scopes:
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;
}
}
}
}
Avanti, c'è la classe 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;
}
Infine, un enum:
public enum DetailScope
{
Private,
Business,
Other
}
Quando eseguo il mio codice, ottengo una casella di riepilogo popolato con un mucchio di dettagli del conto, ciascuno con la propria casella combinata con un campo di applicazione selezionata e una casella di testo con il valore appropriato. Il problema è che tutti i valori selezionati nelle caselle combinate corrispondono il set ambito per il dettaglio è entrato e cambiare qualsiasi valore casella combinata aggiorna tutti loro, come se fossero tutti legati allo stesso account dettagli.
Quando prendo la ObjectDataProvider
dalle DetailScopes CollectionViewSource
e si legano direttamente al ItemsSource
della casella combinata nel DataTemplate
AccountDetail, il problema è andato. Tuttavia, ho bisogno all'interno del CollectionViewSource
perché Mi candido qualche filtro ad esso e non posso applicare il filtro a ObjectDataProvider
.
Qualcuno potrebbe spiegare perché questo sta accadendo e come sono in realtà dovrebbe CollectionViewSource
connessione e ObjectDataProvider
? Grazie.
Soluzione
.
Il problema con il vostro codice è che ogni ComboBox è utilizzando la stessa istanza di CollectionViewSource ; Ciò significa che, con la risorsa chiave "DetailScopes" è condiviso da tutti ComboBox, quindi, quando si seleziona un valore da un particolare ComboBox, si seleziona automaticamente lo stesso valore in tutto ComboBox. E 'perché la raccolta di fondo che è condiviso, tiene traccia della voce selezionata, e dal momento che cambia sulla selezione da una casella combinata, la Notifica CollectionViewSource la modifica a tutte ComboBox .
Quindi la soluzione è molto semplice. Tutto quello che devi fare risorsa DetailScopes non condivisibile .
Ecco la correzione:
<!-- 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>
La speranza si risolve il problema!
Tuttavia, questa soluzione causerà un altro problema. Permettetemi di citare qualcosa da MSDN, in modo che capirete cosa x:. Non condivisa
x: Shared attributo
Se impostato su False, modifica WPF risorse recupero comportamento in modo che le richieste per la risorsa attribuito creare una nuova istanza per ogni richiesta ??strong> al posto di condividendo la stessa istanza per tutti richieste.
Dato che x: provoca condivisa per creare una nuova istanza (una nuova copia) della risorsa ogni volta che si tenta di accedervi, che i mezzi, il metodo del gestore Filtro riguarda solo l'istanza che si ottiene nel code-behind, non tutte le istanze.
Quindi, al fine di lavorare il vostro gestore correttamente, è necessario collegare il Handler da XAML stesso, in questo modo:
<!-- 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>
La speranza risolve tutti i vostri problemi. Fatemi sapere se avete ancora affrontare qualsiasi: -).
Oh, a proposito, il seguente code-behind non è più necessaria. Quindi, per favore rimuoverlo.
// Attach filter to the collection view source
detailScopes = this.Resources["DetailScopes"] as CollectionViewSource;
detailScopes.Filter += new FilterEventHandler(DetailScopesFilter);
.