【发布时间】:2019-01-01 02:23:15
【问题描述】:
我创建了一个带有 2 个视图模型及其相关视图的 wpf 项目(使用 caliburn micro 和 MVVM 模式,没有代码隐藏):
- ShellView.xaml 和 ShellViewModel.cs
- OtherView.xaml 和 OtherViewModel.cs
ShellView 包含:
- ContentControl 指的是 OtherView/OtherViewModel。
- 一个文本框,其中包含所谓的“目标文本”。
OtherView 包含一个 StackPanel,其中包含:
- 接受来自用户的文本(作为“源文本”)的文本框。
- 在 Right-MouseButton 单击事件上将源文本复制到目标的按钮。
我的问题:
- 如何将OtherView/ViewModel中的源文本复制到ShellView/ViewModel中的目标文本?有什么最佳做法吗?
- ShellViewModel 能否从源 TextBox 捕获 PropertyChange 事件?
- 如何反向复制(从目标到源)?
提前感谢您,如果需要,请随时修改下面的代码。
ShellView.xaml
<UserControl
x:Class="CmMultipleViewModelView.Views.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid Width="800" Height="450">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ContentControl
x:Name="ActiveItem"
Grid.Column="0"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<TextBox
x:Name="TargetText"
Grid.Column="1"
Width="80"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</UserControl>
ShellViewModel.cs
public class ShellViewModel : Conductor<object>
{
public ShellViewModel()
{
DisplayName = "Shell Window";
var otherVM = new OtherViewModel();
ActivateItem(otherVM);
}
public string DisplayName { get; set; }
private string _targetText = "Target";
public string TargetText
{
get => _targetText;
set
{
_targetText = value;
NotifyOfPropertyChange(() => TargetText);
}
}
}
OtherView.xaml
<UserControl
x:Class="CmMultipleViewModelView.Views.OtherView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="150"
d:DesignWidth="150"
mc:Ignorable="d">
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Top"
Orientation="Vertical">
<TextBox
x:Name="SourceText"
Width="80"
Margin="3" />
<Button
x:Name="CopyText"
Width="100"
Margin="3"
Content="Copy" />
</StackPanel>
</UserControl>
OtherViewModel.cs
public class OtherViewModel : Screen
{
private string _sourceText = "Source";
public string SourceText
{
get => _sourceText;
set
{
_sourceText = value;
NotifyOfPropertyChange(() => SourceText);
}
}
public void CopyText()
{
// How to copy the SourceText to TargetText using Caliburn Micro MVVM?
// Can ShellViewModel catch the PropertyChange event from source textbox?
}
}
已编辑:
AppBootstrapper.cs
public class AppBootstrapper : BootstrapperBase
{
private readonly SimpleContainer _container = new SimpleContainer();
public AppBootstrapper()
{
Initialize();
}
public ShellViewModel ShellViewModel { get; set; }
protected override object GetInstance(Type serviceType, string key)
{
return _container.GetInstance(serviceType, key);
}
protected override IEnumerable<object> GetAllInstances(Type serviceType)
{
return _container.GetAllInstances(serviceType);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
protected override void Configure()
{
base.Configure();
_container.Singleton<IWindowManager, WindowManager>();
_container.Singleton<IEventAggregator, EventAggregator>();
_container.Singleton<ShellViewModel>();
_container.PerRequest<OtherViewModel>(); // Or Singleton if there'll only ever be one
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
try
{
base.OnStartup(sender, e);
DisplayRootViewFor<ShellViewModel>();
}
catch (Exception ex)
{
Debug.WriteLine(ex.StackTrace);
Debug.WriteLine(ex.Message);
}
}
}
ShellViewModel.cs
public class ShellViewModel : Conductor<object>, IHandle<string>
{
private readonly IEventAggregator _eventAggregator;
public ShellViewModel(IEventAggregator eventAgg, OtherViewModel otherVm)
{
_eventAggregator = eventAgg;
_eventAggregator.Subscribe(this);
ActivateItem(otherVm);
}
public sealed override void ActivateItem(object item)
{
base.ActivateItem(item);
}
public OtherViewModel OtherViewModel { get; set; }
private string _targetText = "Target";
public string TargetText
{
get => _targetText;
set
{
_targetText = value;
NotifyOfPropertyChange(() => TargetText);
}
}
public void Handle(string message)
{
TargetText = message;
}
}
OtherViewModel.cs
public class OtherViewModel : Screen
{
private readonly IEventAggregator _eventAggregator;
public OtherViewModel(IEventAggregator eventAgg)
{
_eventAggregator = eventAgg;
}
private string _sourceText = "Source";
public string SourceText
{
get => _sourceText;
set
{
_sourceText = value;
NotifyOfPropertyChange(() => SourceText);
}
}
public void CopyText()
{
_eventAggregator.PublishOnUIThreadAsync(SourceText);
}
}
再次编辑
添加
_container.Singleton<IWindowManager, WindowManager>();
在 AppBootstraper::Configure 中
问题解决了!
【问题讨论】:
-
在设置
ActivateItem期间,您可以将DataContext 设置为OtherViewModel的一些新属性,然后在CopyButton的OtherView 中,您可以创建Command,并将CommadParameter 绑定到newPropertyWithDataContextOfShellView.TargetText跨度> -
或者只是使用某种 Messenger
-
事件聚合器和自定义事件是正确的解决方案。这减少了视图之间的耦合,并允许您完全替换 ShellViewModel 或 OtherViewModel 功能而无需更改另一个。
标签: c# wpf xaml mvvm caliburn.micro