I have read the other questions regarding a matter similar to this, but it dosn't quite ask for a solution to this simple scenario:
namespace View
{
/// <summary>
/// Interaction logic for PuzzleSelectionScreen.xaml
/// </summary>
public partial class PuzzleSelectionScreen : Page
{
public PuzzleSelectionScreen(PuzzleControllerVM puzzleControllerVM, ScreenSwitcher screenSwitcher)
{
InitializeComponent();
// My button needs a command in screenSwitcher (View) to change Page ..
// .. with a Property (puzzle data) from puzzleControllerVM (View Model)
this.DataContext = puzzleControllerVM;
this.DataContext = screenSwitcher;
}
}
}
I can stick screenSwitcher in puzzleControllerVM and access all the properties just by this.DataContext = puzzleControllerVM;, but this would violate MVMM as screenSwitcher contains many View objects.
What I do above, the DataContext will assign to screenSwitcher only because it is executed last, but I want a convenient solution so my DataContext will have access to both sources without having to stick my screenSwitcher in my view model class PuzzleControllerVM.
U can create a new type which hold reference to both and set the datacontext to the instance of the type.
Something like this
public PuzzleSelectionScreen(PuzzleControllerVM puzzleControllerVM, ScreenSwitcher screenSwitcher)
{
InitializeComponent();
this.DataContext = new Hybrid { PuzzleControllerVM = puzzleControllerVM, ScreenSwitcher = screenSwitcher };
}
public class Hybrid
{
public PuzzleControllerVM PuzzleControllerVM { get; set; }
public ScreenSwitcher ScreenSwitcher { get; set; }
}
Related
I'm familiar with MVVM and differences between models, viewmodels and views. The only thing that I'm not able to find answer to is how to update models at runtime. Simple example to show you what I mean:
Let's say I have application which can display graphs and store them in a database.
I have models
public class Session {
public Document Doc { get; set; }
}
public class Document {
public string Name { get; set; }
public Point[] GraphPoints { get; set; }
}
I can connect those to their viewmodels by passing them as parameters, so:
public class SessionViewModel{
private readonly Session _session;
public SessionViewModel(Session session)
{
this._session = session;
}
}
public class DocumentViewModel{
private readonly Document_document;
public SessionViewModel(Document document)
{
this._document = document;
}
}
public class ShellViewModel {
public SessionViewModel SessionVm { get; set; } // <-- Bind in view
public DocumentViewModel DocumentVm { get; set; } // <-- Bind in view
private Session _session;
public ShellViewModel()
{
_session = new Session();
session.Doc = new Document();
SessionVm = new SessionViewModel(session);
DocumentVm = new DocumentViewModel(session.Doc);
}
}
Problem appears when in the middle of my application's life cycle I decide to change value of document. For example:
public void OnNewDocumentLoaded(Document newDoc)
{
_session.Doc = newDoc;
}
_session.Doc was changed but every DocumentViewModel has its own instance of document which is passed in a constructor, so even though I changed model, my viewmodel stays the same.
Also I don't want to use INotifyPropertyChanged inside my model, because models should not know about framework and from my understanding this is a bad approach. Also I keep my models in PCL project so I'm not even able to implement INotifyPropertyChanged in my models.
From my understanding of a MVVM approach, models should not have a viewmodel associated with them. Instead, your views should have a viewmodel associated to them. Inside your viewmodel you can have objects from models in your application. Inside your viewmodel is where you should implement INotifyPropertyChanged. Those methods control the objects you have changed and then binding can occur between your view and viewmodel.
Sorry for long and descriptive question, but it really bugs me for a long time. I have a problem with MVVM pattern.
I wrote application which actually works, but I don't think it's in a good style. My view model strucure looks like tree: it has references to all child viewmodels which are used to render proper view in ContentPresenter.
Take a look at sample GUI:
Home tab
--------------------------------------
HOME SETTINGS ADMINPANEL
======---------------------------------
______________________________________
/////////
///////// Home content
/////////
Settings tab
--------------------------------------
HOME SETTINGS ADMINPANEL
------============---------------------
______________________________________
settings1 > settings2 > other...
/////////
///////// Settings1 content
/////////
Notice the submenu which appears only in Settings view. Every switchable view is somehow dependent on model type. settings1 is visible only if model property is Type.One, and settings2 is visible when property is Type.Two.
Take a fast look into my current code: common interface for every view that I can change by click. PageHeader is displayed on button change content view:
public interface IPageVM
{
string PageHeader { get; set; }
}
and view models:
public class WindowVM : ViewModelBase
{
public ObservableCollection<IPageVM> ViewModels { get; set; }
public IPageVM CurrentTab { get; set; }
public ICommand ChangeViewModel { get; set; }
private Model _model;
public WindowVM()
{
_model = new Model();
ViewModels = new ObservableCollection<IPageVM>();
ViewModels.Add(new HomeVM(model));
ViewModels.Add(new SettingsVM(model));
if(_model.Admin)
ViewModels.Add(new AdminVM(model));
}
}
public class HomeVM : ViewModelBase, IPageVM
{
public string PageHeader { get { return "HOME"; } }
string Property { get; set; }
public HomeVM(Model model)
{
this.Property = model.Property;
}
}
public class SettingsVM : ViewModelBase, IPageVM
{
public string PageHeader { get { return "SETTINGS"; } }
public ObservableCollection<IPageVM> Tabs { get; set; }
public IPageVM CurrentTab { get; set; }
public ICommand ChangeViewModel { get; set; }
public SettingsVM(Model model)
{
Tabs = new ObservableCollection<IPageVM>();
if(model.Type = Type.One)
Tabs.Add(new Settings1VM(model));
if(model.Type = Type.Two)
Tabs.Add(new Settings2VM(model));
Tabs.Add(new OtherSettingsVM());
CurrentTab = Tabs[0];
}
}
public class Settings1VM: ViewModelBase, IPageVM
{
public string PageHeader { get { return "settings1"; } }
public Settings1VM(Model model)
{
}
}
public class Settings2VM: ViewModelBase, IPageVM
{
public string PageHeader { get { return "settings2"; } }
public Settings1VM(Model model)
{
}
}
xaml:
display buttons in ItemsControl that will change CurrentViewModel and render appropriate view bounded to viewmodels' type by DataTemplate.
Pros:
it already works
I can easily tell how does my GUI structure looks, because root viewmodel contains its children viewmodels and so on.
it's easy to inject data model to children by constructor.
Cons:
xaml code is all a DataTemplate
UserControls are empty in preview mode, it's hard to edit GUI
terrifying future: how will look my viewmodels structure if my application will grow a bit?
So I decided to change my ViewModels to something that looks more like WPF MVVM:
public class WindowVM : ViewModelBase
{
public bool AdminMode { get; set; }
public WindowVM()
{
_model = new Model();
AdminMode = _model.Admin;
AnotherTabVisibilityDependency = _model.Dependency;
}
}
xaml:
<TabControl>
<TabItem Header="HOME">
<TabItem.DataContext>
<vm:HomeVM/>
</TabItem.DataContext>
</TabItem>
<TabItem Header="SETTINGS">
<TabItem.DataContext>
<vm:SettingsVM/>
</TabItem.DataContext>
</TabItem>
<TabItem Header="ADMINPANEL" Visibility="{Binding AdminMode, Converter BoolToVisibility}">
<TabItem.DataContext>
<vm:AdminVM/>
</TabItem.DataContext>
</TabItem>
<TabItem Header="DEPENDANT" Visibility="{Binding AnotherTabVisibilityDependency, Converter BoolToVisibility}">
</TabItem>
</TabControl>
As you probably see, everything is clean, chaning UI is easy; not too much templates to write. Everything looks fine... But there is a thing I don't understand: Now each ViewModel is a separate instance that doesn't know about its parent. I can't pass model that easy.
Questions:
how can I inject data model into each viewmodel? I can't do it via xaml. Do I need to have a global static class with program state, or IoC? Maybe another way?
any alternative approaches? Maybe my second approach also isn't good?
does it make sense to rewrite my logic which actually works? I really hope it does (I hate my viewmodels' code).
Ok so I'm fairly new to this. I followed along with this MVVM tutorial from YouTube. It was pretty good and straightforward. Basically it sets up a very basic program with a Model class, DataAcess class, 3 viewmodels (Main window, Employee and ViewModelBase) and finally a view which has a stackpanel and a couple of text boxes that are bound to the FirstName and LastName in the Model.
It all works how it's meant to and I have been through it a number of times and I'm pretty sure I understand how it all works but the trouble that I am having is adding new Employees.
In the DataAccess class (Employee Repository) Employees are added as shown below.
class EmployeeRepository
{
readonly List<Employee> _employee;
public EmployeeRepository()
{
if (_employee == null)
{
_employee = new List<Employee>();
}
_employee.Add(Employee.CreateEmployee("Bob", "Jones"));
_employee.Add(Employee.CreateEmployee("Sarah", "Marshall"));
_employee.Add(Employee.CreateEmployee("Peter", "Piper"));
}
public List<Employee> GetEmployees()
{
return new List<Employee>(_employee);
}
}
And in the Model there is a method call CreateEmployee as such
public class Employee
{
public static Employee CreateEmployee(string firstName, string lastName)
{
return new Employee { FirstName = firstName, LastName = lastName };
}
public string FirstName { get; set; }
public string LastName { get; set; }
}
So I thought I would add a button to the MainWindow and then add another name to the list. Hopping the view would update as an item is updated. Just to see if it would work I just used the code behind.
I thought I could just add a new employee the same way I did in the EmployeeRepository so I tried this
readonly List<Employee> _employee = new List<Employee>();
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
_employee.Add(Employee.CreateEmployee("John", "Smith"));
}
I have tried many many ways of doing this, to no avail. I have watched and read many tutorials and questions, but nothing that I have tried as worked.
What am I missing? I initially thought that it was not working because I am adding the item to the List in the repository, but not to the ObservableCollection that is in the viewmodel. And the AllEmployees ObservableCollection is the ItemSource for view.
readonly EmployeeRepository _employeeRepository;
public ObservableCollection<Model.Employee> AllEmployees
{
get;
private set;
}
public EmployeeListViewModel(EmployeeRepository currentWindowRepository)
{
if (currentWindowRepository == null)
{
throw new ArgumentException("currentWindowRepository");
}
_employeeRepository = currentWindowRepository;
this.AllEmployees = new ObservableCollection<Model.Employee>(_employeeRepository.GetEmployees());
}
But in the button code I tried to implement something similar, but no.
I can also add the view xaml code and MainViewModel codes so that you can see how it's all bound if you like.
Thanks in advance for any help!
You can't do it in "one operation".
When you add a new Employee in the UI, you first need to instantiate your Employee class and add it to the observable collection.
If in valid state, then persist it to in the repository.
private ICommand addEmployeeCommand;
public ICommand AddEmployeeCommand { get { return addEmployeeCommand; } }
public ObservableCollection<Employee> Employees { get; protected set; }
private void AddEmployee()
{
// Get the user input that's bound to the viewmodels properties
var employee = Employee.Create(FirstName, LastName);
// add it to the observable collection
// Note: directly using model in your ViewModel for binding is a pretty bad idea, you should use ViewModels for your Employees too, like:
// Employee.Add(new EmployeeViewModel(employee));
Employees.Add(employee);
// add it to the repository
this.employeeRepository.AddOrUpdate(employee);
}
// in constructor
this.addEmployeeCommand = new DelegateCommand(AddEmployee, CanExecuteAddEmployee);
As noted, avoid directly using your model inside the ViewModel bindings, it has several disadvantages, like you view now depend on your viewmodel. each and every change in the model needs to be reflected in the view, this beats the purpose of a viewmodel which is meant to decouple view, viewmodel and model.
Another disadvantage is, that typically your models are do not implement INotifyPropertyChanged and this will cause memory leaks in the view.
In your EmployeelistViewModel you are creating ObservableCollection , and you think that it will get repopulated automatically upon addition/deletion of employees. secondly in your GetEmployees method you are creating a new list. you should use obser.coll directly in place of List (_employee). And return this ocoll from your method.
One solution to this is to add INPC to your models and to then have your view models watch their models and update themselves accordingly i.e. something like this:
public class MyListType
{
// some data
}
public class MyModel
{
public IList<MyListType> MyListItems { get; set; }
public MyModel()
{
this.MyListItems = new ObservableCollection<MyListType>();
}
}
public class MyListTypeViewModel : ViewModelBase
{
public MyListType Model {get; set;}
// INPC properties go here
}
public class MyViewModel
{
public IList<MyListTypeViewModel> MyListItemViewModels { get; set; }
public MyViewModel(MyModel model)
{
(model.MyListItems as INotifyCollectionChanged).CollectionChanged += OnListChanged;
// todo: create initial view models for any items already in MyListItems
}
private void OnListChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// create any new elements
if (e.NewItems != null)
foreach (MyListType item in e.NewItems)
this.MyListItemViewModels.Add(new MyListTypeViewModel{Model = item});
// remove any new elements
if (e.OldItems != null)
foreach (MyListType item in e.OldItems)
this.MyListItemViewModels.Remove(
this.MyListItemViewModels.First(x => x.Model == item)
);
}
Now your list of view models will automatically stay synched with your list of models. The main problem with this approach is that your models will typically originate from your ORM (database) code, so you will need to work with whatever framework you're using to inject INPC at creation time e.g. if you're using NHibernate then you'll need to use a binding interceptor for INPC and a collection convention to make the lists ObservableCollections.
I´m new to PRISM and trying some things out. I´m struggeling a little bit with MVVM.
The way you "connect" a view with a viewmodel is clear:
injection through unity, or
set the data context manually (ServiceLocator)
Everything is working fine if I add a view to a region (the viewmodel is created automatically). But that´s not the use case.
Let´s take a look at the example:
public class MyViewModel : NotificationObject
{
public ObservableCollection<AnotherViewModel> OrderModel { get; private set; }
}
I have to create view models and add them to the collection. This view models have to be displayed (AnotherView) in a region (OrderRegion). My problem is, how can I achieve that now the view is created when I am adding a viewmodel to a region. This region is a TabControl, so it could happened that different views must be displayed.
I have already took a look to the PRISM Quickstarts and the StockTrader example. What I am looking for is quite similar to
virtual protected void StartOrder(string tickerSymbol, TransactionType transactionType)
{
if (String.IsNullOrEmpty(tickerSymbol))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.StringCannotBeNullOrEmpty, "tickerSymbol"));
}
this.ShowOrdersView();
IRegion ordersRegion = _regionManager.Regions[RegionNames.OrdersRegion];
var orderCompositeViewModel = ServiceLocator.Current.GetInstance<IOrderCompositeViewModel>();
orderCompositeViewModel.TransactionInfo = new TransactionInfo(tickerSymbol, transactionType);
orderCompositeViewModel.CloseViewRequested += delegate
{
OrderModels.Remove(orderCompositeViewModel);
commandProxy.SubmitAllOrdersCommand.UnregisterCommand(orderCompositeViewModel.SubmitCommand);
commandProxy.CancelAllOrdersCommand.UnregisterCommand(orderCompositeViewModel.CancelCommand);
commandProxy.SubmitOrderCommand.UnregisterCommand(orderCompositeViewModel.SubmitCommand);
commandProxy.CancelOrderCommand.UnregisterCommand(orderCompositeViewModel.CancelCommand);
ordersRegion.Remove(orderCompositeViewModel);
if (ordersRegion.Views.Count() == 0)
{
this.RemoveOrdersView();
}
};
ordersRegion.Add(orderCompositeViewModel);
OrderModels.Add(orderCompositeViewModel);
commandProxy.SubmitAllOrdersCommand.RegisterCommand(orderCompositeViewModel.SubmitCommand);
commandProxy.CancelAllOrdersCommand.RegisterCommand(orderCompositeViewModel.CancelCommand);
commandProxy.SubmitOrderCommand.RegisterCommand(orderCompositeViewModel.SubmitCommand);
commandProxy.CancelOrderCommand.RegisterCommand(orderCompositeViewModel.CancelCommand);
ordersRegion.Activate(orderCompositeViewModel);
}
The view model is created inside the code and added to the region. The whole type regestring is happend through the "ViewExportAttribute" so it makes it harder to understand the pattern behind it.
EDIT:
I have found a way to do this manually but it´s not very nice:
var view = (FrameworkElement) ServiceLocator.Current.GetInstance<AnotherView>();
var model = ServiceLocator.Current.GetInstance<AnotherViewModel>();
view.DataContext = model;
regionManager.Regions["OrderRegion"].Add(view, null, true);
regionManager.Regions["OrderRegion"].Activate(view);
Roman
EDIT2:
Hi, I´m sorry, maybe I wasn´t clear enough.
My goal was to create a view model and then to configure it like in the example from the StockTrader above: Subscribe events, commands etc. After that I want to add this view model to the region, so that´s it could be displayed. This region might be a tabcontrol where different views with different view models are displayed.
The order is:
Create a view model in the controller class
Configure the view model
Add the view model to local collection inside the controller
Add the view model to the region
The missing piece what I was looking for was how to make it happen, that the view is created “automatically” with all stuff like binding etc. I have found an approach in this article (http://www.codeproject.com/Articles/229931/Understand-MVVM-Using-PRISM-by-Hello-World-Silverl). I have to create own interfaces for the view and the view model (IAnotherViewModel, IAnotherView).
Another approach can be found here: http://paulstovell.com/blog/viewmodel-first-prism
Is there any reason not to use implicit DataTemplates for this?
They are DataTemplates that define a DataType property, but not a Key property, and they are used anytime WPF tries to draw an object of the specified DataType
For example,
<TabControl ItemsSource="{Binding MyViewModelCollection}"
SelectedItem="{Binding SelectedViewModel}">
<!-- This could also go elsewhere, like Application.Resources -->
<TabControl.Resources>
<DataTemplate DataType="{x:Type local:ViewModelA}">
<local:ViewA />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModelB}">
<local:ViewB />
</DataTemplate>
</TabControl.Resources>
</TabControl>
If the TabControl is displaying an object of type ViewModelA, it will draw it using ViewA, and if it's displaying ViewModelB, it will draw it using ViewB
yI you are using MEF then you can automate your view registration using Attributes:
/*YOUR VIEW*/
[ExportViewToRegion("MyView", "MyRegion")]
[Export(typeof(MyView))]
public partial class MyView : UserControl
{
....
}
/*IMPLEMENTATION*/
public interface IExportViewToRegionMetadata
{
string ViewName { get; }
string TargetRegion { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = false)]
public class ExportViewToRegionAttribute : ExportAttribute
{
public ExportViewToRegionAttribute(string viewName, string targetRegion)
: base(typeof(UserControl))
{
ViewName = viewName;
TargetRegion = targetRegion;
}
public string ViewName { get; private set; }
public string TargetRegion { get; private set; }
}
[Export(typeof(IFluentRegionManager))]
public class FluentRegionManager : IFluentRegionManager, IPartImportsSatisfiedNotification
{
public IRegionManager RegionManager { get; set; }
[ImportingConstructor]
public FluentRegionManager(IRegionManager regionManager)
{
RegionManager = regionManager;
}
/*This Import will find all views in the assembly with attribute [ExportViewToRegion("ViewName", "RegionName")]*/
[ImportMany(AllowRecomposition = true)]
public Lazy<UserControl, IExportViewToRegionMetadata>[] Views { get; set; }
private readonly List<string> _processedViews = new List<string>();
private Lazy<UserControl, IExportViewToRegionMetadata> _GetViewInfo(string viewName)
{
return (from v in Views where v.Metadata.ViewTypeForRegion.Equals(viewName) select v).FirstOrDefault();
}
public IExportViewToRegionMetadata this[string viewName]
{
get
{
return (from v in Views
where v.Metadata.ViewName.Equals(viewName, StringComparison.InvariantCultureIgnoreCase)
select v.Metadata).FirstOrDefault();
}
}
public void ExportViewToRegion(string viewName)
{
if (viewName==null)
{
throw new ArgumentNullException("viewName");
}
var viewInfo = _GetViewInfo(viewName);
string targetRegion;
UserControl _view;
if (viewInfo != null)
{
targetRegion = viewInfo.Metadata.TargetRegion;
_view = viewInfo.Value;
}
if (string.IsNullOrEmpty(targetRegion) || _processedViews.Contains(viewName)) return;
RegionManager.RegisterViewWithRegion(targetRegion, _view.GetType());
_processedViews.Add(viewName);
}
/*All required views has been discovered and imported */
/*Loop true collection and register view with the region */
public void OnImportsSatisfied()
{
foreach (var viewName in from view in Views where !_processedViews.Contains(view.Metadata.ViewName)
select view.Metadata.ViewName)
{
ExportViewToRegion(viewName);
}
}
}
/* finally call IFluentRegionManager import in the bootstrapper to kick off registration*/
On the main window onClick I have
AddNoticeAboutWrongCity addNoticeAboutWrongCity = new AddNoticeAboutWrongCity();
addNoticeAboutWrongCity.DataContext = ((VerificationViewModule)this.DataContext).WrongCityNotice;
addNoticeAboutWrongCity.ShowDialog();
At popup window there a lot of textboxes and two buttons
Delete object:
this.DataContext = null;
And second option "Save edited notice" which is not usable , because every change of user affection datacontext on main window,and this is demand from design department :)
I don't know why first option(it's "implementation" doesn't work.
Second explanation:
On the ParentWindow I have list of Notices and I can click EditSelectedNotice.
On the EditNoticeWindow I can edit Notice or delete Notice.
Editinig works(After closing EditNoticeWindow I see changed notice on the ParentWindow), but deleting doesn't (Notice is still in collection - on control and in this.DataContext)
My ViewModel:
class VerificationViewModule
{
public ObservableCollection<ReporterNotice> ReporterNotices { get; set; }
public ReporterNotice OtherNotice
{
get
{
return ReporterNotices.Where(n => n.Type == ReporterNoticeType.Other).FirstOrDefault();
}
}
public ReporterNotice DuplicateNotice
{
get
{
return ReporterNotices.Where(n => n.Type == ReporterNoticeType.Duplicate).FirstOrDefault();
}
}
public ReporterNotice WrongCityNotice
{
get
{
return ReporterNotices.Where(n => n.Type == ReporterNoticeType.WrongCity).FirstOrDefault();
}
set { if(value==null)
{
ReporterNotices.Remove(ReporterNotices.Where(n => n.Type == ReporterNoticeType.WrongCity).First());
}
else
{
if (ReporterNotices.Where(n => n.Type == ReporterNoticeType.WrongCity).FirstOrDefault()==null)//there is always only max one instance of this type of notice
{
ReporterNotices.Add(value);
}
else
{
var c = ReporterNotices.Where(n => n.Type == ReporterNoticeType.WrongCity).First();
c = value;
}
}}
}
public VerificationViewModule()
{
ObservableCollection<ReporterNotice> loadedReporterNotices = new ObservableCollection<ReporterNotice>();
loadedReporterNotices.Add(new ReporterNotice() { Content = "Dublic", Type = ReporterNoticeType.WrongCity });
loadedReporterNotices.Add(new ReporterNotice() { Content = "Hilton", Type = ReporterNoticeType.Duplicate });
loadedReporterNotices.Add(new ReporterNotice() { Content = "Another notice", Type = ReporterNoticeType.Other });
ReporterNotices = loadedReporterNotices;
}
}
You can try the following. Implement the mediator to display windows and make sure that you use view models for the DataContext for both the main and edit windows. It is important to tell the main view model that the object is being deleted. This is done via a callback and routing that through a command on the EditNoticeViewModel
//This viewmodel is on the main windows datacontext
public class ParentViewModel
{
private readonly IWindowMediator _mediator;
public ParentViewModel(IWindowMediator mediator)
{
_mediator = mediator;
}
public ObservableCollection<Notice> Notices { get; private set; } //bound to list in xaml
public void OpenNotice(Notice notice)
{
//open the window using the Mediator pattern rather than a new window directly
_mediator.Open(new EditNoticeViewModel(notice, DeleteNotice));
}
private void DeleteNotice(Notice notice)
{
//This will remove it from the main window list
Notices.Remove(notice);
}
}
//view model for EditNoticeWindow
public class EditNoticeViewModel
{
public EditNoticeViewModel(Action<Notice> deleteCallback, Notice notice)
{
Model = notice;
DeleteCommand = new DelegateCommand((a) => deleteCallback(Model));
}
//Bind in xaml to the Command of a button
DelegateCommand DeleteCommand { get; private set; }
//bound to the controls in the xaml.
public Notice Model { get; private set; }
}
//This is a basic interface, you can elaborate as needed
//but it handles the opening of windows. Attach the view model
//to the data context of the window.
public interface IWindowMediator
{
void Open<T>(T viewModel);
}
Depending on implementation you might want to close the view when the delete button gets pushed. You can do this by implementing something like the as described here with respect to WorkspaceViewModel
Why don't you wrap the WrongCityNotice in a viewModel implementing IReporterNotice and having a reference to the parent viewmodel and a Delete method:
public void Delete() { _parentvm.Delete(_wrongCityNotice); }
You can use this wrapper as DataContext.
You're trying to destroy the DataContext. C# doesn't work that way. Setting an object reference to null doesn't delete the object, it only removes the reference to it. (When nothing references an object anymore it gets garbage collected, but you can't destroy an object directly).
DataContext = null only means that locally your DataContext doesn't point to any object any more. The main view model still has a reference however so nothing changes there. You'll have to ask the main view model to remove the notification from it's collection (probably through a callback method (Action) is best so you don't have to know about the parent view model).