2016-04-07 4 views
0

предположим, что у меня есть класс Server с несколькими свойствами (такими как Ping), которые обновляются в фоновом режиме. У меня есть ServerViewModel, который хранит экземпляр сервера и ServersViewModel, который держит разные экземпляры ServerViewModel в ObservableCollection, чтобы отображать серверы в списке в представлении.MVVM RaisePropertyChanged в ViewModel или Model?

The (укороченный) Class Server:

public class Server: ObservableObject, IServer 
{ 

    /// <summary> 
    /// Gets the IP adress of the server 
    /// </summary> 
    [JsonIgnore] 
    public IPAddress IPAdress { get; private set; } 

    /// <summary> 
    /// Gets the name of the server 
    /// </summary> 
    public string Name 
    { 
     get 
     { 
      return name; 
     } 

     private set 
     { 
      if(name != value) 
      { 
       name = value; 
       RaisePropertyChanged("Name"); 
      } 

     } 
    } 

    /// <summary> 
    /// Gives the string of the ip 
    /// </summary> 
    public string IP 
    { 
     get 
     { 
      return ip; 
     } 

     private set 
     { 
      if(ip != value) 
      { 
       ip = value; 
       RaisePropertyChanged("IP"); 
      }     
     } 
    } 


    /// <summary> 
    /// Gets the ping of the server 
    /// </summary> 
    [JsonIgnore] 
    public int Ping 
    { 
     get 
     { 
      return ping; 
     } 

     private set 
     { 
      if(ping != value) 
      { 
       ping = value; 
       RaisePropertyChanged("Ping"); 
      } 
     } 
    } 

    private Thread queryThread; 

    private string name, ip; 

    /// <summary> 
    /// Initializes the server instance 
    /// </summary> 
    /// <param name="ip">The ip adress or dns of the server</param> 
    /// <param name="port">The common port to connect to</param> 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] 
    public Server(string ip, int port) 
    { 
     IP = ip; 

     IPAddress tmpIP; 

     // Check if the given IP matches a DNS 
     if (!IPAddress.TryParse(ip, out tmpIP)) 
     { 
      try 
      { 
       this.IPAdress = Dns.GetHostEntry(ip).AddressList[0]; 
      } 
      catch (Exception ex) 
      { 
       System.Diagnostics.Debug.WriteLine(ex); 
       return; 
      } 
     } 
     else 
     { 
      this.IPAdress = IPAddress.Parse(ip); 
     } 

     Port = port; 

     queryThread = new Thread(QueryServer); 
     queryThread.Start(); 
    } 

    /// <summary> 
    /// Destructor for Server class. Stops the server thread running in background and cleans up. 
    /// </summary> 
    ~Server() 
    { 
     try 
     { 
      queryThread.Abort(); 
      queryThread = null; 
     } 
     catch 
     { 
      // Ignored 
     } 
    } 

    /// <summary> 
    /// Starts the loop that is querying the server 
    /// </summary> 
    private void QueryServer() 
    { 
    } 
} 

Как я обновляю данные в фоновом режиме, я добавил RaisePropertyChanged в Proerties, где это необходимо.

ServerViewModel:

public class ServerViewModel: ViewModelBase 
{ 
    private Server server; 

    public Server Server 
    { 
     get 
     { 
      return server; 
     } 
    } 

    public ServerViewModel(Server server) 
    { 
     this.server = server; 
    } 
} 

ServersViewModel:

public class ServersViewModel: ObservableObject 
{ 
    #region Members 

    ObservableCollection<ServerViewModel> servers = new ObservableCollection<ServerViewModel>(); 

    #endregion 

    #region Properties 
    public ObservableCollection<ServerViewModel> Servers 
    { 
     get 
     { 
      return servers; 
     } 

     set 
     { 
      servers = value; 
     } 
    } 
    #endregion 

    #region Construction 
    public ServersViewModel() 
    { 
     // Add servers to the collection 
    } 
    #endregion 
} 

Я связывание ServersViewModel к списку в представлении. Мой DataBinding для каждого элемента в списке выглядит так:

<Label Name="lblServerPing" Content="{Binding Server.Ping}" /> 

Для меня это выглядит неправильно. Тем более, что я обращаюсь к экземпляру Server представления, а не к виду представления. Я до сих пор не знаю, где поставить RaisePropertyChanged и как исправить это поведение. Я должен признать, что он работает таким образом, но я думаю, что это не так, как должно выглядеть в MVVM.

ObservableObject и ViewModelBase являются источниками света MVVM и реализуют необходимые интерфейсы.

Благодарим за помощь!

ответ

1

Как правило, событие PropertyChanged должно быть поднято в ViewModel, а модель должна быть просто набором свойств/объектов. Затем ViewModel будет выставлять эти свойства и уведомлять представление, когда они меняются через событие PropertyChanged.

Вот упрощенная версия того, что вы делаете, что следует надеяться нарисовать картину того, куда идти, если вы хотите следовать MVVM строго, то есть ...

public class ServerModel 
{ 
    public string Name { get; set; } 
    public string IP { get; set; } 
} 

public class ServerViewModel : ViewModelBase 
{ 
    private ServerModel model; 

    public ServerViewModel(ServerModel model) 
    { 
     this.model = model; 
    } 

    public string Name 
    { 
     get { return model.Name; } 
     private set 
     { 
       model.Name = value; 
       OnPropertyChanged("Name"); 
     } 
    } 

    public string IP 
    { 
     get { return model.IP; } 
     private set 
     { 
       model.IP= value; 
       OnPropertyChanged("IP"); 
     } 
    } 
} 

Логика проверки, что у вас есть внутри сеттеров, пойдет в ViewModel. Если логика внутри ViewModel становится сложной, она в идеале должна быть передана на аутсорсинг классу сервиса - ViewModels не должны содержать много сложной логики, они просто передают представлениям, как отображать данные модели.

Надеюсь, это поможет.

+0

Спасибо. Именно в этом я неправильно понял эту концепцию. Таким образом, я мог бы перемещать поток рабочего потока в модель представления и позволить этому потоку обновлять сервер? Вот как я буду в этом случае. – chris579