C# WPF - bindowanie oraz NVVM

Cześć,
próbuje ogarnąć podstawy C#/WPF/MVVM
i mam do Was kilka pytań…

W projekcie utworzyłem sobie katalog “Views”, a w nim plik typu “UserControl”.
W XAMLu dodałem :

<ComboBox x:Name="cbNetworkInterfaces"/>

Jego zadaiem bedzie wyświetlenie listy interfejsów sieciowych, które są w komputerze.
W code-behind mam:

public partial class SettingsNetworkView : UserControl
{
	private List<string> networkInterfacesList  { get; set; }


	public SettingsNetworkView()
	{
		InitializeComponent();
		networkInterfacesList = NetworkInterfaces();
		cbNetworkInterfaces.ItemsSource = networkInterfacesList;
	}


	public List<string> NetworkInterfaces()
	{
		List<String> nicList = new List<String>();

		foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
		{
			if (nic.OperationalStatus == OperationalStatus.Up && nic.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 || nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
			{
				nicList.Add($"{nic.Description} - {nic.Name}");
			}
		}

		return nicList;
	}
}

I to działa, czyli w liście rozwijanej mam wszystkie interfejsy sieciowe.
Pewnie można to wszystko zrobić inaczej, lepiej… chociażby wykorzystując bindowanie.
Tylko, że mam problem, żeby to ugryźć. Nie wspominając już o MVVM, które mam wrażenie, że tylko wszystko utrudnia.

W każdym razie usunąłem z code-behind
cbNetworkInterfaces.ItemsSource = networkInterfacesList;

i w XAMLu chciałem zrobić tak:
<ComboBox x:Name="cbNetworkInterfaces" ItemsSource="{Binding networkInterfacesList}"/>

Jednak nie działa i nic się nie wyświetla.
Czy mogę prosić o wskazówkę jak zrobić to bindowanie?

Idąc trochę dalej - w kierunku tego NVVP - czy dla takiej rzeczy jak ta lista interfejsów sieciowych
powinienem w dodatkowym katalogu “ViewModels” utworzyć osobną klasę, która będzie opisywać te interfejsy. Czyli w moim wypadku powinna zawierać właściwości “Description” oraz “Name”. A później w liście przechowywać obiekty tej klasy, a nie stringi jak teraz?
Czy to już jednak przesada i dla tak drobnej rzeczy nie warto tego robić?

Sorry, jeżeli trochę to wszystko zamotałem.
I z góry dzięki za poświęcony czas i pomoc :slight_smile:

Żeby działało bindowanie musisz ustawić DataContext na obiekt który zawiera dane.

Coś w tym stylu:

public partial class MainWindow : Window
{
	public class TestViewModel
	{
		public List<string> Interfaces { get; set; }
	}

	public MainWindow()
	{
		InitializeComponent();
		DataContext = new TestViewModel
		{
			Interfaces = GetNetworkInterfaces()
		};
	}

	private List<string> GetNetworkInterfaces()
	{
		List<String> nicList = new List<String>();

		foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
		{
			if (nic.OperationalStatus == OperationalStatus.Up && nic.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 || nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
			{
				nicList.Add($"{nic.Description} - {nic.Name}");
			}
		}

		return nicList;
	}
}

Wtedy bez problemu działa bindowanie:
<ComboBox ItemsSource="{Binding Interfaces}"/>

Dodatkowo twoje dane oczywiście nie mogą być “private” bo wtedy kontrolka się do nich nie dostanie.

Niepotrzebnie robisz UserControl. Kontrolką jest już ComboBox. Nie jest zadaniem kontrolki pobieranie wewnętrznie danych. Te podajesz jej z zewnątrz przez binding. To w zasadzie istota MVVM.

Generalnie powinieneś to podzielić na przynajmniej 3 klasy:

  1. XyzWindow - okno
  2. XyzViewModel - model danych.
  3. Jakiś helper do pobierania interfejsów sieciowych.

Uwaga - view model to nie jest jedynie kontener na dane. Może zawierać w sobie też konieczną logikę do ich przetwarzania, walidacji itp.