私はWPFとMVVMパターンを学習しています。私は物事を正しく実装していない可能性があります。コンポーネントとしてのユーザーコントロール。親ウィンドウへのアクセスがありません
Windows上でコンポーネントを使用できるユーザーコントロールオブジェクトを使用して、アプリケーションのウィンドウのコンポーネントを構築したいと考えています。たとえば、私は、ダイアログウィンドウの唯一のコンポーネントとして、またMainWindowのコンポーネントとして使う予定のNewUnitUserControlを持っています。
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を設定せずに、ユーザーコントロールを介して、自己完結型の再利用可能な "コンポーネント"を作成するか分かりません。ユーザーコントロールを構成するものが私の考え方に間違っていますか?これを行う別の方法はありますか? – ZackDeRose
最も良い方法は、ビューモデルとモデルのグラフを使ってアプリケーションの状態を表現することです。このオブジェクトグラフのルートは、メインウィンドウのDataContextです。コントロールはこのルートのプロパティにバインドされています。例えば、それは、観察可能な子ビューモデルの集合を有することができる。コレクションは、ListViewのItemsSourceにバインドされています。子タイプごとにItemTypeを持つDataTemplatesが定義され、その中にその子のために設計されたUserControlが配置されます。 ListViewがNewUnitViewModel型のDataTemplateを探すと、テンプレートとpoofが見つかります。 – Will