我正在学习WPF和MVVM模式,我可能会错误地实现。
我想使用用户控件对象为我的应用程序窗口构建组件,其中组件可以在Windows上使用。举个例子,我有一个NewUnitUserControl,我打算用它作为对话窗口的唯一组件,也作为MainWindow的组件。
NewUnitUserControl.xaml:
<UserControl x:Class="Sample.Views.UserControls.NewUnitUserControl"
...
xmlns:local="clr-namespace:Sample.Views.UserControls">
<Grid>
<StackPanel Orientation="Vertical">
<Border>
<StackPanel Orientation="Horizontal">
<Label>Name:</Label>
<TextBox Text="{Binding Unit.Name}" Width="136"/>
</StackPanel>
</Border>
<Border HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal">
<Border>
<Button Command="{Binding CreateUnitCommand}">Create</Button>
</Border>
<Border>
<Button Command="{Binding CancelCommand}">Cancel</Button>
</Border>
</StackPanel>
</Border>
</StackPanel>
</Grid>
</UserControl>
NewUnitUserControl.xaml.cs:
namespace Sample.Views.UserControls
{
public partial class NewUnitUserControl : UserControl
{
public NewUnitUserControl()
{
InitializeComponent();
NewUnitViewModel nuvm = new NewUnitViewModel();
DataContext = nuvm;
if (nuvm.CloseAction == null)
{
var window = Window.GetWindow(this); // window evaluates to null
// after this line.
nuvm.CloseAction = new Action(window.Close);
}
}
}
}
NewUnitViewModel.cs
namespace Sample.ViewModels
{
internal class NewUnitViewModel : INotifyPropertyChanged
{
//Properties
private Unit _unit;
public Unit Unit
{
get { return _unit; }
set { _unit = value; OnPropertyChanged("Unit"); }
}
public Action CloseAction { get; set; }
private ICommand _createUnitCommand;
public ICommand CreateUnitCommand
{
get
{
if (_unitUpdateCommand == null)
_unitUpdateCommand = new RelayCommand(param => CreateUnit(), param => true);
return _unitUpdateCommand;
}
}
private ICommand _cancelCommand;
public ICommand CancelCommand
{
get
{
if(_cancelCommand == null)
_cancelCommand = new RelayCommand(param => Cancel(), param => true);
return _cancelCommand;
}
}
//Constructor
public CreateUnitViewModel()
{
_unit = new Models.Unit();
}
//Methods
public void CreateUnit()
{
Debug.Assert(false, String.Format("{0} was created.", Unit.Name));
}
public void Cancel()
{
this.CloseAction();
}
#region INotifyProperty Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
NewUnitDialogWindow.xaml:
<Window x:Class="Sample.Views.NewUnitWindow"
...
xmlns:local="clr-namespace:Sample.Views"
xmlns:controls="clr-namespace:Sample.Views.UserControls"
>
<controls:NewUnitUserControl />
</Window>
NewUnitDialogWindow.xaml.cs
namespace Sample.Views
{
public partial class NewUnitWindow : Window
{
public NewUnitWindow()
{
InitializeComponent();
}
}
}
完整来源:GitHub
我面临的问题是,在我的实施中,我无法使用解决方案here访问用户控件的父窗口(请参阅NewUnitUserControl中的注释。 xaml.cs)。我希望我的问题的根源是我没有正确理解MVVM模式。
答案 0 :(得分:0)
您尝试访问父窗口的方式对我来说似乎并不熟悉。
var window = Window.GetWindow(this);
请尝试以下代码。我编辑了你的,所以只需更换它:)
public NewUnitUserControl()
{
InitializeComponent();
CreateUnitViewModel cuvm = new CreateUnitViewModel();
DataContext = nuvm;
if (nuvm.CloseAction == null)
{
//var window = this.ParentForm; // window evaluates to null
// // after this line.
if(this.ParentForm != null)
cuvm.CloseAction = new Action(this.ParentForm.Close);
}
}
答案 1 :(得分:0)
我认为问题是用户控件不知道父窗口是谁。尝试移动到Loaded事件:
private Window _parentWindow = null;
public NewUnitUserControl()
{
InitializeComponent();
Loaded += (s, e) =>
{
_parentWindow = Window.GetWindow(this);
/// whatever you are going to do with parent window
}
}
您还可以使用来自Prism工具包的IEventAggregator或者MvvmToolkit中的IMessenger(我认为这就是所谓的)来发送来自按钮命令操作的消息。