How can I catch the OnClosing Event from a Ribbon Window? - wpf

In my application I used to use the wpf windows where are extendd from System.WIndows.Window.
I am thinking of migrate them to using Ribbon Windows which are extended From ToolWindow.
Unfortunately I can't use the OnClosing event with Ribbon windows.
How can I trigger when a window is closed?
I need something like the following
protected override void OnClosing(CancelEventArgs e) {
e.Cancel = true;
}
Thanks

Try this:
on XAML add Closing
<ribbon:RibbonWindow x:Class="RibbonWindowSample.RibbonWindowWord"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ribbon="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon"
xmlns:local="clr-namespace:RibbonWindowSample"
Title="RibbonWindowWord" Height="600" Width="1000"
Closing="RibbonWindow_Closing"
>
<TextBlock Text="Hello" />
</ribbon:RibbonWindow>
on Code add
private void RibbonWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (MessageBox.Show("Confirm?", "Confirm", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
e.Cancel = true;
}

Related

Add cofirmation message when ever user clicks on close button in WPF with MVVM

In WPF with MVVM,how to add a confirmation message when a user clicks on close button. Everytime,it just closes the window without any confirmation message whereas the same thing is happening in windows form.
In APP.XAML.CS
public partial class App : Application
{
protected override void OnExit(ExitEventArgs e)
{
if (MessageBox.Show("Sure you wanna close?", "..", MessageBoxButton.YesNo) == MessageBoxResult.No)
e.ApplicationExitCode = 110;
base.OnExit(e);
}
}
When i click on Close button it doesnt ask for confirmation just closes the window.
You could use a behavior.
First of all, you have to add a reference to Interactivity in your project.
Go to References-addReference-assemblies-System.Windows.Interactivity.
Now, you create the behavior.
public class CloseWindowBehavior : Behavior<Window>
{
protected override void OnAttached()
{
this.AssociatedObject.Closing += AssociatedObject_Closing;
}
private void AssociatedObject_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (MessageBox.Show("Sure you wanna close?", "..", MessageBoxButton.YesNo) == MessageBoxResult.No)
e.Cancel = true;
}
}
When you click on the close button, the event assigned will be fired, showing the message box.
Now, you have to declare this created behavior in your xaml file.
<Window x:Class="WpfApplication1.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="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<i:Interaction.Behaviors>
<local:CloseWindowBehavior />
</i:Interaction.Behaviors>
<Grid>
</Grid>
Since you are using the pattern MVVM, behavior is a good choice since you don't need to write a single line in the code behind.
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
base.ShutdownMode = ShutdownMode.OnMainWindowClose;
//update user settings (if first run after software upgrade)
}
// Initialise the application directory//
// Set up the main window and its view model
var mainWindow = new MainWindow();
mainWindowViewModel = new MainWindowViewModel();
mainWindow.DataContext = mainWindowViewModel;
mainWindow.Show();
}
protected override void OnExit(ExitEventArgs e)
{
e.ApplicationExitCode = 110;
Dispose();
base.OnExit(e);
}

Why does my popup not respond to touches? [duplicate]

