Scrolling in Sticky Notes - wpf

I got the following sticky note example:
If the sticky note has more than 9 rows, the additional rows are not visible.
I'm able to navigate through the note with my arrow keys. If I'm going to scroll with the mouse wheel, it seems to ignore the popup and just changes the page.
Is it possible to activate scrolling for sticky note popups?

Edit:The solution outlined below will soon be available as part of the samples included in the PDFTron SDK download. In the meanwhile, I hope that the below solution helps.
Yes, it is possible to activate scrolling for sticky notes.
The problem is most apparent when using the single page view. It appears to work as expected in continuous mode.
However it is not as simple as setting VerticalScrollVisibility = ScrollBarVisibility.Auto;. There are a few files that need to be modified to get this working.
The good news is that we can get the expected behaviour by modifying the code in the provided samples.
Solution
The solution is to add some handling for the PreviewMouseWheel event coming from the PDFViewWPF class.
In the downloaded samples, the following changes were made to get things running as expected:
Add a method to handle the PreviewMouseWheel event in the NoteHost class (Samples/PDFViewWPFTools/CS/Utilities/NoteHost.cs)
internal void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var originalSource = (UIElement)e.OriginalSource;
if (originalSource.IsDescendantOf(mNoteBorder) && mTextBox.IsFocused)
{
mTextBox.ScrollToVerticalOffset(mTextBox.VerticalOffset - e.Delta);
e.Handled = true;
}
}
Also make sure to add mTextBox.VerticalScrollBarVisibility = ScrollBarVisibility.Auto; in the NoteHost.CreateNoteAndArrow() method, after the mTextBox object is instantiated (~line 183).
Next, edit the NoteManager class - Samples/PDFViewWPFTools/CS/Utilities/NoteManager.cs - and add a HandlePreviewMouseWheel method. This will internally call the HandlePreviewMouseWheel on each displayed (opened) note and break at the first one where the event gets handled.
internal void HandlePreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
foreach(var note in mActiveNotes)
{
note.Value.HandlePreviewMouseWheel(sender, e);
if(e.Handled)
{
break;
}
}
}
Next, edit the ToolManager class to ensure that the note manager gets a chance to handle the PreviewMouseWheel before attempting a page change. Open Samples/PDFViewWPFTools/CS/ToolManager.cs and navigate to the PDFView_PreviewMouseWheel. The existing method should look like this:
private void PDFView_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
if (mCurrentTool != null && _IsEnabled)
{
ToolManager.ToolType prev_tm = mCurrentTool.ToolMode;
ToolManager.ToolType next_tm;
while (true)
{
mCurrentTool.PreviewMouseWheelHandler(sender, e);
next_tm = mCurrentTool.NextToolMode;
if (prev_tm != next_tm)
{
mCurrentTool = CreateTool(next_tm, mCurrentTool);
prev_tm = next_tm;
}
else
{
break;
}
}
}
}
Replace it with the below code:
private void PDFView_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
if (mCurrentTool != null && _IsEnabled)
{
ToolManager.ToolType prev_tm = mCurrentTool.ToolMode;
ToolManager.ToolType next_tm;
while (true)
{
mNoteManager.HandlePreviewMouseWheel(sender, e);
if (!e.Handled)
{
mCurrentTool.PreviewMouseWheelHandler(sender, e);
next_tm = mCurrentTool.NextToolMode;
if (prev_tm != next_tm)
{
mCurrentTool = CreateTool(next_tm, mCurrentTool);
prev_tm = next_tm;
}
else
{
break;
}
}
else
{
break;
}
}
}
}
By doing the above, we are giving the NoteManager a chance to handle the PreviewMouseWheel before doing anything else with it.
Another point to note is that we have to now "do the scrolling" in code, using the mTextBox.ScrollToVerticalOffset method in the NoteHost class.

Related

Spurious drop events after drag drop operation completes

