WPF & MVVM, right way to do it - wpf

So I am doing my first WPF MVVM app. Just learning the right principle of MVVM, but there are some things that I don't understand ...
I already have several user controls defined.
First question is what is better to use, UserControl or DataTemplates to change content of the MainWindow?
And how to make "Binding" in the "MainWindow.xaml" to change UserControl/DataTemplates when button is pressed?
For example, When "next" button is pressed then contents of main window disappear and content of user control comes on the screen of "MainWindow.xaml".
Maybe with "" binding, to disable it and enable it?
I found some example which function on DataTemplate A Simple MVVM Example. It helped me to implement some things, but I see some discussions over "UserControl" vs. "DataTemplate" and how to do it? So now I am confused :)

I recently made a WPF application with the MVVM pattern, and I did the following:
I have one 'Window', the mainwindow, and in this window all UserControls are loaded.
Every UserControl has a different Viewmodel, for examples a "GeneralSettingsUserControl" has a GeneralSettingsViewModel for validation and databinding.
Every UserControl has its own codebehind where data is bound to its ViewModel
The following code I found on the internet (I don't know the url anymore) but for me it did the trick to change de ContentControl in the mainwindow.
Switcher.cs:
public static mainWindow mainWindow;
public static void switchPage(UserControl p_objNewPage)
{
mainWindow.navigate(p_objNewPage);
}
mainWindow.xaml.cs
public void navigate(UserControl nextPage)
{
PageContent.Children.Clear();
PageContent.Children.Add(nextPage);
PageContent.LastChildFill = true;
}
PageContent is the name of the Grid where the main content is located. In every UserControl you can call the Switcher.switchPage(new UserControl) to change the content of the window. So when you click a button you can call this method.
Hope it helps and good luck.

Related

WPF How to handle Cut, Copy, Paste toolbar buttons with UserControls and WindowsFormsHost

I'm hoping someone out there can help me. I'm trying to convert a legacy winforms app to WPF using MVVM. I've broken up the main window of the application into 4 main UserControls. The UserControls display different types of data objects and each UserControl has it's own ViewModel. Some of the data objects are inter-changeable between the different UserControls, for instance 'User Control 1' can contain strings objects and so can 'User Control 2 and 'User Control 3' (see diagram below).
My question is how can I handle the Cut, Copy, Paste commands in the toolbar? To possibly make things more complicated, each UserControl can contain a selected object at the same time as the other UserControls contain a selected object and User Control 2 is a WindowsFormsHost wrapper around a winforms control.
So far I've tried using ApplicationCommands but I can't even get them to fire. I've pasted a snippet of the code I thought would work using the ApplicationCommands below. Any help with this would be really appreciated.
<Button Command="ApplicationCommands.Cut" />
and on the UserControls
<UserControl.CommandBindings>
<CommandBinding Command="ApplicationCommands.Cut" Executed="executed_Cut" CanExecute="canExecute_Cut" />
</UserControl.CommandBindings>
and finally in the UserControl's code behind (I know this isn't great)
public void executed_Cut(Object sender, ExecutedRoutedEventArgs e)
{
//execute code here
}
public void canExecute_Cut(Object sender, CanExecuteRoutedEventArgs e)
{
//can execute code here
}
I successfully use the behavior approach described in this question to avoid putting any code in my view model. Then whenever focus goes to a control which has a copy/paste behavior defined the toolbar cut/copy/paste buttons "light up" accordingly.

Screenshot of usercontrol immediately prior to being unloaded

I'm building a pos system that has a main ContentControl to display different screens of the application. I use DataTemplates to map my viewmodels to views. To navigate between the different views displayed in the ContentControl I'd like to store a screenshot of the UserControl in the viewmodel when the UserControl is unloaded (or the ContentControl changes).
I posted a related question here WPF Binding FrameworkElement event to command in which I attempted to bind a command to FrameworkElement.Unloaded but that doesn't work (see answer at that link)
Is this possible without breaking the MVVM pattern?
here is a nice link to how to do a screenshot in wpf.
here is what i would do:
my mainviewmodel which handle the navigation should expose an event and raise this event before you set the new contentviewmodel. the old contentviewmodel should be in the eventargs. in your mainwindow codebehind you subscribe to the event(not breaking mvvm here). when ever this event is raise you can call the screenshot method and put the result to the oldviewmodel.
edit:
mainwindow codebehind
void NavigationChangingEvent(object sender, NavChangingArgs args)
{
var oldvm = args.ChangingViewmodel;
oldvm.Screenshoot = this.mycontentcontrolwheremyviewmodelareshown.GetJpgImage(1, 90);
}

WPF routed events handling in UserControl

