我有一个简单的窗口,里面有一个UserControl“NewCardView”。取消按钮需要调用MainWindow视图模型中包含的函数,以便切换当前显示的UserControl。当我按下按钮时它什么也没做,没有什么可追查的,就像它没有任何约束力一样。我已经尝试绑定到该窗口的datacontext但我没有成功。
<UserControl x:Class="MapProject.View.NewCardView"
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:MapProject.MainView.View"
xmlns:mainwin="clr-namespace:MapProject"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Label x:Name="labeltitle" Content="New Card" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,10,0,0"/>
<ComboBox x:Name="comboBox" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" Margin="133,43,0,0"/>
<TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="133,74,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="23" Margin="133,105,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<DatePicker HorizontalAlignment="Left" VerticalAlignment="Top" Margin="133,136,0,0" Width="120"/>
<Label x:Name="label" Content="District" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="62,43,0,0"/>
<Label x:Name="label1" Content="Map #" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="62,74,0,0"/>
<Label x:Name="label2" Content="Parcel #" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="62,105,0,0"/>
<Label x:Name="label3" Content="Date From" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="62,136,0,0"/>
<Button x:Name="button" Content="OK" HorizontalAlignment="Left" Margin="78,184,0,0" VerticalAlignment="Top" Width="75"/>
<Button x:Name="button_Copy" Content="Cancel" CommandParameter="Blank" Command="{Binding DataContext.ChangePageCommand, BindsDirectlyToSource=True, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type mainwin:MainWindow}}}" HorizontalAlignment="Left" Margin="178,184,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
public ICommand ChangePageCommand
{
get
{
if (_changePageCommand == null)
{
_changePageCommand = new RelayCommand(p => ChangeViewModel(p.ToString()), p => p is string);
}
return _changePageCommand;
}
MainWindow包含此
<DataTemplate DataType="{x:Type mainviewviewmodel:NewCardViewModel}">
<mainview:NewCardView/>
</DataTemplate>
using System;
using System.Diagnostics;
using System.Windows.Input;
namespace MapProject
{
/// <summary>
/// A command whose sole purpose is to
/// relay its functionality to other
/// objects by invoking delegates. The
/// default return value for the CanExecute
/// method is 'true'.
/// </summary>
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="execute">The execution logic.</param>
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameters)
{
return _canExecute == null ? true : _canExecute(parameters);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameters)
{
_execute(parameters);
}
#endregion // ICommand Members
}
}
答案 0 :(得分:0)
正如Clemens正确建议的那样,最好的解决方案是将 ChangePageCommand 命令保留在 NewCardViewModel 级别。创建NewCardViewModel时,初始化ChangePageCommand命令,以便从MainViewModel 调用方法:
public class MainViewModel {
public void CreateNewCard() {
NewCardViewModel newCardModel = new NewCardViewModel();
newCardModel.ChangePageCommand = new RelyCommand(Cancel);
//...
}
void Cancel() {
}
}
public class NewCardViewModel {
public ICommand ChangePageCommand {
get;
set;
}
}
在这种情况下,以下简单绑定应该正常工作:
<Button Command="{Binding ChangePageCommand}" ... />
如果您不希望以这种方式在MainViewModel中初始化NewCardViewModel,则可以使用free DevExpress MVVM Framework制作子视图模型aware of their parents。
使用相同MVVM框架的另一种解决方案是使用Messenger在不同的视图模型之间进行通信。使用这种方法,您可以在MainViewModel级别注册一个操作,并从NewCardViewModel调用它,而不会创建任何强依赖项甚至接口。