I've implemented dragging to external applications in my WPF application and it works. However after dropping onto a target I continue to get spurious drop events on my application after I bring the cursor back onto it. This continues 'forever'.
As far as I can tell from online searches after calling DragDrop.DoDragDrop() I shouldn't need to do anything else. I have tried adding some code to cancel the event but it has no effect even though it runs:
private void UIElement_OnPreviewMouseMove(object sender, MouseEventArgs e)
{
var frameworkElement = (FrameworkElement) sender;
if (frameworkElement.DataContext is IDragSource dragSource)
{
var position = e.GetPosition((IInputElement) sender);
if (dragSource.DragCanStart(new Point {X = position.X, Y = position.Y}))
{
var dragStart = true;
void OnFrameworkElementOnQueryContinueDrag(object o, QueryContinueDragEventArgs e2)
{
if (!dragStart)
{
e2.Action = DragAction.Cancel;
frameworkElement.QueryContinueDrag -= OnFrameworkElementOnQueryContinueDrag;
}
}
frameworkElement.QueryContinueDrag += OnFrameworkElementOnQueryContinueDrag;
dragSource.DragInitiate(sender);
e.Handled = true;
dragStart = false;
}
}
}
I've tracked it down to our code initiating multiple drags. Our guard logic wasn't quite good enough which meant every time the mouse moved over the source component it triggered another drag.
Tricky to debug :)

programatically add button click in winforms?

is it possible to add button click event? i want to add controls dynamicly but i don't bind event's to my controls.
this.buttonDeneme = new System.Windows.Forms.Button();
this.buttonDeneme.Location = new System.Drawing.Point(150, 90);
this.buttonDeneme.Name = "button1";
this.buttonDeneme.Size = new System.Drawing.Size(122, 23);
this.buttonDeneme.TabIndex = 0;
this.buttonDeneme.Text = "FileUpload";
this.buttonDeneme.UseVisualStyleBackColor = true;
this.buttonDeneme.Click += ????
#dotTutorial answer is going to work but lot's people still have difficulty with Linq and Lambda expression so if you don't understand it the very basic way to write this is :
this.buttonDeneme.Click += new EventHandler(MyCustomClickHandler);
void MyCustomClickHandler(object sender, EventArgs e)
{
// do whatever you want here
}
but creating multiple button is usually because they wont do the same exact thing so you might want to set the this.buttonDeneme.Tag to some sort of identifier. i prefer using string in there.
then in the click event you can retrieve that value and know what to do. here a corrected version with the Tag used :
this.buttonDeneme.Tag = "SearchBook";
this.buttonDeneme.Click += new EventHandler(MyCustomClickHandler);
void MyCustomClickHandler(object sender, EventArgs e)
{
// for button created above the value when
// the click is called will be "SearchBook"
string sTag = ((Button)sender).Tag.ToString();
if(sTag == "SearchBook")
{
// do stuff for search book
}
else if(sTag == "blablabla")
{
// do other stuff
}
}
The easiest alternative would be to use a lambda expression.
this.buttonDeneme.Click += ((s, e) => {
// The code that handles a click event
});
's' will be the sender object and 'e' the eventargs.

Remove a ScreenSpaceLines3D Object from a ViewPort?

I am making a 3D Game with WPF in VB, and I am using a ScrennSpaceLines3D Object I found
http://3dtools.codeplex.com/releases/view/2058
but when I try to remove a line I added to the viewport by using
mainViewport.Children.RemoveAt(i)
it gives a NullExceptionError. I have read that this is because it does not totally come off the rendering queue. There have been fixes for c#, but I have yet to find one that works with VB. Is there a way to make this work or possibly draw a line in 3D space some other way? I find it quite ridiculous that VB doesn't even have a way to easily draw 3D lines...
Remove ScreenSpaceLines3D :
foreach (ScreenSpaceLines3D line3D in lines3DList)
{
lines3D.Points.Clear(); // Very importante
_viewport3D.Children.Remove(lines3D);
}
I'm a bit late to the party but i'm having the same issues.
The access violation occurs because each instance registers an event handler to the Rendering event of the composition target
public ScreenSpaceLines3D()
{
...
CompositionTarget.Rendering += OnRender; // <-- this line
}
but forgets to remove it when the instance is removed from the scene.
So to fix this you need to touch the source code:
public ScreenSpaceLines3D()
{
...
// event registration removed
}
private bool AttachedToCompositionTargetRendering { get; set; }
protected override void OnVisualParentChanged(DependencyObject oldParent)
{
base.OnVisualParentChanged(oldParent);
var parent = VisualTreeHelper.GetParent(this);
if (parent == null)
{
if (AttachedToCompositionTargetRendering)
{
CompositionTarget.Rendering -= OnRender;
AttachedToCompositionTargetRendering = false;
}
}
else
{
if (!AttachedToCompositionTargetRendering)
{
CompositionTarget.Rendering += OnRender;
AttachedToCompositionTargetRendering = true;
}
}
}

