I am aware that this question is very similar to this one, but I would have thought the following code would have canceled the shutdown request, but it doesn't? Can anyone explain why?
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);
}
private void button1_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
}
}
}
From MSDN:
Important: When Shutdown is called,
the application will shut down
irrespective of whether the Closing
event of any open windows is canceled.
Related
I created a MainWindow in the main thread, and there was a button in the MainWindow. When the button was clicked, a thread was created, and the thread created a NewWindow, NewWindow. But when I closed NewWindow, I clicked the button of the MainWindow again, and could not enter the function executed by the thread. I want to know exactly what to do to make NewWindow show when I press the button again.
namespace WpfApp
{
/// <summary>
/// MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private bool Restart;
private Thread WindowThread;
private SecondWindow NewWindow;
public MainWindow()
{
InitializeComponent();
}
/// <summary>
///
/// </summary>
private void LaunchWindow()
{
while (true)
{
if (Restart)
{
if (ExportWindow == null)
{
SynchronizationContext.SetSynchronizationContext(
new DispatcherSynchronizationContext(
Dispatcher.CurrentDispatcher));
NewWindow = new SecondWindow();
NewWindow.Closing += (s, e) =>
{
Hide();
e.Cancel = true;
};
NewWindow.Closed += (s, e) =>
{
Dispatcher.ExitAllFrames();
};
}
Restart = false;
ExportWindow.Show();
Dispatcher.Run();
}
}
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnNewClick(object sender, RoutedEventArgs e)
{
if (WindowThread == null)
{
WindowThread = new Thread(new ThreadStart(LaunchWindow));
WindowThread.SetApartmentState(ApartmentState.STA);
WindowThread.IsBackground = true;
WindowThread.Start();
}
Restart = true;
}
}
}
I making some UI and I have ProgressBar in it. Using MVVM pattern.
XAML:
<ProgressBar Grid.Row="2" Minimum="0" Maximum="100" Value="{Binding CurrentProgress, Mode=OneWay}"/>
ViewModel (simplified):
class MyClass : ViewModelBase
{
/// <summary>
/// Fields
/// </summary>
private int _currentProgress;
private readonly BackgroundWorker _worker;
private int _step;
/// <summary>
/// Properties
/// </summary>
public int CurrentProgress
{
get
{
return _currentProgress;
}
set
{
if (_currentProgress != value)
{
_currentProgress = value;
RaisePropertyChanged("CurrentProgress");
}
}
}
/// <summary>
/// Constructor
/// </summary>
public MyClass()
{
_step = 10;
_currentProgress = 0;
_worker = new BackgroundWorker();
_worker.DoWork += DoWork;
_worker.WorkerReportsProgress = true;
_worker.ProgressChanged += ProgressChanged;
_worker.RunWorkerCompleted += RunWorkerCompleted;
}
/// <summary>
/// Command
/// </summary>
private RelayCommand _myCommand;
public RelayCommand MyCommand
{
get
{
return _myCommand ?? (_myCommand =
new RelayCommand(_worker.RunWorkerAsync, CanMyCommand));
}
}
private bool CanMyCommand()
{
return true;
}
/// <summary>
/// Handlers
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 10; i++)
ConsumingMethod();
}
private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Thread.Sleep(5000);
Messenger.Default.Send(new CloseAddDocumentWindow(String.Empty));
}
private void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
CurrentProgress = e.ProgressPercentage;
}
/// <summary>
/// Method
/// </summary>
private void ConsumingMethod()
{
CurrentProgress += _step;
}
}
Code-Behind:
Messenger.Default.Register<CloseAddDocumentWindow>(this, nm =>
{
if (nm.Sender == DataContext)
Close();
});
So, this
Messenger.Default.Send(new CloseAddDocumentWindow(String.Empty));
is the problem. That line close window as u see. If I comment that line, progressbar works good. 10, 20, 30, ... 100% I see. But else, progressbar looks like 10, 20, 30, ... 90%, some waiting and window closing! I try to use Thread.Sleep(5000), to give the progressbar some time to drawing. But even that doesn't help. So, how can I see last persentage change if window closing immediately after that?
For any future reader:
BackgroundWorker's DoWork is performed on a new thread, allowing work to occur without locking the UI for instance. The RunWorkerCompleted functionality will be ran on the calling thread for you, this means it is back on the UI thread and any work done here can lock the UI.
ProgressBar is being updated via different thread, allowing it to update. But as soon as the value goes from 90 to 100, the UI is performing this Close. When OP added the Sleep(5000); it was in the Completed which is the UI thread thus preventing the ProgressBar from showing a full 100%.
Resolution is to move the sleep from Completed into the DoWork loop, or at least after the loop, to see the ProgressBar hit 100%, before sending the close.
When button1 gets tapped by the stylus test method gets called twice, even though I am setting the Handled property in the stylusdown event. Is there a way to have the stylus event not propegate a secondary button click event?
namespace DialogTest
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
test(sender, e);
}
private void button1_StylusDown(object sender, StylusDownEventArgs e)
{
test(sender, e);
e.Handled = true;
}
private void test(object e, EventArgs env)
{
Console.WriteLine(e.ToString(), env.ToString());
Console.WriteLine("clicking");
}
}
If you look at this MSDN Input overview documentation. you will see the fact the both events are called.
From above link:
Because the stylus can act as a mouse, applications that support only mouse input can still obtain some level of stylus support automatically. When the stylus is used in such a manner, the application is given the opportunity to handle the appropriate stylus event and then handles the corresponding mouse event. In addition, higher-level services such as ink input are also available through the stylus device abstraction.
Since it does give you the order the events are called you can create a Boolean variable, set it in the StylusDown EventHandler, then check in your Button_Click EventHandler if it is true, set it to false then exit the Handler.
something like this.
public partial class Window1 : Window
{
bool StylusDown;
public Window1()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
if(StylusDown)
{
StylusDown=false;
return;
}
test(sender, e);
}
private void button1_StylusDown(object sender, StylusDownEventArgs e)
{
StylusDown =true;
test(sender, e);
}
private void test(object e, EventArgs env)
{
Console.WriteLine(e.ToString(), env.ToString());
Console.WriteLine("clicking");
}
}
There may be a better way of accomplishing this, but this is was the first thing that came to mind.
MouseEventArgs has a property called StylusDevice that will be not null if the event originated from a stylus or touch event.
private void button1_Click(object sender, MouseButtonEventArgs e)
{
if (e.StylusDevice != null) return;
...
}
I have a user control that contains a ListBox.
I want to expose a SelectionChanged event on my user control that wraps the listBox.SelectionChanged event.
So that, when the listbox item selection changes, my own custom event on the user control also gets fired after that...
How would I do that?
Any sample would be appreciated.
Thanks!
I'm not sure wrapping is the best approach, even if you could wrap it. I'd suggest just defining your own event, and fire your own event in the handler hooked to listBox.SelectionChanged. You can then pass on any data from the original listbox event to your own event.
Added sample:
public partial class MainWindow : Window
{
public delegate void CustomSelectionChangedEventHandler(object sender, SelectionChangedEventArgs e);
public event CustomSelectionChangedEventHandler CustomSelectionChanged;
public MainWindow()
{
InitializeComponent();
listBox1.SelectionChanged += delegate(object sender, SelectionChangedEventArgs e)
{
OnCustomSelectionChanged(e);
};
}
void listBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
OnCustomSelectionChanged(e);
}
//We'll use the system defined SelectionChangedEventArgs type instead of creating a derived EventArgs class
protected virtual void OnCustomSelectionChanged(SelectionChangedEventArgs e)
{
if (CustomSelectionChanged != null)
CustomSelectionChanged(this, e);
}
}
Further reading:
http://msdn.microsoft.com/en-us/library/edzehd2t.aspx
http://msdn.microsoft.com/en-us/library/17sde2xt.aspx
If you want your custom event on your UserControl to bubble up the visual tree you should expose it as a RoutedEvent. In your .xaml.cs file you'll need to register the event as a routed event and then implement a custom handler and event args class.
XAML:
<UserControl x:Class="WpfApplication1.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<ListView Name="myListView" SelectionChanged="OnSelectionChanged_"/>
</Grid>
</UserControl>
Code:
public partial class MyUserControl : UserControl
{
public delegate void CustomSelectionChangedEventHandler(object sender, SelectionChangedRoutedEventArgs args);
public static readonly RoutedEvent CustomSelectionChangedEvent = EventManager.RegisterRoutedEvent(
"CustomSelectionChanged", RoutingStrategy.Bubble, typeof(CustomSelectionChangedEventHandler), typeof(MyUserControl));
public event RoutedEventHandler CustomSelectionChanged
{
add { AddHandler(CustomSelectionChangedEvent, value); }
remove { RemoveHandler(CustomSelectionChangedEvent, value); }
}
public MyUserControl()
{
InitializeComponent();
}
private void OnSelectionChanged_(object sender, SelectionChangedEventArgs e)
{
RaiseEvent(new SelectionChangedRoutedEventArgs(myListView, CustomSelectionChangedEvent, e.AddedItems, e.RemovedItems));
}
}
public class SelectionChangedRoutedEventArgs : RoutedEventArgs
{
public IList AddedItems { get; set; }
public IList RemovedItems { get; set; }
public SelectionChangedRoutedEventArgs(object source, RoutedEvent routedEvent, IList addedItems, IList removedItems)
: base(routedEvent, source)
{
AddedItems = addedItems;
RemovedItems = removedItems;
}
}
The caller of your control would then provide an event handler for the CustomSelectionChanged event with the signature of:
private void OnCustomSelectionChanged(object sender, SelectionChangedRoutedEventArgs e) { }
I am not familiar with using event handlers, and I was wondering if anyone had or could direct me to some code that shows how to use an event handler that will execute code on the Close/Closed event?
I know this can be done because of this answered question:
Run code on WPF form close
But I need some direction.
Thank you =)
It's just this XAML
<Window ... Closing="Window_Closing" Closed="Window_Closed">
...
</Window>
and code for both the Closing and Closed events
private void Window_Closing(object sender, CancelEventArgs e)
{
...
}
private void Window_Closed(object sender, EventArgs e)
{
....
}
If you want to do it all from code behind put this in your windows .cs file
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Closed += new EventHandler(MainWindow_Closed);
}
void MainWindow_Closed(object sender, EventArgs e)
{
//Put your close code here
}
}
}
If you want to do part in xaml and part in code behind do this in xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Closed="MainWindow_Closed">
<Grid>
</Grid>
</Window>
and this in .cs
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
void MainWindow_Closed(object sender, EventArgs e)
{
//Put your close code here
}
}
}
The above to examples you can apply to any form in a xaml app. You can have multiple forms. If you want to apply code for the entire application exit process modify your app.xaml.cs file to this
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnExit(ExitEventArgs e)
{
try
{
//Put your special code here
}
finally
{
base.OnExit(e);
}
}
}
}
You can override the OnExit function in App.Xaml.cs like this:
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnExit(ExitEventArgs e)
{
//do your things
base.OnExit(e);
}
}
If you are using C# on Microsoft Visual Studio, the following worked for me.
In your Window.cs file
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace Name_Space
{
public partial class Window : Form
{
public Window()
{
InitializeComponent();
//...
}
private void Window_Load(object sender, EventArgs e)
{
//...
}
private void Window_Closed(object sender, EventArgs e)
{
// Your code goes here...!
}
}
}
In your Window.Designer.cs file add this line to the following method
...
private void InitializeComponent()
{
...
//
// Window
//
...
this.Closed += new System.EventHandler(this.Window_Closed); // <-- add this line
}
...