Я работал над некоторыми примерами и применял то, что узнал, чтобы создать приложение для импорта WPF. То, что у меня сейчас есть, работает должным образом, но я стараюсь максимально следовать шаблону MVVM. Я открываю другое окно нажатием кнопки и привязываю значение, выбранное в ListBox, к экземпляру модели, которая будет использоваться в следующем окне. Пока я работал с примерами, я задал вопрос о том, что ViewModel должна быть моделью, когда я пытался реализовать это, я не мог заставить его работать, какие-либо предположения?
Это мой HomeView, это представление содержит ListBox и кнопка. Пользователь выберет значение из ListBox, и кнопка перейдет в новое окно и будет использовать выбранное значение, чтобы применить информацию к новому окну
<Window x:Class="DICOM_Importer.Views.HomeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DICOM_Importer.Views"
mc:Ignorable="d"
Background="Gold"
Title="DICOM Importer" Height="385" Width="600">
<Grid Style="{StaticResource gridBackground}">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Column="1" Grid.Row="0" Style="{StaticResource homeTitle}">DICOM IMPORTER</Label>
<Image x:Name="appil_logo" Grid.Column="0" Grid.Row="0" Grid.RowSpan="4" Source="/assets/appil_logo.png"/>
<Border Grid.Column="1" Grid.Row="0" Style="{StaticResource studyListHeader}" Width="Auto">
<Label Style="{StaticResource studyListText}">Active Studies</Label>
</Border>
<ListBox Name="activeStudiesListBox" Grid.Column="1" Grid.Row="2" ItemsSource="{Binding Studies}" SelectedItem="{Binding SelectedStudy}">
<ListBox.ItemTemplate>
<DataTemplate DataType="Study">
<TextBlock Text="{Binding StudyTitle}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Grid.Row="3" Grid.Column="1" Style="{StaticResource buttonStyle}" Command="{Binding NavigateCommand}" Content="Select" />
</Grid>
</Window>
Вот HomeViewModel, который содержит ссылку на childView , StudyImporterView и StudyImporterViewModel. Когда происходит навигация, значения применяются к StudyImporterViewModel для привязки к элементам в StudyImporterView
using DICOM_Importer.Commands;
using DICOM_Importer.Models;
using DICOM_Importer.Views;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Xml.Linq;
namespace DICOM_Importer.ViewModels
{
public class HomeViewModel
{
//setting up some variable that will be use through this class
// the private read only is setting up a Studies data type that will have a studies object attached to it
public ObservableCollection<Studies> Studies { get; set; }
private StudyImporterViewModel importViewModel;
private Studies selectedStudy;
public HomeViewModel()
{
NavigateCommand = new SelectStudyToImport(this);
importViewModel = new StudyImporterViewModel();
string path_to_debug_folder = Directory.GetCurrentDirectory();
string path = Path.GetFullPath(Path.Combine(path_to_debug_folder, @"..\..\")) + @"Data\Studies.xml";
var xmlRootElement = XElement.Load(path);
List<Studies> studies = xmlRootElement.Descendants("Study")
.Select(CreateModelFromStudyXmlNode)
.ToList();
this.Studies = new ObservableCollection<Studies>(studies);
}
private Studies CreateModelFromStudyXmlNode(XElement studyXmlNode)
{
var newStudy = new Studies();
newStudy.StudyTitle = studyXmlNode.Element("StudyTitle").Value;
newStudy.ImportDirectory = studyXmlNode.Element("ImportDirectory").Value;
return newStudy;
}
public Studies SelectedStudy
{
get { return selectedStudy; }
set { selectedStudy = value; }
}
public ICommand NavigateCommand
{
get;
set;
}
public void Navigate()
{
StudyImporterView view = new StudyImporterView();
view.DataContext = importViewModel;
importViewModel.ImporterTitle = SelectedStudy.StudyTitle;
importViewModel.ImporterPath = SelectedStudy.ImportDirectory;
view.ShowDialog();
}
}
}
Вот StudyModel, который использует вышеуказанный класс
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DICOM_Importer.Models
{
/// <summary>
/// Model class for study titles and import directories for active studies
/// </summary>
///
//When using the MVVM pattern approach all classes should inherit from the INotifyPropertyChanged interface
//this is what allows the two-way binding functionality
public class Studies : BaseModel
{
//every property in the Model Object should have a private variable outside of the Object
private string studyTitle;
private string importDirectory;
//this is a data object with a single property of studyTitle
//it return the private variable in Get and updates that variable through the OnPropertyChanged event
public string StudyTitle
{
get { return studyTitle; }
set
{
studyTitle = value;
OnPropertyChanged("StudyTitle");
}
}
public string ImportDirectory
{
get { return importDirectory; }
set
{
importDirectory = value;
OnPropertyChanged("ImportDirectory");
}
}
}
}
Вот класс это вопрос StudyImporterViewModel, он выглядит как модель. Есть ли способ, которым я могу создать StudyImporterModel, а затем использовать его в StudyImporterViewModel, чтобы сохранить мой код более согласованным?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DICOM_Importer.ViewModels
{
public class StudyImporterViewModel : INotifyPropertyChanged
{
private string importerTitle;
private string importerPath;
/// <summary>
/// Gets the study information from the HomeView
/// </summary>
public String ImporterTitle
{
get { return importerTitle; }
set
{
importerTitle = value;
OnPropertyChanged(ImporterTitle);
}
}
public String ImporterPath
{
get { return importerPath; }
set
{
importerPath = value;
OnPropertyChanged(ImporterPath);
}
}
#region PropertyChangedEventHandler
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
Вот StudyImporterView
<Window x:Class="DICOM_Importer.Views.StudyImporterView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DICOM_Importer.Views"
mc:Ignorable="d"
Background="Gold"
Title="Importer" Height="450" Width="800">
<Grid Style="{StaticResource gridBackground}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="125" />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="280" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal">
<Label Style="{Binding Source={StaticResource studyTitle}}" Content="Study:" />
<Label Style="{Binding Source={StaticResource studyTitle}}" Name="StudyImportViewStudyText" Content="{Binding ImporterTitle}" />
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Orientation="Horizontal" >
<Label Style="{Binding Source={StaticResource studyTitle}}" Content="Import Directory" />
<Label Style="{Binding Source={StaticResource studyTitle}}" Content="{Binding ImporterPath}" />
</StackPanel>
<Button Grid.Column="2" Grid.Row="1" Style="{Binding Source={StaticResource buttonStyleImport}}" Content="Submit" />
<TextBox Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="2" x:Name="TestBox" />
</Grid>
</Window>
Я вернул свой код обратно в рабочее состояние, но раньше, когда я пытался реализовать использование модели вместо использования существующего StudyImporterViewModel I продолжал получать пустое исключение в методе Navigate в HomeViewModel при попытке применить importViewModel.ImporterTitle = SelectedStudy.StudyTitle;