This question already has answers here:
SurfaceScrollViewer: getting touch on nested children
(2 answers)
Closed 2 years ago.
I have been banging my head on this for a while now! Here is my simple User Control:
<UserControl x:Class="DaCapo.MyUserControl"
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:s="http://schemas.microsoft.com/surface/2008"
IsManipulationEnabled="True"
Width="300" Height="300">
<Canvas>
<s:SurfaceButton x:Name="button" Width="100" Height="100" Content="Click!" Style="{x:Null}"/>
<Popup x:Name="popup" Width="200" Height="100" IsOpen="False" StaysOpen="True" PlacementRectangle="0,0,200,100"
AllowsTransparency="True" Focusable="True">
<DockPanel x:Name="dockpanel" Width="200" Height="100" Background="SteelBlue" Focusable="True"/>
</Popup>
</Canvas>
</UserControl>
I want to be able to detect touches on the DockPanel or in a possible child of it. Here follows the code behind for the same class, with the alternatives I attempted:
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
TouchExtensions.AddHoldGestureHandler(this.button, this.HoldHandler);
/* NONE OF THE FOLLOWING WORKS */
// TouchExtensions.AddTapGestureHandler(this.popup, this.TapHandler);
// this.dockpanel.TouchDown += new System.EventHandler<TouchEventArgs>(popup_TouchDown);
// this.popup.TouchDown += new System.EventHandler<TouchEventArgs>(popup_TouchDown);
// this.popup.ManipulationStarting += new System.EventHandler<ManipulationStartingEventArgs>(popup_ManipulationStarting);
// this.dockpanel.ManipulationStarting += new System.EventHandler<ManipulationStartingEventArgs>(popup_ManipulationStarting);
}
void popup_ManipulationStarting(object sender, ManipulationStartingEventArgs e) { Debug.WriteLine("Tap..."); }
void popup_TouchDown(object sender, TouchEventArgs e) { Debug.WriteLine("Tap..."); }
private void TapHandler(object sender, TouchEventArgs e) { Debug.WriteLine("Tap..."); }
private void HoldHandler(object sender, TouchEventArgs e) { Debug.WriteLine("Holding..."); this.popup.IsOpen = true; }
}
I do believe I am missing something obvious. Can someone please help me? Thanks.
The Button & popup needs to be connected to its click (or touch) handlers defined in the code behind, in XAML itself.
If you want to handle touch events for the dockpanel, How about
adding a button inside the dockpanel with opacity = 0 ??
EDIT :
I can see that you defined a few handlers, but did you add those Handlers to the button?
For example, for a SurfaceButton :
IN XAML :
<s:SurfaceButton Click="OpenButton_Click"/>
Correspondingly connects the function in C# as:
private void OpenButton_Click(object sender, RoutedEventArgs e)
{
// Handle the action for the click here.
}
Under the covers, Popup creates another hwnd to render its content into. This is different from all other WPF controls. You need to register this hwnd with the Surface SDK so it will start sending touch events to it. Use this to do that: http://msdn.microsoft.com/en-us/library/microsoft.surface.presentation.input.touchextensions.enablesurfaceinput.aspx

WPF: using Commands bound in a UserControl

