Я изучаю WPF и шаблон MVVM, и я могу неправильно выполнять вещи.Пользовательский контроль в качестве компонентов. Нет доступа к родительскому окну
Я хочу построить компоненты для окон моего приложения, используя объекты User Control, где компоненты могут использоваться в 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.
'NewUnitViewModel cuvm = new NewUnitViewModel(); DataContext = nuvm; 'это запах кода. Ваш пользовательский элемент управления должен вести себя как элемент управления. Элементы управления не устанавливают свой DataContext. Создает ли TextBox экземпляр TextBoxViewModel и устанавливает его как DataContext? Это помешало бы вам отказаться от этого. – Will
@ Пока я вижу вашу точку зрения. Я не вижу, как создать автономный многоразовый «компонент» с помощью пользовательского элемента управления, не устанавливая DataContext User Control. Что-то не так с моей концепцией того, что составляет пользовательский контроль? Есть ли другой способ сделать это? – ZackDeRose
Лучший способ представить состояние вашего приложения через график моделей и моделей. Корнем этого графа объектов является DataContext главного окна. Элементы управления привязаны к свойствам этого корня. Например, он может иметь наблюдаемую коллекцию моделей детского просмотра. Сбор привязан к элементу ItemsSource ListView. Определены DataTemplates с ItemType для каждого типа дочерних элементов, и в них помещается UserControl, предназначенный для этого дочернего элемента. Теперь, когда ListView ищет DataTemplate типа NewUnitViewModel, он находит шаблон и poof! – Will