I have a WPF UserControl that contains a button. I also have a WPF Window that contains a button.
In both the UserControl and the Window I place the following line in XAML:
UIElement.PreviewMouseLeftButtonDown="OnPreviewMouseLeftButtonDown"
and in 'OnPreviewMouseLeftButtonDown' I've place a debug print that displays args.Source.
When I click on the button that is inside the window, I get the button as the EventArgs source. However, when I click the button that inside the UserControl (which is also inside a window, so I could test it, but not the same window) I get the UserControl as the EventArgs source.
I tired to see if there is some decorator around the UserControl (using snoop) but it seems straight forward.
I can't understand what is so special about UserControl in WPF that I don't get the right sender. Can someone please explain to me what am I missing?
While the question is old, I recently ran into a similar problem myself, involving the ContextMenuOpening event. Some amount of searching yielded the source code to UserControl here, which contains the following section:
// Set the EventArgs' source to be this UserControl
internal override void AdjustBranchSource(RoutedEventArgs e)
{
e.Source=this;
}
So, apparently UserControl sets the Source of ANY routed event to itself. I have no idea why it does this, though...
Use e.OriginalSource as mentioned above. If you need to find the button, then you can use VisualTreeHelper.GetParent to find the actual Button control.

Usercontrol with treeview selected event that refreshed another usercontrol not working

I'm relatively new to WPF programming and can't seem to get this working correctly. This is in my mind something rather simplistic that i would like to get working so I didn't try the MVVM framework and decided to keep it simple.
I have a usercontrol treeview with report paths. I have another usercontrol with a reportviewer. Selecting a report path in the treeview should refresh the reportviewer.
I can "call" the method from the treeview usercontrol for refreshing the reportviewer in the report usercontrol but nothing happens.
I was reading other posts and some seem to suggest a button event to a delegate that will allow the other usercontrol method to be executed. I'm not using a button event so I'm a bit puzzled.
I thought I could do something like this:
private void treeViewMenu_Selected(object sender, RoutedEventArgs e)
{
//Get the selected item
....
//Call the method of another user control
ReportUserControl ruc = new ReportUserControl();
ruc.RefreshReport();
}
Obviously that didn't work...I know that it shouldn't be too difficult but i am in a brain freeze moment and can't seem to get it working.
Any suggestions would be greatly appreciated.
Thanks!

Designing WPF UserControl that gets its DataContext from outer controls: How to have some sample data in designer but use inherited DC at runtime?

I am designing a WPF user control which contains other user controls (imagine a WidgetContainer, containing different Widgets) - using M-V-VM architecture.
During development, I have WidgetContainerView in a window, window (View) spawns a WidgetContainerViewModel as its resource, and in a parameterless constructor of WidgetContainerViewModel, I fill its exposed collection with some sample widgets (WidgetViewModels).
WidgetContainer control inherits the DataContext from window, and inside, there is a ListView, that binds Widgets to WidgetView control (which is inside ListView.ItemTemplate).
Now this works OK in my WindowView, as I see my sample widgets, but once I edit the WidgetContainerView or WidgetView, there is no content - at design time, controls are standalone, and they don't inherit any DataContext, so I don't see a content, and have troubles designing them (a ListView is empty, Widget's fields as well...).
I tried adding a sample widget to the WidgetView:
public partial class WidgetView : UserControl
{
public WidgetView()
{
InitializeComponent();
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
{
//btw, MessageBox.Show(...) here sometimes crashes my Visual Studio (2008), but I have seen the message - this code gets executed at design time, but with some lag - I saw the message on reload of designer, but at that time, I have already commented it - wtf?
this.DataContext = new WidgetViewModel(); //creates sample widget
}
}
}
but that didn't work - I still don't see anything in designer.
I also wanted to create a WidgetViewModel as a resource in WidgetView, like this:
<UserControl x:Class="MVVMTestWidgetsControl.View.WidgetView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="WidgetViewModel" //this doesn't work!
Height="Auto" Width="Auto">
<UserControl.Resources>
<ResourceDictionary>
<ViewModel:WidgetViewModel x:Key="WidgetViewModel" />
</ResourceDictionary>
</UserControl.Resources>
<TextBlock Text="{Binding Path=Title}"></TextBlock>
</UserControl>
but I don't know how to assign a WidgetViewModel as a DataContext of a whole widget - I can't add DataContext attribute to UserControl, because WidgetViewModel is defined later in the code. Any ideas how to do this? I could use a sample data this way, and just override it in code so that it has the right content at runtime...
What are your best practices when developing user controls? Thank you, designing empty control is no fun :)).
In your second snippet, you should be able to refer to your DataContext as a DynamicResource:
DataContext="{DynamicResource WidgetViewModel}"
But most custom user controls have some sort of top level layout container, and you can set the DataContext on that container as a StaticResource.
In your case, however, you may want to consider dropping the VM portion of your code altogether since you're writing a custom UserControl. You should ask yourself what benefits are you gaining from a completely self-contained ViewModel with no real backing Model designed for just one View (i.e. the custom UserControl). Perhaps you could just define some DependencyProperties and use those?
I came up with several solutions: Add DC as resource (it will get automatically instantiated with parameterless constructor), and do the following in View's codebehind:
public PanelView()
{
InitializeComponent();
if (!DesignerProperties.GetIsInDesignMode(new DependencyObject())) //DeleteAtRelease:
{
//we are in runtime, reset DC to have it inherited
this.DataContextHolder.DataContext = DependencyProperty.UnsetValue;
}
}
Better way would be to only assign DC if we are at designtime, but VS didn't like it - it worked only sometimes, and quite nondeterministically, and once it even crashed.
Other check for design time is:
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
{
this.DataContext = new WidgetViewModel();
}

Resources