I'm doing a sample with MVVM and have a problem with commands. I have an Article class (with ID, Name, Price, etc.), an ArticleViewModel that represents the view model, and a user control (ArticleControl) that allows to input the data for the article, with bindings to the properties of the ArticleViewModel. This user control has a biding for a save command.
<UserControl.CommandBindings>
<CommandBinding x:Name="saveCmd"
Command="local:Commands.Save"
CanExecute="CommandBinding_CanExecute"
Executed="CommandBinding_Executed"/>
</UserControl.CommandBindings>
This is how the command is defined:
public class Commands
{
private static RoutedUICommand _save;
public static RoutedUICommand Save
{
get { return _save; }
}
static Commands()
{
InputGestureCollection saveInputs = new InputGestureCollection();
saveInputs.Add(new KeyGesture(Key.S, ModifierKeys.Control, "Ctrl+S"));
_save = new RoutedUICommand(
"Save",
"Save",
typeof(Commands),
saveInputs);
}
}
And the command binding handlers:
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
double baseprice = 0;
double.TryParse(ArticleBasePrice.Text, out baseprice);
e.CanExecute =
!string.IsNullOrEmpty(ArticleID.Text) &&
!string.IsNullOrEmpty(ArticleName.Text) &&
!string.IsNullOrEmpty(ArticleDescription.Text) &&
baseprice > 0;
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
ArticleViewModel avm = (ArticleViewModel)DataContext;
if (avm != null && avm.Save())
{
ArticleID.Text = String.Empty;
ArticleName.Text = String.Empty;
ArticleDescription.Text = String.Empty;
ArticleBasePrice.Text = String.Empty;
}
}
Now, I put this user control on a window. When I hit Ctrl+S the command is executed. However, I also put a Save button on that window, next to this user control. When I click it I want to execute the same command (and I don't want to do another command binding in the window where the user control is hosted).
<StackPanel>
<local:ArticleControl x:Name="articleControl" />
<Button Name="btnSave"
Content="Save" Width="100"
HorizontalAlignment="Left"
Command="{???}"/> <!-- what should I put here? -->
</StackPanel>
But I do not know how to refer that saveCmd defined in the user control. I tried different things, some are completely wrong (they throw exception when running the app), some don't have any effect.
Command="{StaticResource saveCmd}"
Command="{StaticResource local:ArticleControl.saveCmd}"
Command="{x:Static local:Commands.Save}"
Any help is appreciated. Thank you.
The reason why the Save button will not cause the commandbindings of your other control to execute is because the Save button is outside the user control and therefore the command system will not look for a commandbinding in that control. The Command execution strategy is a bit like a bubbling event and will start from the focused item (the Button) and go up the visual tree until it finds the CommandBindings.
You can either implement the command binding in the parent control or set the CommandTarget property of the Save button to the user control.
Another approach is to set the FocusManager.IsFocusScope=True on the button or the container of the button. If you do this I suggest you read up on what IsFocusScope does but in a nutshell it will leave the input focus on whatever control has the focus when you press the button, instead of making the button the new input focus. This is generally used for toolbars or menu like structures.
Based on Patrick's suggestions, this is what I did:
Put the command binding in the user control and implemented the handlers in the code-behind as shown in the original message.
Used Command, CommandTarget and FocusManager properties on the button to point to the binding from the user control (ArticleUserControl is the x:Name of the user control).
This is how the XAML for the window looks:
<Window x:Class="MVVMModel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMModel"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<local:ArticleControl x:Name="articleControl" />
<Button Name="btnSave" Content="Save" Width="100" HorizontalAlignment="Left"
Command="local:Commands.Save"
CommandTarget="{Binding ElementName=ArticleUserControl}"
FocusManager.IsFocusScope="True" />
</StackPanel>
</Window>
I think you just have to move your CommandBinding to a Resource Dictionary, so that it's available outside your UserControl!
Here is what I did to work, though I'm not particularly happy with the solution. If anyone knows a better approach, please do let me know.
I moved the logic for the commands handler in a separate, static class:
static class CommandsCore
{
public static bool Save_CanExecute(ArticleControl ac)
{
double baseprice = 0;
double.TryParse(ac.ArticleBasePrice.Text, out baseprice);
return
!string.IsNullOrEmpty(ac.ArticleID.Text) &&
!string.IsNullOrEmpty(ac.ArticleName.Text) &&
!string.IsNullOrEmpty(ac.ArticleDescription.Text) &&
baseprice > 0;
}
public static void Save_Executed(ArticleControl ac)
{
ArticleViewModel avm = (ArticleViewModel)ac.DataContext;
if (avm != null && avm.Save())
{
ac.ArticleID.Text = String.Empty;
ac.ArticleName.Text = String.Empty;
ac.ArticleDescription.Text = String.Empty;
ac.ArticleBasePrice.Text = String.Empty;
}
}
}
I kept the command binding in the user control as it was
<UserControl.CommandBindings>
<CommandBinding x:Name="saveCmd"
Command="local:Commands.Save"
CanExecute="CommandBinding_CanExecute"
Executed="CommandBinding_Executed"/>
</UserControl.CommandBindings>
But in the handlers I called the two methods I just defined above.
public void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = CommandsCore.Save_CanExecute(this);
}
public void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
CommandsCore.Save_Executed(this);
}
And then I did the same from the window where the control is used.
<Window x:Class="MVVMModel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMModel"
Title="MainWindow" Height="350" Width="525">
<Window.CommandBindings>
<CommandBinding x:Name="saveCmd"
Command="local:Commands.Save"
CanExecute="CommandBinding_CanExecute"
Executed="CommandBinding_Executed"/>
</Window.CommandBindings>
<StackPanel>
<local:ArticleControl x:Name="articleControl" />
<Button Name="btnSave" Content="Save" Width="100" HorizontalAlignment="Left"
Command="local:Commands.Save"/>
</StackPanel>
</Window>
and the handlers
public void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = CommandsCore.Save_CanExecute(articleControl);
}
public void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
CommandsCore.Save_Executed(articleControl);
}
And this works, the Save button is enabled only when the fields are filled in appropriately and the command is executed correctly when clicking the button.

