基于 MainWindow 事件更新视图模型
Update viewmodel based on MainWindow event
我有一个 UdpClient,在我的 MainWindow 上触发了一个 DataRecevied 事件:
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 和 User class如下所示:
public class ClientData
{
public List<User> Users {get;set;)
}
public class User
{
public string Name {get;set;}
}
在我的 MainWindow 上,我有一个名为 UserListView
的 UserControl,它有一个名为 UserListViewModel
的 ViewModel
ViewModel 如下所示:
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); }
}
}
我在这里遇到的困难是,当主窗口上的 ClientConnectionOnDataReceived
事件被触发时,我想更新我的 ClientData
class,然后应该以某种方式通知我的 Viewmodel该列表已更改,随后更新我的 UI.
任何人都可以给我一个关于如何在 WPF 中使用 MVVM (Prism) 实现此目的的可靠示例吗?
我是 MVVM 的新手,所以我仍在努力解决这个问题。
首先,主要 window 应该进行订阅并没有明显的理由。
我会选择这样的东西:
- 创建一个封装订阅的服务(并在其构造函数中订阅)
- 注册为单例
- 让它实现
INotifyPropertyChanged
(通知消费者对 Users
的更改)
- 将服务注入
UserListViewModel
并观察 Users
属性(参见 PropertyObserver)
- 当服务中的
Users
发生变化时,更新用户列表视图模型中的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 );
}
}
}
然后注册服务
Container.RegisterType<IUserService, YakUdpService>( new ContainerControlledLifetimeManager() );
在您的引导程序或模块的初始化中。
我有一个 UdpClient,在我的 MainWindow 上触发了一个 DataRecevied 事件:
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 和 User class如下所示:
public class ClientData
{
public List<User> Users {get;set;)
}
public class User
{
public string Name {get;set;}
}
在我的 MainWindow 上,我有一个名为 UserListView
的 UserControl,它有一个名为 UserListViewModel
ViewModel 如下所示:
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); }
}
}
我在这里遇到的困难是,当主窗口上的 ClientConnectionOnDataReceived
事件被触发时,我想更新我的 ClientData
class,然后应该以某种方式通知我的 Viewmodel该列表已更改,随后更新我的 UI.
任何人都可以给我一个关于如何在 WPF 中使用 MVVM (Prism) 实现此目的的可靠示例吗?
我是 MVVM 的新手,所以我仍在努力解决这个问题。
首先,主要 window 应该进行订阅并没有明显的理由。
我会选择这样的东西:
- 创建一个封装订阅的服务(并在其构造函数中订阅)
- 注册为单例
- 让它实现
INotifyPropertyChanged
(通知消费者对Users
的更改) - 将服务注入
UserListViewModel
并观察Users
属性(参见 PropertyObserver) - 当服务中的
Users
发生变化时,更新用户列表视图模型中的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 );
}
}
}
然后注册服务
Container.RegisterType<IUserService, YakUdpService>( new ContainerControlledLifetimeManager() );
在您的引导程序或模块的初始化中。