WPF DataBinding with Code First Entity Framework - wpf

I am just getting familiar with WPF databinding. I've figured out most of the basics but I'm having trouble figuring out a couple of things.
First, let's say I have an object called Synth that has a collection of Banks. In turn, a Bank has a collection of Patches. I have a synth window to which I set the DataContext to a single Synth object. I have one listbox (lstBanks) that shows all the banks ({Binding Banks}) and another (lstPatches) that shows all the patches ({Binding ElementName=lstBanks, Path=SelectedItem.Patches}). This all works great. I see the applicable patches when I select a bank.
Question 1: How can I load a selected Patch into a dialog window with two-way binding, yet cancel those changes if DialogResult = false?
Right now, I have a patch dialog that receives a patch in the constructor which it sets as its DataContext, but I am only using OneWay binding. This happens on the doubleclick of lstPatches.
private void Patch_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
Models.Patch patch = (Models.Patch)((ListBoxItem)sender).DataContext;
PatchEdit p = new PatchEdit(patch);
p.Owner = this;
if (p.ShowDialog().GetValueOrDefault())
{
// Do stuff if applicable
}
}
Here is my PatchEdit constructor and OK button event:
public PatchEdit(Models.Patch Patch) : this()
{
this.DataContext = Patch;
}
private void btnOK_Click(object sender, RoutedEventArgs e)
{
Models.Patch p = (Models.Patch)DataContext;
p.Name = txtName.Text;
p.MidiProgramChangeValue = int.Parse(txtPCN.Text);
this.DialogResult = true;
this.Close();
}
If the user clicks OK on the patch dialog, that's when I set the properties from the form back to the DataContext. I wasn't sure if this was the best way to do it. I don't want to really save the changes until the user clicks OK on the main synth window. So all bank and patch edits should only remain local, and only be "locally" committed if the user clicks OK and not Cancel on the dialog.
Question 2: Once a patch is updated via the dialog, how can I get that change reflected in lstPatches?
I understand that directly navigating my models which are essential of type DBSet aren't Observable. I've seen posts regarding using an Observable collection, but doesn't this just complicate something that is supposed to be easy with WPF databinding? If it's the only way, how do I accomplish this easily using my code first models?

Question 1: Bind to a second/temporary object. If the user cancels, throw it away. If they don't, use it to update your original object. Data-binding doesn't really offer an "undo" or "reset" method.
Question 2: No, using ObservableCollection's doesn't complicate things. It is the recommended way of doing things. It is actually much harder to work without them.

Related

MVP Presenter to Presenter communication

I'm currently preparing core framework for our upcoming project based on WinForms and MVP design pattern.
I'm not sure, what would be the best way, how to communicate between two Views/Presenters. To be more specific - I have a ListView and a DetailView. When user clicks on an item in the ListView, I need to display edit form for this item, which in my case is DetailView.
Options:
Should ListPresenter create DetailPresenter on the click event? (A Factory could be of a help.)
Should instance of DetailPresenter be injected in ListPresenter constructor?
I feel 2) might be the "right" solution, but I would prefer creating DetailView/DetailPresenter just in time I really need it - i.e. when user clicks the button.
The next problem, I don't know how to go about it is the objects lifetime. When I inject a View into Presenter, who is responsible for the cleanup? I'm used to behaviour, where cleanup is made by the same party who created it. But in this case I could imagine View could be disposed by the Presenter.
I hope the questions are not too generic, I have read a lot of articles about MVC/MVP, but they mostly don't go further than showing how to implement single View-Presenter communication.
Thank you.
You could wrap the ListPresenter and the DetailPresenter in a ListDetailPresenter.
public class ListDetailPresenter
{
private ListPresenter _listPresenter;
private DetailPresenter _detailPresenter;
public ListDetailPresenter()
{
_listPresenter = new ListPresenter();
_detailPresenter = new DetailPresenter();
_listPresenter.SelectionChanged += OnSelectionChanged;
}
private void OnSelectionChanged(object sender, EventArgs e)
{
_detailPresenter.SetItem(_listPresenter.SelectedItem);
}
}

UI freezed instead of showing BusyIndicator in Silverlight

This is a side-related question to this other question:
BackgroundWorker in Silverlight ViewModel
I have a TabControl where I load many TabItems when the user selects menu options. I load this Tabs by binding the TabControl ItemsSource to an ObservableCollection. When I add a new TabItem to this Collection, it is shown perfectly.
The problem is I've realized that since user press a button until the tab is created (ViewModel and View creation takes a couple of seconds), the screen is freezed.
I've tried to set "IsBusy" before calling the "loadTab" but it doesn't shows up... I've tried almost everything with async calls but the UI thread is in use and it throws an exception when I create the new tab control.
Is there any trick I'm loosing??? Any ideas??? Thanks in advance.
have you seen this post?
http://www.dotnetspark.com/kb/3524-doesnt-your-girlfriend-deserves-more-time.aspx
It helps when you avoid heavy stuff in the load event and make Visible=true after you finish to load all your resources, so in that sense you avoid the user feeling tempted to click something that is not ready yet.
Not sure if it helps, but how about this idea?
public void DoStuff(Object values)
{
//your values object could be anything,
//they might even be some objects from your form
//as long as you dont modify them in the other thread
imgLoading.Visible=true;
var client = new Proxy();
client.OnWorkCompletedAsync +=client_OnCompleted() ;
client.Work(values);
}
void client_OnCompletedAsync(object sender, EventArgs e)
{
imgLoading.Visible=false;
//now you can update the UI with other stuff
}