KeyDown event in wpf hyperlink

I need to perform some operations on the keydown event on a wpf hyperlink.
I have a simple richtextbox in which i have a hyperlink. I want Keydown event to be fired only when the focus is on the hyperlink, that is the cursor is on the hyperlink text.
Doing this doesn't work and i couldn't find any explanation of why this doesn't work.
<Hyperlink KeyDown="Hyperlink_KeyDown">
test
</Hyperlink>
I would really appreciate it if you could help me.
Thanks.
Have a good day,
Astig.
it doesn't work because hyperlink isn't recognized like focused, you may catch this event in parent control for example grid but before it will be caught you must click on it.
So you may catch window's keydown event like this:
XAML:
<Window x:Class="WpfApplication3.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"
Name="MW" KeyDown="MW_KeyDown">
<Grid>
<TextBlock>
<Hyperlink Name="HL1" NavigateUri="http://www.google.com/" RequestNavigate="HL1_RequestNavigate">
Focus it and key down
</Hyperlink>
</TextBlock>
</Grid>
and code:
private void MW_KeyDown(object sender, KeyEventArgs e)
{
if (HL1.IsMouseOver == true)
HL1_RequestNavigate(HL1,new RequestNavigateEventArgs(HL1.NavigateUri, HL1.Name));
}
private void HL1_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true;
}
Edit
Also you can set focus to hyperlink like that:
XAML:
<Hyperlink Name="HL1" NavigateUri="http://www.google.com/" RequestNavigate="HL1_RequestNavigate" KeyDown="HL1_KeyDown" MouseEnter="HL1_MouseEnter">
code:
private void HL1_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true;
}
private void HL1_KeyDown(object sender, KeyEventArgs e)
{
HL1_RequestNavigate(HL1, new RequestNavigateEventArgs(HL1.NavigateUri, HL1.Name));
}
private void HL1_MouseEnter(object sender, MouseEventArgs e)
{
HL1.Focus();
}

UserControl PreviewMouseLeftButtonUp problem

I have a UserControl in WPF. I also have a Borderless window. To move it- I use DragMove.
But- to get a click event in the user control- I use the PreviewMouseLeftButtonUp event and capture the mouse on UserControl_MouseEnter.
The problem is- that if I click the control, then move the window- the event can be triggered also when clicking near the control, not on it.
Here is my code:
UserControl1.xaml:
<UserControl x:Class="WpfApplication1.UserControl1"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" MouseEnter="UserControl_MouseEnter" MouseLeave="UserControl_MouseLeave">
<Grid>
</Grid>
</UserControl>
UserControl1.xaml.cs:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void UserControl_MouseEnter(object sender, MouseEventArgs e)
{
CaptureMouse();
}
private void UserControl_MouseLeave(object sender, MouseEventArgs e)
{
ReleaseMouseCapture();
}
}
MainWindow.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" xmlns:my="clr-namespace:WpfApplication1" WindowStyle="None" MouseLeftButtonDown="Window_MouseLeftButtonDown">
<Grid>
<my:UserControl1 Margin="39,29,380,199" Background="Red" PreviewMouseLeftButtonUp="UserControl1_PreviewMouseLeftButtonUp">
</my:UserControl1>
</Grid>
</Window>
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DragMove();
}
private void UserControl1_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Hello World");
}
}
If you run this app- you'll see that if you click on the control, then drag the window, then click near the control (the side may vary)- it will trigger the PreviewMouseLeftButtonUp event even though you didn't click on the control itself.
Any ideas how to solve this?
Thanks!
I asked around, and found that to solve the problem, I need to change the User control's events:
Instead of MouseLeave- I use MouseMove.
private void UserControl_MouseEnter(object sender, MouseEventArgs e)
{
if (this.IsEnabled)
CaptureMouse();
}
private void UserControl_MouseMove(object sender, MouseEventArgs e)
{
Point mouseposition = e.GetPosition(this);
if (mouseposition.X < 0 || mouseposition.Y < 0 || mouseposition.X > this.ActualWidth || mouseposition.Y > this.ActualHeight)
ReleaseMouseCapture();
}

Resources