用户控件作为组件。无法访问父窗口

时间:2016-09-13 18:32:40

标签: c# wpf xaml mvvm

我正在学习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模式。

2 个答案:

答案 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(我认为这就是所谓的)来发送来自按钮命令操作的消息。