Reflect property change from one ViewModel to another

I have this WPF/MVVM Application that a TabControl with a bunch of tabs. When the app loads, data for all tabs are loaded. There are some calculations that are made on Tab1 that's dependent on values from Tab2. what's happening is, when I enter / change data on tab2, it simply doesn't reflect on Tab1 when I click on Tab1. under the hood, the calculations are made properly but it doesn't reflect on tab1. I have to go to the main tab to re-load all the data to reflect changes. Any ideas how to implement this?
You need to implement INotifyPropertyChanged on your view model data properties. Then, have your view model subscribe to the event (the Initialize() method is called by the view model constructor):
private void Initialize()
{
// Subscribe to events
this.PropertyChanging += OnPropertyChanging;
this.PropertyChanged += OnPropertyChanged;
this.Books.CollectionChanging += OnBooksCollectionChanging;
}
The view model handler for the event can then update any properties that need to be updated:
void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
switch(e.PropertyName)
{
case "FirstProperty":
this.SomeOtheProperty = whatever;
break;
case "Another property":
this.YetAnotherProperty = somethingElse;
break;
}
}
That should get the job done.
If two different ViewModels need to show the same data/value they should bind to the same ViewModel.
I think that adding a binding between ViewModels is bad because it introduces a lot of dependencies.
If a property of a single ViewModel is dependent on an other property of the same ViewModel you could use property changed notification as mentioned in David's answer.

WPF: how to signal an event from ViewModel to View without code in codebehind? [duplicate]

This question already has answers here:
How can I Have a WPF EventTrigger on a View trigger when the underlying Viewmodel dictates it should?
(4 answers)
Closed 8 years ago.
I have quite simple (I hope :)) problem:
In MVVM, View usually listens on changes of ViewModel's properties. However, I would sometimes like to listen on event, so that, for example, View could start animation, or close window, when VM signals.
Doing it via bool property with NotifyPropertyChanged (and starting animation only when it changes from false to true) is possible, but it feels like a hack, I'd much prefer to expose event, as it is semantically correct.
Also, I'd like to do it without code in codebehind, as doing viewModel.myEvent += handler there would mean that I'd have manually unregister the event in order to allow View to be GC'd - WPF Views are already able to listen on properties 'weakly', and I'd much prefer to program only declaratively in View.
The standard strong event subscription is also bad, because I need to switch multiple ViewModels for one View (because creating View every time takes too much CPU time).
Thank you for ideas (if there is a standard solution, a link to msdn will suffice)!
Some comments:
You can use the weak event pattern to ensure that the view can be GC'd even if it is still attached to the view model's event
If you're already switching multiple VMs in for the one view, wouldn't that be the ideal place to attach/detach the handler?
Depending on your exact scenario, you could just have the VM expose a state property which the view uses as a trigger for animations, transitions, and other visual changes. Visual state manager is great for this kind of thing.
This is something that I wrestled with as well...
Similar to what others are saying, but here is an example with some code snippets... This example shows how to use pub/sub to have a View subscribe to an event fired by the VM - in this case I do a GridView. Rebind to ensure the gv is in sync with the VM...
View (Sub):
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Composite.Presentation.Events;
private SubscriptionToken getRequiresRebindToken = null;
private void SubscribeToRequiresRebindEvents()
{
this.getRequiresRebindToken =
EventBus.Current.GetEvent<RequiresRebindEvent>()
.Subscribe(this.OnRequiresRebindEventReceived,
ThreadOption.PublisherThread, false,
MemoryLeakHelper.DummyPredicate);
}
public void OnRequiresRebindEventReceived(RequiresRebindEventPayload payload)
{
if (payload != null)
{
if (payload.RequiresRebind)
{
using (this.gridView.DeferRefresh())
{
this.gridView.Rebind();
}
}
}
}
private void UnsubscribeFromRequiresRebindEvents()
{
if (this.getRequiresRebindToken != null)
{
EventBus.Current.GetEvent<RequiresRebindEvent>()
.Unsubscribe(this.getRequiresRebindToken);
this.getRequiresRebindToken = null;
}
}
Call unsub from the close method to prevent memory leaks.
ViewModel (Pub):
private void PublishRequiresRebindEvent()
{
var payload = new RequiresRebindEventPayload();
payload.SetRequiresRebind();
EventBus.Current.GetEvent<RequiresRebindEvent>().Publish(payload);
}
Payload class
using System;
using Microsoft.Practices.Composite.Presentation.Events;
public class RequiresRebindEvent
: CompositePresentationEvent<RequiresRebindEventPayload>
{
}
public class RequiresRebindEventPayload
{
public RequiresRebindEventPayload()
{
this.RequiresRebind = false;
}
public bool RequiresRebind { get; private set; }
public void SetRequiresRebind()
{
this.RequiresRebind = true;
}
}
Note that you can also set the constructor up to pass in a Guid, or some identified in, which can be set on Pub and checked on sub to be sure pub/sub is in sync.
imho yYand separated
state - to be able to move data back/forth between view <-> vm
actions - to be able to call onto view model functions/commands
notifications - to be able to signal to the view that something has happened and you want it to take a viewy action like make an element glow, switch styles, change layout, focus another element etc.
while is true that you can do this with a property binding, its more of a hack as tomas mentioned; always has felt like this to me.
my solution to be able to listen for 'events' from a view model aka notifications is to simple listen for data-context changes and when it does change i verify the type is the vm i'm looking for and connect the events. crude but simple.
what i would really like is a simple way to define some 'view model event' triggers and then provide some kind of handler for it that would react on the view side of things all in the xaml and only drop to code behind for stuff thats not do-able in xaml
Like adrianm said, when you trigger your animation off a bool property you are actually responding to an event. Specifically the event PropertyChanged which the WPF subsystem. Which is designed to attach/detach correctly to/from so that you don't leak memory (you may forget to do this when wiring an event yourself and cause a memory leak by having a reference active to an object which otherwise should be GCed).
This allows you to expose your ViewModel as the DataContext for the control and respond correctly to the changing of properties on the datacontext through databinding.
MVVM is a pattern that works particularly well with WPF because of all these things that WPF gives you, and triggering off a property change is actually an elegant way to use the entire WPF subsystem to accomplish your goals :)
A more general question to ask is: "Why am I trying to deal with this event in my ViewModel?"
If the answer has anything to do with view-only things like animations, I'd argue the ViewModel needs not know about it: code behind (when appropriate), Data/Event/PropertyTriggers, and the newer VisualStateManager constructs will serve you much better, and maintain the clean separation between View and ViewModel.
If something needs to "happen" as a result of the event, then what you really want to use is a Command pattern - either by using the CommandManger, handling the event in code behind and invoking the command on the view model, or by using attached behaviors in the System.Interactivity libs.
Either way, you want to keep your ViewModel as "pure" as you can - if you see anything View-specific in there, you're probably doing it wrong. :)

