Search code examples
c#wpfxamldata-binding

DataBinding doesn't show my bounded datasources in WPF Window


i'm new to the concept of XAML, WPF, MVVM and so on. And firstly maybe sorry for my bad english skills :P

I have the task to create an application, that takes user inputs. My Mainwindow is an userform with some textboxes, buttons and labels. These textboxes are bound to an instance of the class "Versandauftrag"(english-> shipping order). In turn, this instance has some properties that are objects from other custom classes like adressee, addressor, advice...

For illustration:

 public class Versandauftrag


 private  UpdateBase? _update; <--- Class for INotifyPropertyChanged
 public string? ID {get;set;}
 public Empfänger? Empfänger {  get; set; } <---- Addressee
 public Avis? Avis { get; set; } <---- Advice

 public Versender? Versender { get; set; } <--- Addressor

 public Abholung? Abholung { get; set; }

 public ObservableCollection<Packstück>? PackstückListe { get; set; } <--- List with items

 public Packstück? SelectedPackstück { get; set; } = null;

 public Versandauftrag()
 {
     this._update = new UpdateBase();
 }

Here the Addresse class for example:

public class Empfänger : UpdateBase
{
    private Address adresse = new Address();

    public Address Adresse
    {
        get { return adresse; }
        set
        {
            if (value != adresse)
            {

                adresse = value;
                OnPropertyChanged();
            }

        }

    }

    private string? _referenz;
    public string? Referenz...


    private string? _kundennr;
    public string? Kundennr ...


    private bool isPrivate;

    public bool IsPrivate ...

My ViewModel class is Eingabe (Input).

 public class Eingabe : UpdateBase

   //some commands
 public MainWindow MainWindow { get; set; }
 
 public Versandauftrag Versandauftrag { get; set; }

 private string lastJob;
 public string LastJob...
 
 public Eingabe(MainWindow main)
 { MainWindow = main;
   MainWindow.DataContext = this;  <--- this was one attempt to get the real bounded instance
   Versandauftrag = new Versandauftrag{ Empfänger = new Empfänger { Referenz = "123"} 
 };

MainWindow:

  public partial class MainWindow : Window
  
  public Eingabe EingabeVM { get; set; }
  public MainWindow()
  {
      InitializeComponent();
      DataBaseConnection.initDB();
      EingabeVM = new Eingabe(this);
      this.btnVersenden.Click += EingabeVM.VersendenButton_Click;
      this.txtNameVersender.SelectionChanged += EingabeVM.txtNameVersender_SelectionChanged;
      this.btnNeu.Click += EingabeVM.neuButton_Click;
  }

XAML Textbox example:

<TextBox x:Name="txtPLZ"  Text="{Binding Path=Versandauftrag.Empfänger.Adresse.Zip , UpdateSourceTrigger=PropertyChanged}" Width="54" FontSize="16" />

I set the DataContext from MainWindow at the initalitation from Eingabe (in the constructor). On the MainWindow is a button "New" that open a new form which fetches the relevant data from a database. This data fills every property from Versandauftrag (all in the right place and order). This all happens in the class EingabeView which has a property from Eingabe. The constructor from EingabeView takes an instance from Eingabe to set it to its private property from type Eingabe. After the initialization it sets all the fetched data to the instance <EingabeProperty>.Versandauftrag.x.

My mainwindow should show all fetched data in the textboxes but it doesn't show any data. I guess that the bindings are not bound to the correct instance of Versandauftrag but i don't get the right way to handle it.

I've tried the following steps:

  1. Set DataContext in MainWindow Constructor
  2. Set the DataContext with Window.DataContext in XAML -> It show's me that Eingabe doesn't have an public constructor

Edit: Some pictures from the app

MainWindow at the start of the app and also after I press the "Prüfen" (check for shipping id) Button from EingabeView (the little pic under the button "Neu")

MainWindow

EingabeView to fetch all needed data from DB


Solution

  • Every single property in your binding chain needs to be observable if it has a setter. You missed this one:

    public Versandauftrag Versandauftrag { get; set; }

    Versandauftrag = new Versandauftrag{ Empfänger = new Empfänger { Referenz = "123"}

    As well as every property of Versandauftrag (your naming convention is atrocious, you're designing software, not writing a diary). If you can set it, it needs to be observable.

    Which also raises the point that maybe not everything should be settable. A proper design would be as immutable as possible, especially with trivially immutable properties like Versandauftrag.PackstückListe -- it's already an observable collection, setting it is bad design, just call Clear() on it if needed.