【问题标题】:MVVM RaisePropertyChanged in ViewModel or Model?ViewModel 或 Model 中的 MVVM RaisePropertyChanged?
【发布时间】:2016-04-07 14:11:10
【问题描述】:

假设我有一个 Server 类,其中包含多个在后台更新的属性(例如 Ping)。 我有一个保存服务器实例的 ServerViewModel 和一个在 ObservableCollection 中保存 ServerViewModel 不同实例的 ServersViewModel,以在视图中的列表中显示服务器。

(缩短的)服务器类:

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()
    {
    }
}

当我在后台更新数据时,我在需要它的 Proerties 中添加了 RaisePropertyChanged。

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}" />

对我来说,这看起来是错误的。特别是因为我正在访问视图的服务器实例而不是视图的属性。我仍然不知道将 RaisePropertyChanged 放在哪里以及如何解决此行为。我不得不承认它是这样工作的,但我认为这不是 MVVM 中的样子。

ObservableObject 和 ViewModelBase 来自 MVVM light,正在实现所需的接口。

感谢您的帮助!

【问题讨论】:

    标签: c# mvvm mvvm-light


    【解决方案1】:

    通常应该在 ViewModel 中引发 PropertyChanged 事件,并且模型应该只是属性/对象的集合。然后,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");
             }
        }
    }
    

    您在 setter 中的验证逻辑将进入 ViewModel。如果 ViewModel 内部的逻辑变得复杂,最好将其外包给服务类 - ViewModel 不应该包含很多复杂的逻辑,它们只是告诉 View 如何显示 Model 数据。

    希望这会有所帮助。

    【讨论】:

    • 谢谢。这就是我在这个概念中误解的一点。所以我可以将后台工作线程移动到视图模型并让这个线程刷新服务器?在这种情况下,我就是这样做的。
    猜你喜欢
    • 1970-01-01
    • 2013-06-14
    • 2011-06-22
    • 2010-10-20
    • 2019-03-10
    • 1970-01-01
    • 2015-05-10
    • 2019-05-29
    • 1970-01-01
    相关资源
    最近更新 更多