MVVM CollectionViews in WPF Application Framework (WAF)

In short my question is: How do you prefer to expose filtered/sorted/grouped ObservableCollections to Views in WAF?
I was fairly happy with my first attempt which involved filtering on the VM and exposing an ICollectionView of Model objects for the View to bind to:
public StartDetailViewModel(IStartDetailView view, StartPoint start, Scenario scenario)
: base(view)
{
this.scenario = scenario;
this.start = start;
this.startsViewSource = new CollectionViewSource();
this.startsViewSource.Filter += new FilterEventHandler(Starts_Filter);
this.startsViewSource.Source = scenario.Starts;
}
public ICollectionView FilteredStarts
{
get
{
return startsViewSource.View;
}
}
void Starts_Filter(object sender, FilterEventArgs e)
{
if (e.Item != null)
{
e.Accepted = (((StartPoint)e.Item).Date == this.start);
}
}
}
However, exposing the Model objects directly is insufficient since each item now needs its own ViewModel.
So, CollectionViewSource.Source is now attached to a collection of Views. The main problem with this is when applying filters:
void Starts_Filter(object sender, FilterEventArgs e)
{
//Since e.Item is now a view we are forced to ask the View for the ViewModel:
StartItemViewModel vm = ((IStartItemView)e.Item).GetViewModel<StartItemViewModel>();
[...]
}
This feels wrong to me. Are there better approaches?
UPDATE
So I reverted to a CollectionViewSource.Source of Model objects and maintained a seperate collection of child View objects to which the View was bound.
The question then of course is why am I using CollectionViewSource in a ViewModel at all?
I think the following prinicple applies: If the filtering/sorting functionality is a property of the View only (i.e. an alternate view might legitimately not provide such functionality) then CollectionViews should be used in the View (with code-behind as necessary). If the filtering/sorting functionality is a dimension of the Model then this can be dealt with in the ViewModel or Model by other means.
This makes sense once you realise that code-behind in MVVM views is perfectly acceptable.
Any comments?
I think the real benefit of CollectionView lies in when you are in need of reporting information as you step through collectionview items one by one. In this way you are able to utilize the CurrentPosition property and MoveCurrentToNext (/etc.) methods which may be desireable. I particularly like the idea of being able to report PropertyChanged notifications in MVVM when item properties in the collection changed/items are added/removed/changed.
I think it just makes a bit more sense to use in controls that require more complex notifications (such as datagrid, where you may want to raise PropertyChanged events and save to your datastore each time the selectionchanges or a new item is addd to the control).
I hope that makes sense. That is just what I am putting together as a beginner.
Also, I really don't think anything should go in the code-behind of a view except a datacontext and the shared data you may be feeding it from a viewmodel.

Resources