First, regarding the question about printing, here are several suggested links from
MSDN about .NET Framework support for printing:
An example of how to print the graph with PrintDocument would be to add a PrintDocument component to your form, double click on the PrintDocument to generate an event for the PrintPage event, then do something like this (assuming you have a WaveformGraph or ScatterGraph called graph):
private void OnPrintDocumentPrintPage(object sender, PrintPageEventArgs e)
{
Rectangle bounds = new Rectangle(e.MarginBounds.Location, graph.Size);
ComponentDrawArgs args = new ComponentDrawArgs(e.Graphics, bounds);
graph.Draw(args);
}
When you're ready to print, call the Print method on the PrintDocument.
Regarding the ability to enable an interaction mode without keyboard modifiers, there is not a direct way to do this. The advantage of the keyboard modifiers is that it allows you to have multiple modes enabled at the same time and a way to easily switch between them interactively, but the disadvantage is that there's not an easy way to toggle them via toolbars as you're trying to do. This is good feedback and I will file a suggestion to consider this for a future release.
There is a way to workaround this by synthesizing the keystrokes for the interaction keyboard modifiers, though. Below is a helper class called AutoInteractionMode that will work with either WaveformGraph or ScatterGraph. To use it in your project, create a class member variable for the AutoInteractionMode, then initialize it in your constructor after the InitializeComponent call, like this:
public class MyForm : Form
{
private AutoInteractionMode _autoInteraction;
// This could be a ScatterGraph as well.
private NationalInstruments.UI.WindowsForms.WaveformGraph waveformGraph1;
// ...
public MyForm()
{
InitializeComponent();
_autoInteraction = new AutoInteractionMode(waveformGraph1);
}
}
Once this is hooked up, you can set the InteractionMode property to correspond to the modes that you're toggling via the toolbars, and the AutoInteractionMode should do the right thing when the mouse enters the plot area without the use of the keyboard modifier. Hope this helps.
- Elton
class AutoInteractionMode
{
private bool _mouseInPlotArea;
private bool _enabled;
private XYGraph _graph;
private const GraphInteractionModes PanMask = GraphInteractionModes.PanX | GraphInteractionModes.PanY;
private const GraphInteractionModes ZoomMask = GraphInteractionModes.ZoomAroundPoint | GraphInteractionModes.ZoomX | GraphInteractionModes.ZoomY;
public AutoInteractionMode(XYGraph graph)
{
if (graph == null)
throw new ArgumentNullException("graph");
_mouseInPlotArea = false;
_enabled = false;
_graph = graph;
Enabled = true;
}
public bool Enabled
{
get
{
return _enabled;
}
set
{
if (value && !_enabled)
_graph.MouseMove += new MouseEventHandler(OnGraphMouseMove);
else if (!value && _enabled)
_graph.MouseMove -= new MouseEventHandler(OnGraphMouseMove);
_enabled = value;
}
}
[StructLayout(LayoutKind.Sequential)]
private struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public int dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
private struct KEYBDINPUT
{
public short wVk;
public short wScan;
public int dwFlags;
public int time;
public int dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
private struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
}
[StructLayout(LayoutKind.Explicit)]
private struct INPUT
{
[FieldOffset(0)] public int type;
[FieldOffset(4)] public MOUSEINPUT mi;
[FieldOffset(4)] public KEYBDINPUT ki;
[FieldOffset(4)] public HARDWAREINPUT hi;
}
private const int INPUT_KEYBOARD = 1;
private const int KEYEVENTF_EXTENDEDKEY = 0x0001;
private const int KEYEVENTF_KEYUP = 0x0002;
private const int KEYEVENTF_UNICODE = 0x0004;
private const int KEYEVENTF_SCANCODE = 0x0008;
[DllImport("user32.dll")]
private static extern uint MapVirtualKey(uint uCode, uint uMapType);
[DllImport("user32.dll")]
private static extern uint SendInput(uint nInputs, [In] INPUT[] pInputs, int cbSize);
private static void SendKeyUp(Keys key)
{
Send(key, true);
}
private static void SendKeyDown(Keys key)
{
Send(key, false);
}
private static void Send(Keys key, bool keyUp)
{
INPUT[] input = new INPUT[1];
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = (short)key;
input[0].ki.wScan = ((short)MapVirtualKey((uint)key, 0));
input[0].ki.dwFlags = ((IsExtendedKey(key) ? KEYEVENTF_EXTENDEDKEY : 0) | (keyUp ? KEYEVENTF_KEYUP : 0));
input[0].ki.time = 0;
input[0].ki.dwExtraInfo = 0;
SendInput(1, input, Marshal.SizeOf(typeof(INPUT)));
}
private static bool IsExtendedKey(Keys key)
{
return (((key < Keys.Space) || (key > Keys.F15)) && ((key != Keys.Tab) && (key != Keys.Enter) && (key != Keys.LineFeed)));
}
private void OnGraphMouseMove(object sender, MouseEventArgs e)
{
Point pt = new Point(e.X, e.Y);
if (_graph.PlotAreaBounds.Contains(pt))
{
if (!_mouseInPlotArea)
{
_mouseInPlotArea = true;
if ((_graph.InteractionMode & ZoomMask) > 0)
SendKeyDown(Keys.ShiftKey);
else if ((_graph.InteractionMode & PanMask) > 0)
SendKeyDown(Keys.ControlKey);
}
}
else
{
if (_mouseInPlotArea)
{
_mouseInPlotArea = false;
if ((_graph.InteractionMode & ZoomMask) > 0)
SendKeyUp(Keys.ShiftKey);
else if ((_graph.InteractionMode & PanMask) > 0)
SendKeyUp(Keys.ControlKey);
}
}
}
}