Ich war jedoch nicht zufrieden mit dem, was ich bisher gefunden habe. Einige der Lösungen, die ich so weit zu komplex abgetan habe - für ein Bedarf, das sehr häufig ist und extrem einfach zu lösen wäre, wenn es das MVVM -Muster nicht verwendet, scheint es nicht so schwierig zu sein. Offensichtlich bietet das MVVM -Muster einige große Vorteile, die es immer noch zu einem würdigen Muster machen, aber ein Dialog zum Sammeln einiger Informationen in einem speziellen Fenster und dann ein Ergebnis des Aufrufansichtsmodells ist ein sehr häufiges Bedürfnis - zu häufig, um es zu einem solchen Mangel an Klarheit zu geben, wie man es mit dem Erreichen des Sichts -Modells einsteht. Viewa hat nie Kenntnis des Dialogfelds für den hervorgebrachten Dialog. Und andere Ansätze erfüllen nicht mindestens eines der oben genannten Kriterien. Es ist nicht so wunderbar einfach wie es wäre, wenn alles in Code-Behind erfolgen würde, aber ich fand es recht einfach, und es sind keine zusätzlichen externen Abhängigkeiten erforderlich. />
DIALOGEVENTARGS.CS
Code: Select all
public delegate void DialogEventHandler(DialogEventArgs args);
public class DialogEventArgs(TIn input) : EventArgs
{
public Window Dialog { get; set; }
public TIn Input { get; } = input;
public TOut Output { get; set; }
public bool Accepted { get; private set; }
public void ShowDialog(Window parentWindow)
{
Dialog.OwnerWindow = parentWindow;
Accepted = (bool)Dialog.ShowDialog();
}
}
ViewModelBase.cs
Code: Select all
public abstract class ViewModelBase
{
public event EventHandler RequestClose;
protected void OnRequestClose()
{
RequestClose?.Invoke(this, EventArgs.Empty);
}
}
categoriesViewModel.cs
Code: Select all
public class CategoriesViewModel : ViewModelBase
{
private DialogEventArgs _dialogArgs;
public List SelectedCategories { get; } = [];
public CategoriesViewModel(DialogEventArgs args)
{
_dialogArgs = args;
var input = args.Input;
// do something with input - e.g. initialize a list or something
}
[RelayCommand]
public void Cancel()
{
// do some clean up work
OnRequestClose();
}
[RelayCommand]
public void Commit()
{
args.Output = SelectCategories;
OnRequestClose();
}
}
< /code>
Das Dialogfenster übergibt das DialogEnventArgs an das Ansichtsmodell und zeichnet sich ab, um auf das RequestClose -Ereignis zu antworten. Es bietet auch eine Werksmethode zum Erstellen der DialogEGEventArgs (da dieses Dialogfeld in der gesamten Anwendung verwendet werden kann).public partial class CategoriesDialog() : Window
{
public CategoriesDialog(DialogEventArgs args)
{
InitializeComponent();
var vm = new CategoriesViewModel(args);
DataContext = vm;
vm.RequestClose += (s, e) => Close();
}
public static DialogEventArgs GetDialogArgs(List input)
{
var args = new DialogEventArgs(input);
args.Dialog = new ChooseCategories(args);
return args;
}
}
mainwindow.cs
Code: Select all
public class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
vm = new MainViewModel();
vm.RequestCategoriesDialog += args => args.ShowDialog(this);
}
}
MainViewModel.cs
public class MainViewModel : ViewModelBase
{
public event DialogEventHandler RequestCategoriesDialog;
public List CurrentCategories { get; } = [];
[RelayCommand]
private void UpdateCategories()
{
var args = CategoriesDialog.GetDialogArgs(CurrentCategories);
RequestCategoriesDialog?.Invoke(args);
if (args.Accepted)
{
// respond to acceptance
}
}
}
< /code>
Auf diese Weise bleiben beide Ansichtsmodelle in Bezug auf UI-Bedenken agnostisch, und beide UIs sind agnostisch über die Eingaben und Ausgänge, die von den View-Modellen hin und her übergeben werden und können einfach als Boten zwischen den beiden fungieren, während das erforderliche UI-Verhalten durchgesetzt wird. Wenn ich dieses Verhalten mehr implementieren würde, hätte ich wahrscheinlich eine "DialogViewModelBase" -Klasse, um dieses Muster wiederholbarer zu machen, wollte das obige Beispiel jedoch zu viel Pilzing abhalten.