WPF Datenbindung: Collection und Object Ausgabe
-
29-09-2019 - |
Frage
Ich habe eine MainWindow.xaml-Datei:
<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}}" />
und seine Code-Behind-Klasse, wo ich die Filter für Detail definiert Tive:
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;
}
}
}
}
Als nächstes gibt es die AccountDetail
Klasse:
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;
}
Schließlich ist ein Enum:
public enum DetailScope
{
Private,
Business,
Other
}
Wenn ich meinen Code ausführen, bekomme ich ein Listenfeld mit einem Bündel von Kontodaten bevölkert, von denen jeder seine eigene Combo-Box mit einem ausgewählten Bereich und ein Textfeld mit dem entsprechenden Wert. Das Problem ist, dass alle die ausgewählten Werte in den Kombinationsfeldern den Umfang Satz für das zuletzt eingegebenen Detail und Ändern von einem der Combo-Box Werte aktualisieren alle von ihnen entsprechen, als ob sie alle auf das gleiche Konto Detail gebunden sind.
Wenn ich die ObjectDataProvider
von dem CollectionViewSource
DetailScopes herausnehmen und bindet es direkt an den ItemsSource
des Kombinationsfelds in der DataTemplate
AccountDetail, ist das Problem verschwunden. Aber ich brauche es in der CollectionViewSource
weil ich etwas zu filtern sie beantrage, und ich kann das Filtern auf ObjectDataProvider
nicht anwendbar.
Könnte jemand bitte erklären, warum dies geschieht und wie soll ich eigentlich zu verbinden CollectionViewSource
und ObjectDataProvider
? Vielen Dank.
Lösung
.
Das Problem mit Ihrem Code ist, dass jede ComboBox ist die gleiche Instanz von Collection mit ; das bedeutet, ist die Ressource, mit der Taste „DetailScopes“ geteilt durch all ComboBox-, so, wenn Sie einen Wert von einem bestimmten ComboBox auswählen, wählt es automatisch den gleichen Wert in allen ComboBox. Es ist, weil die zugrunde liegende Sammlung, die gemeinsam genutzt wird, den Überblick über das ausgewählte Element hält, und da es ändert sich auf die Auswahl von einem ComboBox, die Collection meldet die Änderung auf alle ComboBox .
So ist die Lösung sehr einfach. Alles was Sie brauchen DetailScopes Ressource unsharable .
machenHier ist das Update:
<!-- 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>
Hope es löst Ihr Problem!
Allerdings ist diese Lösung wird ein anderes Problem verursachen. Lassen Sie mich etwas von MSDN zitieren, so dass Sie verstehen, was x:. Geteilt tut
x: Geteilt Attribut
Bei der Einstellung falsch ist, ändert WPF Ressource-Abruf Verhalten, so dass Anfragen für die zugeschrieben Ressource Erstellen Sie eine neue Beispiel für jede Anforderung statt teilen die gleiche Instanz für alle Anfragen.
Da x: Geteilt wird eine neue Instanz (eine neue Kopie) der Ressource erstellen, wenn Sie den Zugriff versuchen es, das bedeutet, wird die Filter-Handler-Methode angebracht nur auf die Instanz, die Sie im bekommen Code-behind, nicht alle Instanzen.
Also, um Ihre Handler richtig funktioniert, müssen Sie den Handler von XAML selbst, so befestigen:
<!-- 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>
Hope es löst alle Probleme. Lassen Sie mich wissen, wenn Sie noch irgendwelche Gesicht: -).
Ach übrigens, der folgende Code-Behind wird nicht mehr benötigt. Also bitte nehmen Sie es.
// Attach filter to the collection view source
detailScopes = this.Resources["DetailScopes"] as CollectionViewSource;
detailScopes.Filter += new FilterEventHandler(DetailScopesFilter);
.