Laden...

Wie kann ich an an Elemente in einem Dictionary binden?

Erstellt von D0ct0R_HaCkiE vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.288 Views
D
D0ct0R_HaCkiE Themenstarter:in
11 Beiträge seit 2012
vor 4 Jahren
Wie kann ich an an Elemente in einem Dictionary binden?

Hallo Leute,

nach ein paar Jahren C#-Pause wollte ich ein neues Projekt beginnen. Ein paar Basics habe ich, mein Wissen ist aber etwas eingestaubt... Nehmt also bitte etwas Rücksicht. 😃

Ich habe ein Dictionary erstellt. Die Keys sind vom Typ String, als Values kommen eigene Klassen zum Einsatz, die alle samt die selbe Elternklasse haben, die wiederum eine Collection aus Parts haben. Auf XAML-Seite ist schließlich für jedes Part-Element eine TextBox definiert.

Das Ganze sieht dann so aus:

Die Elternklasse:

abstract public class IbisAbstract
{
    abstract public ObservableCollection<string> Parts { get; }
}

Eine abgeleitete Klasse:

public class IbisDS001 : IbisAbstract
{
    public ObservableCollection<string> parts = new ObservableCollection<string> { "0001" };

    public override ObservableCollection<string> Parts => parts;
}

Die Anwendung selbst:

public Dictionary<string, IbisAbstract> IbisDictionary { get; set; }

private void InitializeIbisDictionary()
{
    IbisDictionary = new Dictionary<string, IbisAbstract>
    {
        { "IbisDS001", new IbisDS001() }
    };
}

Schließlich noch das Binding auf XAML-Ebene:

<TextBox x:Name="LineDS001Textbox" Style="{StaticResource StandardTextbox}"
         Text="{Binding IbisDictionary[IbisDS001].Parts[0], ElementName=MainWindow, Mode=TwoWay, StringFormat=\{0:D4\}}" />

Es werden keine Fehler angezeigt, die Anwendung läßt sich kompilieren und starten. Allerdings kann ich eintippen was ich will, die Parts bleiben unverändert im Urzustand.

Ich habe nun 2 Tage versucht, das Problem selbst zu lösen und finde keine Lösung. Statt dem Dictionary habe ich auch schon ein ObservableDictionary versucht, wie auch diverse Bindungs-Syntax und Verwendung der Eigenschaft DataContext. Am Ergebnis änderte alles nichts. Es werden grundsätzlich die bei der Initiierung angegebenen Defaultwerte ausgegeben.

Meine Vermutung ist, daß entweder die Vererbung Sorgen macht. Andernseits könnte es auch daran liegen, daß meine Ibis*-Klassen IPropertyChanged nicht verwenden, was an und für sich mit den Observable-Objekten nicht erforderlich sein müßte.

Ich würde mich sehr freuen, wenn ihr mir bei der Fehlersuche etwas unter die Arme greifen könnt. 😃

Vielen Dank und viele Grüße
Dan

Viele Grüße
D0ct0R_HaCkiE

2.078 Beiträge seit 2012
vor 4 Jahren

Du bindest an dein MainWindow (ElementName=MainWindow), allerdings verwendet das Binding dann die Window-Instanz als Source, nicht den DataContext vom Window.

<TextBox x:Name="LineDS001Textbox" Style="{StaticResource StandardTextbox}"
         Text="{Binding DataContext.IbisDictionary[IbisDS001].Parts[0], ElementName=MainWindow, Mode=TwoWay, StringFormat=\{0:D4\}}" />

Probier das Mal aus

D
D0ct0R_HaCkiE Themenstarter:in
11 Beiträge seit 2012
vor 4 Jahren

Hi,

vielen Dank für die äußerst schnelle Rückmeldung.

Nachdem ich mir deinen Vorschlag angesehen und mich etwas zum DataContext belesen habe, bin ich schließlich auf die Lösung gekommen. Das DataContext und ElementName=MainWindow letztlich verschiedene Instanzen sind, war mir nicht bekannt.

Vielen Dank!

Die Änderungen im Detail:

In der Form habe ich den Datenkontext gesetzt.

public Main()
{
	InitializeComponent();

	DataContext = this;
}

Die Bindung im XAML sieht nun wie folgt aus:

<TextBox x:Name="LineDS001Textbox" Style="{StaticResource StandardTextbox}"
         Text="{Binding IbisDictionary[IbisDS001].Parts[0], Mode=TwoWay, StringFormat=\{0:D4\}}" />

Interessanter Weise scheint das nicht zu funkionieren, wenn ich als DatenKontext direkt IbisDictionary oder IbisDictionary[IbisDS001] angebe.

Ich muß mich eindeutig mehr mit den Bindungen beschäftigen. ^^

Viele Grüße
Dan

Viele Grüße
D0ct0R_HaCkiE

187 Beiträge seit 2009
vor 4 Jahren
  1. Dein Getter in der IbisDS001 Klasse gibt immer eine neue Collection mit dem Sting 0001 zurück. Deswegen erscheinen Deine Änderungen nicht.

was an und für sich mit den Observable-Objekten nicht erforderlich sein müßte

Das ist falsch gedacht. Die ObservableCollection benachrichtigt nur über die Anzahl der Elemente in der Sammlung, nicht über Änderungen am Wert. Deswegen erscheinen Deine Änderungen nicht.

Ich habe nun folgende Klassen etwas abgeändert und die neue Klasse Part hinzugefügt.

        public override ObservableCollection<Part> Parts { get; }

        public IbisDS001()
        {
            Parts = new ObservableCollection<Part>
            {
                new Part { Number = 1 }
            };
        }
    }

    public class Part : INotifyPropertyChanged
    {
		private int number;

		public int Number
		{
			get { return number; }
			set
			{
				if (number != value)
				{
					number = value;
					OnPropertyChanged(nameof(Number));
				}
			}
		}

		public event PropertyChangedEventHandler PropertyChanged;

		protected virtual void OnPropertyChanged(string propertyName)
		{
			PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
		}
	}

<Window x:Class="MyCsharp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"        
        xmlns:local="clr-namespace:MyCsharp"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.DataContext>
        <local:MainWindowViewModel x:Name="ViewModel" />
    </Window.DataContext>
    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
        </Grid.RowDefinitions>
        <TextBox x:Name="LineDS001Textbox" Grid.Row="0" Text="{Binding IbisDictionary[IbisDS001].Parts[0].Number, Mode=TwoWay, StringFormat=\{0:D4\}, UpdateSourceTrigger=PropertyChanged}" />
        <Button Grid.Row="1" />
    </Grid>
</Window>

4.931 Beiträge seit 2008
vor 4 Jahren
  1. Dein Getter in der IbisDS001 Klasse gibt immer eine neue Collection mit dem String 0001 zurück. Deswegen erscheinen Deine Änderungen nicht.

Diese Aussage ist falsch, die Zuweisung wird nur initial einmal beim Erstellen des Klassenobjekts vorgenommen (d.h. dies ist eine Initialisierung).