Releasing mouse capture and letting mouse click pass through

I have a control that is similar to a Popup or Menu. I want to display it and when the user clicks outside the bounds of the box, have it hide itself. I've used Mouse.Capture(this, CaptureMode.SubTree) as well as re-acquired the capture the same way Menu/Popup do in OnLostMouseCapture.
When the user clicks outside the bounds of the control, I release the mouse capture in OnPreviewMouseDown. I don't set e.Handled to true. The mouse click will make it to other controls on the main UI, but not to the close button (Red X) for the window. It requires 2 clicks to close the app.
Is there a way to tell WPF to restart the mouse click, or to send a repeated mouse click event?
Here's my code. Note I renamed it to MainMenuControl - I'm not building a Menu, so Menu/MenuItem and Popup aren't options.
public class MainMenuControl : Control
{
static MainMenuControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MainMenuControl), new FrameworkPropertyMetadata(typeof(MainMenuControl)));
}
public MainMenuControl()
{
this.Loaded += new RoutedEventHandler(MainMenuControl_Loaded);
Mouse.AddPreviewMouseDownOutsideCapturedElementHandler(this, OnPreviewMouseDownOutsideCapturedElementHandler);
}
void MainMenuControl_Loaded(object sender, RoutedEventArgs e)
{
this.IsVisibleChanged += new DependencyPropertyChangedEventHandler(MainMenuControl_IsVisibleChanged);
}
void MainMenuControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.IsVisible)
{
Mouse.Capture(this, CaptureMode.SubTree);
Debug.WriteLine("Mouse.Capture");
}
}
// I was doing this in OnPreviewMouseDown, but changing to this didn't have any effect
private void OnPreviewMouseDownOutsideCapturedElementHandler(object sender, MouseButtonEventArgs e)
{
Debug.WriteLine("OnPreviewMouseDownOutsideCapturedElementHandler");
if (!this.IsMouseInBounds())
{
if (Mouse.Captured == this)
{
Mouse.Capture(this, CaptureMode.None);
Debug.WriteLine("Mouse.Capture released");
}
Debug.WriteLine("Close Menu");
}
}
protected override void OnLostMouseCapture(MouseEventArgs e)
{
base.OnLostMouseCapture(e);
Debug.WriteLine("OnLostMouseCapture");
MainMenuControl reference = e.Source as MainMenuControl;
if (Mouse.Captured != reference)
{
if (e.OriginalSource == reference)
{
if ((Mouse.Captured == null) || (!reference.IsAncestorOf(Mouse.Captured as DependencyObject)))
{
//TODO: Close
Debug.WriteLine("Close Menu");
}
}
// if a child caused use to lose the capture, then recapture.
else if (reference.IsAncestorOf(e.OriginalSource as DependencyObject))
{
if (Mouse.Captured == null)
{
Mouse.Capture(reference, CaptureMode.SubTree);
Debug.WriteLine("Mouse.Capture");
e.Handled = true;
}
}
else
{
//TODO: Close
Debug.WriteLine("Close Menu");
}
}
}
private bool IsMouseInBounds()
{
Point point = Mouse.GetPosition(this);
Rect bounds = new Rect(0, 0, this.Width, this.Height);
return bounds.Contains(point);
}
}
The problem is that the mouse handling you are talking about is outside the WPF eventing system and part of the operating system so we're really talking about two fairly different mouse message queues that interact well enough most of the time but in these edge case we see that the interoperability is not perfect.
You could try to generate Win32 mouse messages or send your own window a close message but all those approaches are hacks. Since popups and menus exhibit exactly the same symptoms you describe, it doesn't seem like there is going to be an easy to way to accomplish what you want as you've described it.
Instead, I suggest that you consider giving up the mouse capture when the mouse leaves the north client area of the window or some other heuristic such as a specified distance from the control. I know this is probably not ideal but it might be a satisfactory compromise if you want the close button to work badly enough.

