Wpf 基于MainWindow事件更新viewmodel

Wpf 基于MainWindow事件更新viewmodel,wpf,prism,viewmodel,Wpf,Prism,Viewmodel,我有一个UdpClient,在我的主窗口上触发DataReceived事件: public partial class MainWindow : Window { public static YakUdpClient ClientConnection = new YakUdpClient(); public ClientData; public MainWindow() { InitializeComponent(); Loade

我有一个UdpClient,在我的主窗口上触发DataReceived事件:

public partial class MainWindow : Window
{
    public static YakUdpClient ClientConnection = new YakUdpClient();
    public ClientData;

    public MainWindow()
    {
        InitializeComponent();
        Loaded += OnLoaded;
    }

    private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
    {
        ClientData = new ClientData();
        ClientConnection.OnDataReceived += ClientConnectionOnDataReceived;
    }

    private void ClientConnectionOnDataReceived(object sender, MessageEventArgs messageEventArgs)
    {
        ClientData.Users = messageEvenArgs.ConnectedUsers;
    }
}
我的ClientData和用户类如下所示:

public class ClientData
{
    public List<User> Users {get;set;)
}

public class User
{
    public string Name {get;set;}
}
public class UserListViewModel: BindableBase
{
    public UserListViewModel()
    {
        //I am sure there are better ways of doing this :(
        Users = new ObservableCollection<User>((MainWindow)Application.Current.MainWindow).ClientData.Users
    });

    private ObservableCollection<User> _users;
    public ObservableCollection<User> Users
    {
        get{ return _users;}
        set { this.SetProperty(ref this._users, value); }
    }
}
我在这里遇到的困难是,当主窗口上的
clientconnectionandareceived
事件被触发时,我想更新我的
ClientData
类,然后我的视图模型应该以某种方式被通知列表已更改,并随后更新我的UI

有谁能给我一个在WPF中使用MVVM(Prism)实现这一点的实例吗


我是MVVM新手,所以我仍在努力解决这个问题。

首先,没有明显的理由让主窗口进行订阅

我喜欢这样的东西:

  • 创建一个封装订阅(并在其构造函数中订阅)的服务
  • 将其注册为单身
  • 让it实现
    INotifyPropertyChanged
    (通知消费者
    用户的更改
  • 将服务注入
    UserListViewModel
    并观察
    Users
    属性(请参阅)
  • 当服务中的
    用户
    发生更改时,更新用户列表视图模型中的
    用户
最重要的是,这里不需要
ObservableCollection
:-)

编辑:示例:

interface IUserService : INotifyPropertyChanged
{
    IReadOnlyCollection<User> Users
    {
        get;
    }
}

class YakUdpService : BindableBase, IUserService
{
    private readonly YakUdpClient _yakUdpClient;
    private IReadOnlyCollection<User> _users;

    public YakUdpService()
    {
        _yakUdpClient = new YakUdpClient();
        _yakUdpClient.OnDataReceived += ( s, e ) => Users = e.ConnectedUsers;
    }

    public IReadOnlyCollection<User> Users
    {
        get
        {
            return _users;
        }
        private set
        {
            SetProperty( ref _users, value );
        }
    }
}

class UserListViewModel : BindableBase
{
    private IReadOnlyCollection<UserViewModel> _users;
    private readonly IUserService _userService;
    private readonly PropertyObserver<IUserService> _userServiceObserver;

    public UserListViewModel( IUserService userService )
    {
        _userService = userService;
        _userServiceObserver = new PropertyObserver<IUserService>( userService );
        _userServiceObserver.RegisterHandler( x => x.Users, () => Users = _userService.Users.Select( x => new UserViewModel( x ) ).ToList() );
        //                                                                                                ^^^ should use factory in real code
    }

    public IReadOnlyCollection<UserViewModel> Users
    {
        get
        {
            return _users;
        }
        private set
        {
            SetProperty( ref _users, value );
        }
    }
}
接口IUserService:INotifyPropertyChanged
{
IReadOnlyCollection用户
{
收到
}
}
YakUdpService类:BindableBase,IUserService
{
私有只读YakUdpClient(YakUdpClient);
私人IReadOnlyCollection用户;
公共YakUdpService()
{
_yakUdpClient=新的yakUdpClient();
_yakUdpClient.OnDataReceived+=(s,e)=>Users=e.ConnectedUsers;
}
公共IReadOnlyCollection用户
{
收到
{
返回用户;
}
专用设备
{
SetProperty(参考用户,值);
}
}
}
类UserListViewModel:BindableBase
{
私人IReadOnlyCollection用户;
专用只读IUserService\u userService;
私有只读属性Observer\u userServiceObserver;
公共用户列表视图模型(IUserService用户服务)
{
_userService=userService;
_userServiceObserver=新属性Observer(userService);
_userServiceObserver.RegisterHandler(x=>x.Users,()=>Users=\u userService.Users.Select(x=>newuserviewmodel(x)).ToList());
//^^^^应在实际代码中使用工厂
}
公共IReadOnlyCollection用户
{
收到
{
返回用户;
}
专用设备
{
SetProperty(参考用户,值);
}
}
}
然后注册服务

Container.RegisterType<IUserService, YakUdpService>( new ContainerControlledLifetimeManager() );
Container.RegisterType(新ContainerControlledLifetimeManager());

在引导程序或模块的初始化中。

首先,没有明显的理由说明主窗口应该进行订阅

我喜欢这样的东西:

  • 创建一个封装订阅(并在其构造函数中订阅)的服务
  • 将其注册为单身
  • 让it实现
    INotifyPropertyChanged
    (通知消费者
    用户的更改
  • 将服务注入
    UserListViewModel
    并观察
    Users
    属性(请参阅)
  • 当服务中的
    用户
    发生更改时,更新用户列表视图模型中的
    用户
最重要的是,这里不需要
ObservableCollection
:-)

编辑:示例:

interface IUserService : INotifyPropertyChanged
{
    IReadOnlyCollection<User> Users
    {
        get;
    }
}

class YakUdpService : BindableBase, IUserService
{
    private readonly YakUdpClient _yakUdpClient;
    private IReadOnlyCollection<User> _users;

    public YakUdpService()
    {
        _yakUdpClient = new YakUdpClient();
        _yakUdpClient.OnDataReceived += ( s, e ) => Users = e.ConnectedUsers;
    }

    public IReadOnlyCollection<User> Users
    {
        get
        {
            return _users;
        }
        private set
        {
            SetProperty( ref _users, value );
        }
    }
}

class UserListViewModel : BindableBase
{
    private IReadOnlyCollection<UserViewModel> _users;
    private readonly IUserService _userService;
    private readonly PropertyObserver<IUserService> _userServiceObserver;

    public UserListViewModel( IUserService userService )
    {
        _userService = userService;
        _userServiceObserver = new PropertyObserver<IUserService>( userService );
        _userServiceObserver.RegisterHandler( x => x.Users, () => Users = _userService.Users.Select( x => new UserViewModel( x ) ).ToList() );
        //                                                                                                ^^^ should use factory in real code
    }

    public IReadOnlyCollection<UserViewModel> Users
    {
        get
        {
            return _users;
        }
        private set
        {
            SetProperty( ref _users, value );
        }
    }
}
接口IUserService:INotifyPropertyChanged
{
IReadOnlyCollection用户
{
收到
}
}
YakUdpService类:BindableBase,IUserService
{
私有只读YakUdpClient(YakUdpClient);
私人IReadOnlyCollection用户;
公共YakUdpService()
{
_yakUdpClient=新的yakUdpClient();
_yakUdpClient.OnDataReceived+=(s,e)=>Users=e.ConnectedUsers;
}
公共IReadOnlyCollection用户
{
收到
{
返回用户;
}
专用设备
{
SetProperty(参考用户,值);
}
}
}
类UserListViewModel:BindableBase
{
私人IReadOnlyCollection用户;
专用只读IUserService\u userService;
私有只读属性Observer\u userServiceObserver;
公共用户列表视图模型(IUserService用户服务)
{
_userService=userService;
_userServiceObserver=新属性Observer(userService);
_userServiceObserver.RegisterHandler(x=>x.Users,()=>Users=\u userService.Users.Select(x=>newuserviewmodel(x)).ToList());
//^^^^应在实际代码中使用工厂
}
公共IReadOnlyCollection用户
{
收到
{
返回用户;
}
专用设备
{
SetProperty(参考用户,值);
}
}
}
然后注册服务

Container.RegisterType<IUserService, YakUdpService>( new ContainerControlledLifetimeManager() );
Container.RegisterType(新ContainerControlledLifetimeManager());

使用EventAggregator(有时称为“Messenger”)查看PubSub事件;它将使紧密的逻辑与ViewModels分离,并允许可伸缩性/更改。我建议您看看Prism的EventAggregator:另外,Prism对连接ViewModels很有用-有一个
BindableBase
类,它很好地实现了
INotifyPropertyChanged
,当ViewModel中发生更改时,它将能够更新您的视图。我只是想澄清一下——我不是Prism的下属/为Prism工作:)@GeoffJames,你会注意到我的
UserListViewModel
继承自
BindableBase
。对不起,我是你