How to use Application.Exit Event in WPF? - c#

I need to delete some certain files, then user closes program in WPF. So I tried MDSN code from here http://msdn.microsoft.com/en-us/library/system.windows.application.exit.aspx this way:
this code located here App.xml.cs
public partial class App : Application
{
void App_Exit(object sender, ExitEventArgs e)
{
MessageBox.Show("File deleted");
var systemPath = System.Environment.GetFolderPath(
Environment.SpecialFolder.CommonApplicationData);
var _directoryName1 = Path.Combine(systemPath, "RadiolocationQ");
var temp_file = Path.Combine(_directoryName1, "temp.ini");
if (File.Exists(temp1_file))
{
File.Delete(temp1_file);
}
}
}
// App.xaml
<Application x:Class="ModernUIApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
ShutdownMode="OnExplicitShutdown"
Exit="App_Exit">
<Application.Resources>
First of all it doesn't delete files, secondly this program stays in the process after I pushed exit button( this is really strange). This code don't give any errors. And finally it doesn't show MessageBox So anything wrong here?
I think he just can`t find this function.

It's quite simple:
Add "Exit" property to the application tag
<Application x:Class="WpfApplication4.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
Exit="Application_Exit">
</Application>
and handle it in the "code behind"
private void Application_Exit(object sender, ExitEventArgs e)
{
// Perform tasks at application exit
}
The Exit event is fired when the application is shutting down or the Windows session is ending. It is fired after the SessionEnding event. You cannot cancel the Exit event.

you should add app_exit in your xaml code
<Application x:Class="CSharp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
ShutdownMode="OnExplicitShutdown"
Exit="App_Exit"
>
</Application>
you can just hook the event Closing on your main window like this -
<Window Closing="Window_Closing">
And in your event do all the work you need
private void Window_Closing(object sender, CancelEventArgs e)
{
MessageBox.Show("File deleted");
var systemPath = System.Environment.GetFolderPath(
Environment.SpecialFolder.CommonApplicationData);
var _directoryName1 = Path.Combine(systemPath, "RadiolocationQ");
var temp_file = Path.Combine(_directoryName1, "temp.ini");
if (File.Exists(temp1_file))
{
File.Delete(temp1_file);
}
}

If you don't like adding Exit event to XAML, you could try this alternative.
Add following method to your App.xaml.cs:
protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
// Your code here
}

If you want to follow MVVM principle you can use System.Windows.Interactivity.WPF.
MainWindow.xaml
<Window x:Class="Endonext.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<i:InvokeCommandAction Command="{Binding WindowClosingCommand, Mode=OneTime}" />
</i:EventTrigger>
</i:Interaction.Triggers>
MainWindowViewModel.cs
public class MainWindowViewModel
{
ICommand WindowClosingCommand => new RelayCommand(arg => this.WindowClosing());
private void WindowClosing()
{
// do what you want.
}
}
This approach is more testable.
Have a nice day.

Make sure that the namespace (MyApp) matches "x:Class=MyApp..."
Under properties for <Application></Application>, double click on the textbox next to 'Exit'.
If you get "Unable to add event handler" then Rebuilding the project fixed it for me.
XAML
<Application x:Class="MyApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
Exit="Application_Exit"
>
Code behind
using System.Windows;
namespace MyApp
{
public partial class App : Application
{
private void Application_Exit(object sender, ExitEventArgs e)
{
//your code
}
}
}

Related

Use ChromiumFX/ChromiumWebBrowser inside an C# addin

I’m trying to add a ChromiumWebBrowser components inside a C#/WPF addin. (Before the addin used CefSharp but the new version of the host application run addin inside custom AppDomain so CefSharp doesn’t work anymore.)
To the problem is, when I call ChromiumWebBrowser.Initialize() a new instance of the host application is launch 🤔 (with some command line args which are dropped by the application).
I really don’t understand the stuff around this command line.
Can you explain to me where I do a mistake ? ChromiumWebBrowser cannot be used inside addin ? I miss somethings ?
Here the C# sample of my code
public partial class myWindow : Window
{
public myWindow()
{
CfxRuntime.LibCefDirPath = #"E:\sources\app\Output\Debug_msvc2017_x64\Addins\cef\Release64";
ChromiumWebBrowser.OnBeforeCfxInitialize += ChromiumWebBrowser_OnBeforeCfxInitialize;
ChromiumWebBrowser.OnBeforeCommandLineProcessing += ChromiumWebBrowser_OnBeforeCommandLineProcessing;
Chromium.WebBrowser.ChromiumWebBrowser.Initialize();
InitializeComponent();
// browser is a ChromiumWebBrowser instance
browser.MouseClick += Wb_MouseClick;
browser.Show();
}
private void Wb_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
{
(sender as ChromiumWebBrowser).LoadUrl("https://www.google.com"); // properly trigger but nothings will be displayed
}
static void ChromiumWebBrowser_OnBeforeCommandLineProcessing(CfxOnBeforeCommandLineProcessingEventArgs e)
{
Console.WriteLine(e.CommandLine.CommandLineString); // here the command line create a new instance of the application where the plugin is loaded
}
static void ChromiumWebBrowser_OnBeforeCfxInitialize(OnBeforeCfxInitializeEventArgs e)
{
e.Settings.LocalesDirPath = #"E:\sources\app\Output\Debug_msvc2017_x64\Addins\cef\locales";
e.Settings.ResourcesDirPath = #"E:\sources\app\Output\Debug_msvc2017_x64\Addins\cef\Resources";
}
}
‌
And the xaml part
‌
<Window x:Class="App.Views.myWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:App.Views"
xmlns:webbrowser="clr-namespace:Chromium.WebBrowser;assembly=ChromiumWebBrowser"
mc:Ignorable="d"
Title="myWindow" Height="800" Width="1200">
<Grid x:Name="grid1">
<WindowsFormsHost x:Name="wpfContainer">
<webbrowser:ChromiumWebBrowser x:Name="browser"></webbrowser:ChromiumWebBrowser>
</WindowsFormsHost>
</Grid>
</Window>
‌
Thanks in advance for your help ;)

WPF data binding is not working for second usage

I'm using GalaSoft.MvvmLight.Messaging for communication between classes.
From my ViewModel I'm asking for an object of type view to use it as the content of my DialogHost ( part of the MaterialDesign Framework ):
ViewModel:
Messenger.Default.Send(new NotificationMessage("dialogFormOpenStaple"));
-
private void DialogReceived(string msg, object param)
{
if (msg == "dialogFormOpenStaple")
{
this.dialogContent = param;
this.isDialogOpen = true;
}
}
View
private void NotificationMessageReceived(string msg)
{
if (msg == "dialogFormOpenStaple")
{
object content = new dialogEditMode();
Messenger.Default.Send(new NotificationMessage<object>(content, "dialogFormOpenStaple"));
}
}
All this is working fine. In my XAML itself I got some button bindings to RelayCommands.
<UserControl x:Class="kati2._0.production.dialogEditMode"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:kati2._0.production"
mc:Ignorable="d"
>
[...]
<Button Margin="8 0 0 0" Style="{DynamicResource MaterialDesignFlatButton}" Foreground="#FF757476" IsDefault="True" Command="{Binding dialogOpenStapleNo}">No</Button>
[...]
</UserControl>
Those RelayCommands are defined in my ViewModel. When I open die Dialog for the first time and click on the button it's working fine. If I try it a second time the dialog also opens up but the click event is not getting triggered.

Binding app.xaml to view WPF in c#

I use MVVM framework and got this tutorial on net: https://code.msdn.microsoft.com/windowsdesktop/How-to-use-MVVM-Pattern-0e2f4571 and http://www.c-sharpcorner.com/UploadFile/raj1979/simple-mvvm-pattern-in-wpf/
Now, my problem is:
I can't display the mainpage.xaml even there is no semantic error. Here's my code on app.xaml.cs:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
BasicWPF.View.MainPage window = new MainPage();
UserViewModel VM = new UserViewModel();
window.DataContext = VM;
window.Show();
}
Can anyone help me? Thanks for any help! :)
Thanks to everyone who helped.
[SOLVED]
Change the startupuri in app.xaml to where the page you want to load. In my case
1: I change it:
StartupUri="View/MainPage.xaml"
2: In app.xaml.cs, I typed in this code:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
BasicWPF.View.MainPage window = new MainPage();
UserViewModel VM = new UserViewModel();
window.DataContext = VM;
}
from my previous code, delete this code: window.show(); because it startup the page twice coming from app.xaml and app.xaml.cs. To prevent that, delete: window.show();
Thank you again! :)
Set the starting page in app.xaml, not the app.xaml.cs file - in the Application tag, if there is no property StartupUri - add one and set its value to your page name, this way the page will be automatically shown as soon as your application is started. It should look something like this:
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainPage.xaml">
I am considering that you are doing it this way because you wish to set the DataContext of the page, but there is a better way to set the DataContext of your page and it is by setting it directly into your XAML code. Here is an example:
<Page x:Class="WpfApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525" >
<Page.DataContext>
<local:UserViewModel/>
</Page.DataContext>
xmlns:local is a prefix mapping to the namespace you have set for it. Having this you are able to access the types contained in the namespace using the prefix - local:UserViewModel.
what you can do is instead of setting data context in app.xaml.cs, just hook up the loaded event of main window and add the following code.
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
UserViewModel VM = new UserViewModel();
this.DataContext = VM;
}
This should work. Dont forget to remove the codes from App.xaml.cs.
Thanks
SO in your case you have a main window inside that main window you need to load the page.
What you can do is add a frame to your mainwindow like
<Frame x:Name="myFrame"/>
then inside the mainwindow loaded event add the below code
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
UserViewModel VM = new UserViewModel();
this.DataContext = VM;
myFrame.Content = new MainPage();
}
This is like we are adding a frame and loading your view to that frame.

NullReferenceException loading RenderWindowControl for vtk in WPF

I am trying to load a RenderWindowControl from vtk libraries on my WPF proyect using ActiViz.NET and Visual Studio 2013. The library works fine since I did a new project just to practice on itbut when I tried to integrate it into my work, I got a null RenderWindowControl this time. This is my code:
MainWindow.xaml:
<Window x:Class="myProject.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:VtkTab="clr-namespace:myProject.Views.UITabs.VtkTab"
x:Name="Mainwindow"
MinHeight="600"
MinWidth="800"
Title="{Binding Title}"
Height="720"
Width="1280"
Icon="{StaticResource ApplicationIcon}"
Loaded="OnLoaded"
DataContext="{Binding Main, Source={StaticResource ViewModelLocator}}"
Style="{StaticResource WindowStyle}"
mc:Ignorable="d">
<DockPanel>
<TabControl>
....
....
<VtkTab:VtkTabView />
....
....
</TabControl>
</DockPanel>
</Window>
VtkTabView.xaml:
<UserControl x:Class="myProject.Views.UITabs.VtkTab.VtkTabView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vtk="clr-namespace:Kitware.VTK;assembly=Kitware.VTK"
Loaded="WindowLoaded"
Height="480" Width="640">
<WindowsFormsHost Name="Wfh">
<vtk:RenderWindowControl x:Name="RenderControl" />
</WindowsFormsHost>
</UserControl>
VtkTabView.xaml.cs:
public partial class UITabView
{
protected static Random _random = new Random();
vtkActor actor = vtkActor.New();
public VtkTabView()
{
InitializeComponent();
var sphere = vtkSphereSource.New();
sphere.SetThetaResolution(8);
sphere.SetPhiResolution(16);
var shrink = vtkShrinkPolyData.New();
shrink.SetInputConnection(sphere.GetOutputPort());
shrink.SetShrinkFactor(0.9);
var move = vtkTransform.New();
move.Translate(_random.NextDouble(), _random.NextDouble(), _random.NextDouble());
var moveFilter = vtkTransformPolyDataFilter.New();
moveFilter.SetTransform(move);
moveFilter.SetInputConnection(shrink.GetOutputPort());
var mapper = vtkPolyDataMapper.New();
mapper.SetInputConnection(moveFilter.GetOutputPort());
// The actor links the data pipeline to the rendering subsystem
actor.SetMapper(mapper);
actor.GetProperty().SetColor(1, 0, 0);
}
private void WindowLoaded(object sender, RoutedEventArgs e)
{
var renderer = RenderControl.RenderWindow.GetRenderers().GetFirstRenderer();
renderer.AddActor(actor);
}
}
RenderControl.RenderWindow is null on WindowLoaded (VtkTabView.xaml.cs) and I do not know why. Might it be because I load UITabView from a second xamp and I lose the content of RenderControl?, it is the only difference I see compare to the example I did.
Access the RenderWindow on Load event of the RenderWindowControl.
e.g.
public VtkTabView()
{
InitializeComponent();
// initialize your sphrere and actor
RenderControl.Load += MyRenderWindowControlOnLoad;
}
private void MyRenderWindowControlOnLoad(object sender_in, EventArgs eventArgs_in){
//access the RenderWindow here
}

FlowDocument and XamlReader x:Class

In my MainWindow I have a FlowDocumentScrollViewer binding its property Document to a FlowDocument in my MainViewModel.
This document is loaded from an external xaml file store on a remote computer. Currently I'm able to load this document properly via XamlReader.Load(xamlfile) and display it in the FlowDocumentScrollViewer. So far so good.
The problem occurs when I try to add hyperlink in this document. Because to handle the RequestNavigate event I need a x:Class. For the time being this Class need to be my MainWindow because the event is handle in the code-behind. Obviously when I add x:Class="Ugrader.MainWindow" in my external document I get a lovely 'System.Windows.Markup.XamlParseException' at the moment of parsing.
So is there a way to solve this ?
Here is piece of my code
MainWindow.xaml
<Window x:Class="Ugrader.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Geco3-Upgrading version"
WindowStyle="none" ResizeMode="NoResize" ShowInTaskbar="False" WindowStartupLocation="CenterScreen"
Height="400" Width="700"
DataContext="{Binding Main,Source={StaticResource Locator}}">
<FlowDocumentScrollViewer Grid.Column="1" Background="{x:Null}" VerticalScrollBarVisibility="Hidden"
Document="{Binding WhatsNewDoc}"/>
</Window>
MainViewModel.cs
namespace Ugrader.ViewModel
{
public class MainViewModel : ViewModelBase
{
#region Constructor
public MainViewModel()
{
try
{
FileStream xamlFile = new FileStream(updateLocation + "whatsnew.xaml", FileMode.Open, FileAccess.Read);
FlowDocument current = System.Windows.Markup.XamlReader.Load(xamlFile) as FlowDocument;
WhatsNewDoc = current;
}
catch (Exception)
{
}
}
#endregion
#region Properties
private FlowDocument _watsNewDoc = new FlowDocument();
public FlowDocument WhatsNewDoc
{
get
{
return _watsNewDoc;
}
set
{
if(_watsNewDoc != value)
{
_watsNewDoc = value;
RaisePropertyChanged("WhatsNewDoc");
}
}
}
#endregion
}
}
The external FlowDocument
<FlowDocument x:Class="Ugrader.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
ColumnWidth="400" FontSize="12" FontFamily="Century Gothic" Foreground="LightGray">
<Paragraph>
<Italic>
For additionnal information, please watch this
<Hyperlink TextDecorations="{x:Null}" RequestNavigate="Hyperlink_Clicked" NavigateUri="path_to_the_file" >video</Hyperlink>
</Italic>
</Paragraph>
</FlowDocument>
By the way, is there a way to handle this parse exception (in case of bad external file), because even in this try/catch block, this stop my program.
Thanks you in advance,
Bastien.
I find a way to deal with my problem, it's not really beautiful, do not respect the spirit of mvvm, but well, this is working.
So, as it's not possible to add x:Class at runtime (I guess), I came to the idea of handling the RequestNavigate event of each Hyperlinkat runtime. So the solution is pretty simple (and dirty).
In code-behind (yeah I know, it's ugly), on the MainWindow loaded event, I find all hyperlinks in my document, and handle each RequestNavigate events. As simple (and dirty) as this.
Here is some code :
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var hyperlinks = GetVisuals(this).OfType<Hyperlink>();
foreach (var link in hyperlinks)
link.RequestNavigate += link_RequestNavigate;
}
public static IEnumerable<DependencyObject> GetVisuals(DependencyObject root)
{
foreach (var child in LogicalTreeHelper.GetChildren(root).OfType<DependencyObject>())
{
yield return child;
foreach (var descendants in GetVisuals(child))
yield return descendants;
}
}
If someone has a better solution, I take it.

Categories

Resources