Home > Blockchain >  How to show members of a list in listbox when selected in WPF
How to show members of a list in listbox when selected in WPF

Time:04-10

I'm fairly new to programming, so please forgive my ignorance.

I have 2 classes and 2 listboxes in my WPF app for adding patients and wards. One of my classes (Ward) includes a list of the other class (Patients) as a property.

I've figured out how to add patients to a ward as a list. Now the part I'm struggling with: I need to be able to add the patients to a particular ward based on the ward that is selected in that ward list, and also show the patients of that ward in a separate listbox.

I created a selection changed event so that when a ward is selected, the patients will show. I just don't know how to change the source of the second listbox to the wards' patients.

I've attached the code and a screenshot of the app below. Any help getting this to work is really appreciated. Thanks.

Screenshot: [1]: https://i.stack.imgur.com/omILR.png

public partial class MainWindow : Window
{
    public ObservableCollection<Ward> ward = new ObservableCollection<Ward>();
    public ObservableCollection<Patient> patient = new ObservableCollection<Patient>();


    public MainWindow()
    {
        InitializeComponent();
    }

    private void sliderCapacity_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        tblkCapacity.Text = string.Format("{0:F0}", sliderCapacity.Value);
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        btnAddWard.IsEnabled = false;
        btnAddPatient.IsEnabled = false;
        Ward w1 = new Ward("Marx Brothers", 3);
        Ward w2 = new Ward("Addams Family", 7);

        ward.Add(w1);
        ward.Add(w2);

        Patient p1 = new Patient("Chico", 67, BloodType.A);
        Patient p2 = new Patient("Graucho", 57, BloodType.AB);
        Patient p3 = new Patient("Harpo", 46, BloodType.B);

        w1.Patients.Add(p1);
        w1.Patients.Add(p2);
        w1.Patients.Add(p3);

        //display on screen
        lbxWards.ItemsSource = ward;

        //begin ward list count at 2
        Ward.NumberOfWards  ;
        Ward.NumberOfWards  ;
        int totalWards = Ward.NumberOfWards;
        tblkNumberOfWards.Text = string.Format("({0})", totalWards);
    }

    private void lbxWards_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        //need to make patients listbox (lbxPatients) populate with patients of selected ward when hovered
 
    }

Patient Class:

public class Patient
    {
        public string PatientName { get; set; }

        public DateTime DOB { get; set; }

        public static int Age { get; set; }

        public BloodType BloodType { get; set; }

        public static int NumberOfPatients { get; set; }


        public Patient(string patientName, DateTime dob, int age, BloodType bloodType)
        {
            PatientName = patientName;
            DOB = dob;
            Age = age;
            BloodType = bloodType;
        }

        public Patient(string patientName, int age, BloodType bloodType)
        {
            PatientName = patientName;
            Age = age;
            BloodType = bloodType;
        }

        public Patient()
        {
            
        }

        public override string ToString()
        {
            return string.Format("{0} ({1}) Type: {2}", PatientName, Age, BloodType);
        }

    }

Ward Class

public class Ward
    {
        public List<Patient> Patients { get; set; }
        public string WardName { get; set; }
        public double Capacity { get; set; }
        public static int NumberOfWards { get; set; }

        public Ward(string wardName, double capacity)
        {
            WardName = wardName;
            Capacity = capacity;
            Patients = new List<Patient>();
        }

        public Ward()
        {
            Patients = new List<Patient>();
        }

        public override string ToString()
        {
            return string.Format("{0} Ward \t (Limit: {1})", WardName, Capacity);
        }

    }

CodePudding user response:

Use MVVM instead of code-behind. Give your main window a DataContext of MainWindowViewModel. Like this

// BaseViewModel class for implementing INotifyPropertyChanged.
// This is a terribly simple implementation.  There are better ones.

public class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;

    protected RaisePropertyChanged(string name) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name);
}

// MainWindowViewModel. An instance of this should be set, at startup as 
// the DataContext of the MainWindow

public class MainWindowViewModel : BaseViewModel
{
    public ObservableCollection<Ward> Wards { get; } = new();
    private Ward _currentWard;
    public Ward CurrentWard
    {
        get => _currentWard;
        set
        {
            if (value == _currentWard)
                return;

             // Current ward changed.  Raise the event.

            _currentWard = value;
            RaisePropertyChanged(nameof(CurrentWard));
        }
    }
}

Then your XAML in MainWindow might look something like this (I'm supposing a grid with rows and columns. I'm also supposing that the current default DataContext of this XAML is an instance of MainWindowViewModel

<!-- Main list of wards on the left -->
<ListBox x:Name="WardListBox" 
    ItemsSource="{Binding Wards}"
    SelectedItem="{Binding CurrentWard}"
    Grid.Row="0" Grid.Column="0"
    />

<!-- List of patients in the currently selected ward on the right -->

<ListBox x:Name="PatientListBox"
    ItemsSource="{Binding CurrentWard.Patients}"
    Grid.Row="0" Grid.Column="1"
    />
  • Related