我建立了一个虚拟UserControl
,它的代码后面有一个显示消息的方法!我已经在主窗口中使用了此控件,并且想在使用Commands和MVVM单击Button
时执行其方法。我该怎么办?
<UserControl x:Class="ControlBining.Control1"
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"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid DataContext="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}">
</Grid>
</UserControl>
C#:
public partial class Control1 : UserControl
{
public Control1()
{
InitializeComponent();
}
public void ShowMessage()
{
MessageBox.Show("Called from other control!");
}
}
MainWindow XAML:
<Window x:Class="ControlBining.MainWindow"
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"
xmlns:local="clr-namespace:ControlBining"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<StackPanel Margin="0 50 0 0">
<local:Control1 Width="100"/>
<Button Width="100" Content="Show Message"/>
</StackPanel>
</Window>
RelayCommand:
public class RelayCommand : ICommand
{
private readonly Predicate<object> m_canExecute;
private readonly Action<object> m_execute;
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
{
m_canExecute = canExecute;
m_execute = execute;
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object parameter)
{
return m_canExecute(parameter);
}
public void Execute(object parameter)
{
m_execute(parameter);
}
}
当前,我已经使它起作用了,但是我真的不确定它是否是一个好的设计:
控制代码隐藏
private void Control1_Loaded(object sender, RoutedEventArgs e)
{
ViewModel m = (ViewModel)DataContext;
m.ShowMessage += M_ShowMessage;
}
private void M_ShowMessage()
{
ShowMessage();
}
在ViewModel中
public event Action ShowMessage;
private ICommand m_showMessageCommand;
public ICommand ShowMessageCommand
{
get
{
return m_showMessageCommand ?? (m_showMessageCommand = new RelayCommand(
p => true,
p => ShowMessage?.Invoke()));
}
}
XAML:
答案 0 :(得分:1)
如果只需要显示一条消息,则应将ShowMessage()
方法移至视图模型,并使用消息服务从视图模型类中执行此操作。
如果您真的想调用仅在视图中定义才有意义的某种方法,则可以通过在视图中实现接口并使用该接口注入视图模型来实现。例如,当您调用命令时:
public interface IView
{
void ShowMessage();
}
public partial class Control1 : UserControl, IView
{
public Control1()
{
InitializeComponent();
}
public void ShowMessage()
{
MessageBox.Show("Called from other control!");
}
}
查看模型:
public ICommand ShowMessageCommand
{
get
{
return m_showMessageCommand ?? (m_showMessageCommand = new RelayCommand(
p => true,
p =>
{
IView view as IView;
if (view != null)
{
//...
view.ShowMessage();
}
}));
}
}
视图模型对视图一无所知,只知道一个接口,当然可以将其称为IView
之外的其他名称。
另一种选择是使用事件聚合器或Messenger,以耦合方式将事件或消息从视图模型发送到视图。请参阅this博客文章,以获取有关此信息的更多信息。
这两种方法都不会破坏MVVM模式。