在WPF中的用户控制2中使用MVVM修改用户控制1中模型的属性时,更新该属性



我有一个主窗口,其中包含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的信息

最新更新