MainWindow.Closing event not always raised in Silverlight 4 OOB app

I've made a rather complex Silverlight 4 out-of-browser application. One of my main view models adds an event handler to the Application.Current.MainWindow.Closing event.
This works fine when the application is initially run. It is able to cancel the close operation.
However, sometimes after performing operations like showing and closing a ChildWindow, the MainWindow's Closing event is no longer calling my handler.
In the debugger, I added a watch to the MainWindow's underlying closing event delegate. It's not null before showing the ChildWindow. Then sometimes after the ChildWindow is closed the delegate is null. This is explains why my handler is not called any more. But why is this delegate getting nulled? And why is it only happening occasionally?
My application is not unbinding my event handler at any point.
This is the delegate I'm watching:
System.Windows.Application.Current.MainWindow.m_closingEvent
Other stuff: I'm using Caliburn Micro
I had the exact same problem. We have a large silverlight application running OOB.
For some reason the m_ClosingEvent was nulled after running for a while. I have not been able to find the cause of this issue but I think it may have something to do with us changing the root visual or all the child windows we show.
I´m using a class ApplicationWrapper.
public class ApplicationWrapper : IApplicationWrapper
{
public void Initialize()
{
HookCloseEvent(true);
}
private void HookCloseEvent(bool hook)
{
if (hook && IsRunningOutOfBrowser)
{
Application.Current.MainWindow.Closing += OnClosing;
}
else
{
if (IsRunningOutOfBrowser)
{
Application.Current.MainWindow.Closing -= OnClosing;
}
}
}
private void OnClosing(object sender, ClosingEventArgs e)
{
InvokeClosing(e);
}
... etc..
}
And the InvokeClosing method was never called. But when I changed it to
public class ApplicationWrapper : IApplicationWrapper
{
private Window _mainWindow;
public void Initialize()
{
if(IsRunningOutOfBrowser)
{
_mainWindow = Application.Current.MainWindow;
}
HookCloseEvent(true);
}
private void HookCloseEvent(bool hook)
{
if (hook && IsRunningOutOfBrowser)
{
_mainWindow.Closing += OnClosing;
}
else
{
if (IsRunningOutOfBrowser)
{
_mainWindow.Closing -= OnClosing;
}
}
}
private void OnClosing(object sender, ClosingEventArgs e)
{
InvokeClosing(e);
}
... etc...
}
The m_ClosingEvent isn´t nulled.
So, try to just store the "initial" MainWindow in a field and check if that solves your problem.
Instead of hooking to the event, why not register a service instead? Create a class that implements IApplicationService and IApplicationLifetimeAware. The latter gives you an "onexiting" and "onexited" pair of events. You place the service in the application by pointing to it in a section called in your App.xaml. I've used this for many projects and never had an issue with the exiting methods not being called.
Ok, after pulling out my hair and many false starts I finally found the answer - it seems to be a known bug with the Closing event, OOB and ChildWindows open/closes...
The trick is to store a static reference to the Main Window:
public MainPage()
{
InitializeComponent();
Loaded += MainPage_Loaded;
}
private void MainPage_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
//you have to store this to work around the bug
//http://forums.silverlight.net/forums/p/185664/424174.aspx
_mainWindow = App.GetApp.MainWindow;
App.GetApp.MainWindow.Closing += (s, e1) =>
{
if (UIUtilities.ShowMessage("Would you like to exit AMT Mobile?", "Exit Application", MessageBoxButton.OKCancel) != MessageBoxResult.OK)
{
e1.Cancel = true;
}
};
}

Resources