Doing my first MVVM WPF application. I expected to see a Main() method in the App.xaml (I'm used to Silverlight) but it isn't there. I added my own Main method. In Silverlight I then created a View linked to a ViewModel and set it as the RootVisual. How do I correctly open my first View Window in WPF?
There are many ways, but I think the WPF equivalent of setting a Silverlight RootVisual is to call Application.Run
App.Run(new MainWindow())
In general, there is no right or wrong way here nor is there an accepted convention. Some people make this call in the Startup event. Other people don't use the event and override OnStartup instead. Still others use StartupUri in App.xaml.
When I created my first (and to date, only) WPF project, to display the appliation's main window (called MainWindow), I overrode the App class's OnStartup method as below:
/// <summary>
/// Raises the System.Windows.Application.Startup event.
/// </summary>
/// <param name="e">The <see cref="System.Windows.StartupEventArgs" /> that contains the event data.</param>
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// I did some app-specific stuff here...
MainWindow view = new MainWindow();
// Allow all controls in the window to bind to the ViewModel by setting the
// DataContext, which propagates down the element tree.
MainWindowViewModel viewModel = new MainWindowViewModel();
// and I did some more app-specific stuff here...
view.DataContext = viewModel;
view.Show();
}
I believe this was the recommended way for MVVM applications (was a while back though); this code was taken from a .NET 3.5 application.
Related
How can we bind a user-control to a view-model object, when this last contains parameters in his constructor ???
Does the binding using "DataContext" in the view ensure that when we create a view-model, the view is automatically created ??
If you are using an IoC container, this is supported out-of-the-box.
It really depends on the IoC container you are using, but here is an example using Prism Unity container.
The following examples are taken out from the Prism QuickStarts guide
So, at first, we will have to set up the unity container:
public class QuickStartBootstrapper : UnityBootstrapper
{
private readonly CallbackLogger callbackLogger = new CallbackLogger();
/// <summary>
/// Configures the <see cref="IUnityContainer"/>.
///May be overwritten in a derived class to add specific
/// type mappings required by the application.
/// </summary>
protected override void ConfigureContainer()
{
// Here you can do custom registeration of specific types and instances
// For example
this.Container.RegisterInstance<CallbackLogger>(this.callbackLogger);
base.ConfigureContainer();
}
}
Baisically, youre done!
All you have to do now is have your view recieve the viewModel as a parameter in his constructor, like this:
public partial class OverviewView
{
public OverviewView(OverviewViewModel viewModel)
{
InitializeComponent();
this.DataContext = viewModel;
}
}
Unity IoC container will take care of your parameters in the ViewModel even without you having to register those types most of the times.
Please note that in my answer I only refered to the IoC part of the configuration. setting up an entire MVVM application requires a bit more work and varies depending the MVVM framework you are using
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);
}
I search DesignMode boolean on a custom WPF UserControl... How correctly do I impelment it?
I have a WPF Control hosted in a WinForm. I saw that the "DesignerProperties" class does not work in such a case.
I have some logic in the constructor that throws exceptions in the design mode and want to skip that code, because I don't arrive to see a Form with my UserControl in the designer.
I tried
private static bool? _isInDesignMode;
/// <summary>
/// Gets a value indicating whether the control is in design mode
/// (running in Blend or Visual Studio).
/// </summary>
public static bool IsInDesignModeStatic
{
get
{
if (!_isInDesignMode.HasValue)
{
#if SILVERLIGHT
_isInDesignMode = DesignerProperties.IsInDesignTool;
#else
var prop = DesignerProperties.IsInDesignModeProperty;
_isInDesignMode
= (bool)DependencyPropertyDescriptor
.FromProperty(prop, typeof(FrameworkElement))
.Metadata.DefaultValue;
#endif
}
return _isInDesignMode.Value;
}
}
but this does not work :(( I see designer exceptions at "blocked" with IsInDesignModeStatic code lines...
I used this to detect DesignMode (my WPF control is defined in a Class Library).
' Exit here if in Design Mode
If Assembly.GetEntryAssembly() Is Nothing Then Exit Sub
You may be able to check Assembly.GetEntryAssembly.FullName.ToString if it is not nothing and determine where the control is being initialized from.
The DesignerProperties.IsInDesignModeProperty was returning null for me when the control was hosted in WinForms because WPF doesn't know there is a designer there.
Steve
Try this
if (DesignerProperties.GetIsInDesignMode(this/*this user control*/))
{
// Design-mode specific functionality
}
I am little new to Command binding so this might be a trivial question to many. I know that we can add Command bindings in xaml of a window and give its correspondng property in viewmodel. This viewmodel will be given to the DataContext of the window. Something like the following
--app.xaml.cs
mainWindow.DataContext = viewModel;
-- xaml
lt;Button Grid.Row="1" HorizontalAlignment="Right" Margin="0,3,18,3" Name="button1" Width="110"
Command="{Binding LoadCommand}">_Load</Button>
-- viewmodel
/// <summary>
/// Gets the load command.
/// </summary>
/// <value>The load command.</value>
public ICommand LoadCommand
{
get
{
if (m_LoadCommand == null)
{
m_LoadCommand = new RelayCommand(param => CanLoad(), param => Load());
}
return m_LoadCommand;
}
}
Here the relaycommand is a class which implements ICommand interface. CanLoad() and Load() are the methods which will get executed for canexecute and execute action of the relaycommand respectively. This is the click event of the button which is handled.
I have a user control which has a custom routedevent registered in it and the user control is then used on a window. I am currently adding the event handler explicitly in code.
//hook up event listeners on the actual UserControl instance
this.ucCustomEvent1.CustomClick += new RoutedEventHandler(ucCustomEvent_CustomClick);
//hook up event listeners on the main window (Window1)
this.AddHandler(UserControlThatCreatesEvent.CustomClickEvent, new RoutedEventHandler(ucCustomEvent_CustomClick));
I dont want to hook up the routedevent explicitly in code but in the xaml in the similar way as in the button example. I have uploaded the working sample code here for your perusal.
I'm not sure I fully understand your question but I hope one of my answers below helps you out.
To attach a "direct" event handler in XAML, just do the following:
<c:MyUserControl x:Name="uc1" CustomClick="uc1_CustomClickHandler"/>
To hook up a handler for the (routed) event of one element (e.g. the CustomClick event in your example) to another element (e.g. the parent window):
<Window c:MyUserControl.CustomClick="ucCustomEvent_CustomClick"/>
Now, if you want to tie up an event in your UI to a Command in your ViewModel, you will need attached behaviors to do that. There are lots of frameworks around featuring different implementations of this. Here's one you can try out: http://sachabarber.net/?p=514. It will allow you to do something like the following in your code:
<c:MyUserControl local:CommandBehavior.RoutedEventName="MyCustomClick"
local:CommandBehavior.TheCommandToRun="{Binding MyViewModelCommand}"/>
Hope this helps.
We have a Region in the Window tag of our shell, adding things to this region pops out another Window.
<Window x:Class="GTS.GRS.N3.Shell.Shell1"
--removed namespace references for clarity
cal:RegionManager.RegionName="{x:Static Constants:RegionNames.WindowRegion}">
We're adding ViewModels to the Region Manager and then the View is attached via a data context so that the ViewModel knows nothing about the View i.e.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<DataTemplate DataType="{x:Type Model:CommunicationViewModel}">
<v:CommunicationView />
</DataTemplate>
</ResourceDictionary>
My question is how do I close the Pop up Window, I tried removing the ViewModel from the RegionManager - but this exceptions ... the View is a UserControl, but I need to close its Owner which is a new Window opened by the Region. I don't really want to have to hack it via the DataContext of the ViewModel.
Can anyone assist please?
Andy,
It took me quite awhile to figure this one out myself.
The cleanest way to accomplish this is by using the DelegateCommand (or RelayCommand) and adding an event handler in the code that creates the window with window.Show().
// Define the View
Shell window = Container.Resolve<Shell>();
// Define the ViewModel
ShellViewModel windowVM = Container.Resolve<ShellViewModel>();
// When the ViewModel asks to be closed, close the View.
EventHandler handler = null;
handler = (sender, e) =>
{
windowVM.RequestClose -= handler;
window.Close();
};
windowVM.RequestClose += handler;
// Set the ViewModel as the DataContext of the View
window.DataContext = windowVM;
// Display the View
window.Show();
I then use a Composite Event to notify the window's ViewModel (not the UserControl's) that it has a request to close. The assigned subscription handler for the composite event then calls this.OnRequestClose().
In the Constructor for the ViewModel:
//subscribe to composite events
_eventAggregator.GetEvent<WindowCloseEvent>().Subscribe(WindowClose);
In the body of the ViewModel:
/// <summary>
/// Private Event handler for WindowCloseEvent.
/// </summary>
private void WindowClose(bool value)
{
// Close the View
this.OnRequestClose();
}
See Josh Smith's excellent article on MSDN about using the M-V-VM pattern with WPF at http://msdn.microsoft.com/en-us/magazine/dd419663.aspx for more information.
_regionManager.Regions[RegionNames.PopupRegion].Deactivate(_regionManager.Regions[RegionNames.PopupRegion].ActiveViews.FirstOrDefault());