I have the following class which work just fine
public class RemoteSource {
ObservableCollection<RemoteDataViewModel> remote;
string[] _servers = new string[] {
"server",
"server",
"server",
"server",
"server"
};
public RemoteSource() {
remote = CreateDataSource();
}
protected ObservableCollection<RemoteDataViewModel> CreateDataSource() {
ObservableCollection<RemoteDataViewModel> res = new ObservableCollection<RemoteDataViewModel>();
ITerminalServicesManager _manager = new TerminalServicesManager();
foreach (var host in _servers) {
using (ITerminalServer srv = _manager.GetRemoteServer(host)) {
try {
srv.Open();
foreach (ITerminalServicesSession session in srv.GetSessions()) {
res.Add(new RemoteDataViewModel() { Server = srv.ServerName, SessionID = session.SessionId, UserID = session.UserName, State = session.ConnectionState, ConnectedTime = session.ConnectTime, LogonTime = session.LoginTime, IdleTime = session.IdleTime, UserIP = session.ClientIPAddress, Workstation = session.WindowStationName });
}
srv.Close();
}
catch (Win32Exception) { }
catch (SystemException) { }
catch (Exception) { }
}
}
return res;
}
/// <summary>
/// Gets the data.
/// </summary>
/// <value>
/// The data.
/// </value>
public ObservableCollection<RemoteDataViewModel> Data { get { return remote; } }
public ObservableCollection<string> hosts { get; set; }
}
The RemoteSource is setup but a button event that does the following
DataContext = new RemoteSource();
I want to read through a text file that has the list of server names like so
Server1
Server2
Server3
etc
and load them into an ObservableCollection then be able to do the same thing I am currently doing on this line
foreach (var host in _servers) # but where _servers is the observablecollection initiated from the button event
I attempted doing something like this under the button event, but rs.hosts always returns as null
RemoteSource rs = new RemoteSource();
rs.hosts.Add(Environment.MachineName);
Your ObservableCollection<T>
should be a property of your ViewModel. Then, in the View, you bind some ItemsControl.ItemsSource
property to it.
For exemple (super simplified):
public class SessionViewModel : INotifyPropertyChanged
{
// ...
public ObservableCollection<String> ServerList { get; set; }
}
And in the View
<ListView x:Name="ServerList" ItemsSource="{Binding ServerList}"/>
Not sure if you're trying to let the user select a server, or edit the server. I'm answering both. Editing first, then selecting after.
Bindings can only update properties of a class. They cannot replace an instance of one type with a completely different instance of another type within a collection. That's just not how it works. Remember, this is Model View ViewModel. Your ViewModels must expose Models whose properties are bound to elements in the UI. These properties will be updated by the bindings.
So, create a Model for your server
public sealed class ServerInfo
{
public string Name {get;set;}
public string IP {get;set;}
public string Whatevs {get;set;}
}
In your VM, you would expose your list of servers from the ViewModel. If you're looking to do work on selected servers, you'd want to have a Selected property and do work on update.
public sealed class ViewModelLol : INotifyPropertyChanged
{
// init from ctor
public ObservableCollection<ServerInfo> Servers {get;private set;}
public ServerInfo SelectedServer {get;set;} // should be INPC impl, but yawn
// boring stuff goes here
}
In your UI, you'd bind an ItemsSource to the collection
<ListBox ItemsSource="{Binding Servers}" SelectedItem="{Binding SelectedServer}" >
<ListBox.ItemTemplate>
<DataTemplate>
<!-- If you wanted to edit the server name... -->
<TextBox Text="{Binding Name}"/>
<!-- If you only care about selection... -->
<Label Content="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Not exactly sure if you want to be able to edit the server name, if so, use the first option. If you want to present to the user a list of servers and allow them to select one, then use the label option.
Once the user selects a server, SelectedServer
in the ViewModel is updated. You can take that opportunity to do whatever work you need to.
ViewModels should be at the top of the logic food chain. They interpret actions of users of the system and convert them into API calls within. So if you need to connect to a server, then the VM should contain the logic to connect to the server. The VM shouldn't be a child of some business logic class. That requires some tricky spaghetti code and will be harder to implement.
VMs are supposed to sit between the UI and your core business logic, which shouldn't care about the UI at all. For instance, connecting to a server has nothing to do with the UI. Identifying which server to connect to does. Bridging that gap is the role of the VM.