我有一个主窗口,其中包含2个使用ContentControl的用户控件。在主窗口视图模型中,Person模型被实例化并通过DI传递给两个用户控件。我的要求是,如果在用户控件2中编辑属性"名字",则这需要反映回用户控件1的"名字"属性中。已附上代码。
ShellViewModel(主窗口(
public class ShellViewModel : Screen
{
public IPersonModel _personModel { get; }
private IPeopleService _peopleService;
public UserControl1ViewModel UserControl1VM { get; set; }
public UserControl2ViewModel UserControl2VM { get; set; }
public ShellViewModel(IPersonModel personModel, IPeopleService peopleService)
{
_personModel = personModel;
_peopleService = peopleService;
_personModel = _peopleService.GetPersonInfo(1);
UserControl1VM = new UserControl1ViewModel(_personModel);
UserControl2VM = new UserControl2ViewModel(_personModel);
}
}
public class UserControl1ViewModel : PropertyChangedBase
{
private IPersonModel Model;
public UserControl1ViewModel(IPersonModel model)
{
Model = model;
}
public string FirstName
{
get
{
return Model.FirstName;
}
set
{
NotifyOfPropertyChange(() => FirstName);
NotifyOfPropertyChange(() => FullName);
}
}
public string LastName
{
get { return Model.LastName; }
set
{
NotifyOfPropertyChange(() => LastName);
NotifyOfPropertyChange(() => FullName);
}
}
public string FullName => $"{FirstName} {LastName}";
}
public class UserControl2ViewModel : PropertyChangedBase
{
private IPersonModel _model;
public UserControl2ViewModel(IPersonModel model)
{
_model = model;
}
public string FirstName
{
get
{
return _model.FirstName;
}
set
{
_model.FirstName = value;
NotifyOfPropertyChange(() => FirstName);
//NotifyOfPropertyChange(() => FullName);
}
}
public string LastName
{
get { return _model.LastName; }
set
{
_model.LastName = value;
NotifyOfPropertyChange(() => LastName);
//NotifyOfPropertyChange(() => FullName);
}
}
}
UserControl2视图:
UserControl x:Class="UI.Views.UserControl2View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:UI.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="400">
<Grid>
<StackPanel Margin="12">
<TextBox Text="{Binding FirstName, Mode=TwoWay}" Margin="5"/>
<TextBox Text="{Binding LastName, Mode=TwoWay}" Margin="5"/>
<TextBlock Text="{Binding FirstName, Mode=OneWay}" Margin="5"/>
</StackPanel>
</Grid>
</UserControl>
UserControl1视图:
<UserControl x:Class="UI.Views.UserControl1View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:UI.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="350">
<Grid>
<StackPanel Margin="10">
<TextBlock Text="{Binding FirstName}" Margin="5"/>
<TextBlock Text="{Binding LastName}" Margin="5"/>
<TextBlock Text="{Binding FullName}" Margin="5"/>
</StackPanel>
</Grid>
</UserControl>
您需要使用Caliburn Micro中的EventAggregator
模式实现来通知在当前ViewModel中没有直接引用的另一个ViewModel的实例。
要做到这一点,您需要从定义一个消息类型开始,该消息类型可用于唯一标识特定的更改。
public class NotifyPersonModelChangeMessage
{
public IPersonModel PersonModel { get; set; }
}
下一步包括当所需属性发生变化时,从UserControl2ViewModel
发布NotifyPersonModelChangeMessage
类型的消息。
例如,
public class UserControl2ViewModel : PropertyChangedBase
{
private IPersonModel Model;
private IEventAggregator _eventAggregator;
public UserControl2ViewModel(IPersonModel model,IEventAggregator eventAggregator)
{
Model = model;
_eventAggregator = eventAggregator;
_eventAggregator.SubscribeOnUIThread(this);
}
public string FirstName
{
get
{
return Model.FirstName;
}
set
{
Model.FirstName = value;
NotifyOfPropertyChange(nameof(FirstName));
NotifyOfPropertyChange(nameof(FullName));
NotifyNameChange();
}
}
private void NotifyNameChange()
{
_eventAggregator.PublishOnUIThreadAsync(new NotifyPersonModelChangeMessage { PersonModel = Model });
}
}
这将向事件聚合器实现发布一条消息。下一步是确保UserControl1ViewModel
订阅消息并相应地进行更改。这可以通过Caliburn Micro 的IHandle<T>
接口的实现来实现
public class UserControl1ViewModel : PropertyChangedBase, IHandle<NotifyPersonModelChangeMessage>
{
private IPersonModel _model;
public UserControl1ViewModel(IPersonModel model, IEventAggregator eventAggregator)
{
_model = model;
eventAggregator.SubscribeOnUIThread(this);
}
public Task HandleAsync(NotifyPersonModelChangeMessage message, CancellationToken cancellationToken)
{
_model = message.PersonModel;
NotifyOfPropertyChange(nameof(FirstName));
NotifyOfPropertyChange(nameof(LastName));
return Task.CompletedTask;
}
// rest of the class
}
每次向EventAggregator发布NotifyPersonModelChangeMessage
类型的消息时,都会调用HandleAsync
方法,因为我们已经订阅了EventAggregate并正在侦听特定的消息类型。
您可以在Caliburn Micro 的官方文档中阅读更多关于EventAggregator的信息