I've got a little problem and tried to solve it now for nearly 6 to 8 hours but I didn't find any matching answer. I'm a complete newbie to WPF, so please point me any errors I made.
At first I have the following in my App.xaml.cs:
namespace WpfVideowand
{
public partial class App : Application
{
...
private void Application_Startup(object sender, StartupEventArgs e)
{
foreach (System.Windows.Forms.Screen MyScreen in System.Windows.Forms.Screen.AllScreens)
{
List<string> MyStrings = Xml.GetScreens(i);
if (MyStrings[1] == "true")
{
OpenWindow(MyScreen, MyStrings[0], i);
}
i++;
Shelf MyShelf = new Shelf(MyScreen, i, MyStrings[0]);
MyShelf.Show();
}
}
private void OpenWindow(System.Windows.Forms.Screen myScreen, string configName, int screenNumber)
{
Shelf NewShelf = new Shelf(myScreen, screenNumber, configName);
}
}
}
And inside the Shelf.xaml.cs it looks this way:
namespace WpfVideowand
{
public partial class Shelf : Window
{
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
System.Windows.Forms.Screen _Screen { get; set; }
...
public Shelf(System.Windows.Forms.Screen myScreen, int screenNumber, string configName)
{
InitializeComponent();
_Screen = myScreen;
ShowOnMonitor(screenNumber);
...
}
private void ShowOnMonitor(int screenNumber)
{
System.Windows.Forms.Screen[] ScreenArray;
ScreenArray = System.Windows.Forms.Screen.AllScreens;
int XCoord = Convert.ToInt32(ScreenArray[screenNumber].Bounds.Left);
this.Left = XCoord;
int YCoord = Convert.ToInt32(ScreenArray[screenNumber].Bounds.Top);
this.Top = XCoord;
IntPtr active = GetActiveWindow();
System.Windows.Application.Current.Windows.OfType<Window>().SingleOrDefault(window => new WindowInteropHelper(window).Handle == active).Name = "Monitor" + screenNumber.ToString();
System.Windows.Application.Current.Windows.OfType<Window>().SingleOrDefault(window => new WindowInteropHelper(window).Handle == active).WindowState = WindowState.Maximized;
}
...
}
}
The way described above worked fine in Windows Forms Application. In WPF I have the problem, that I get the error message, that rectangle (the window) would have no Top or Left property.
I even tried it in some other ways, like creating with
System.Windows.Forms.Screen _screen = System.Windows.Forms.Screen.FromControl(this);
an object, that would have .Top and .Left. But there I get the message, that I cannot convert a Shelf-object into a System.Windows.Forms.Control.
Anyone a suggestion, how I could make my Screens appear on the monitor where it should be?
Ok, I found it myself...
For anyone who is interested in finding some answers to this problem here it is:
At first, see that you have the correct reference implemented. For this you need System.Drawing and System.Windows.Forms. (Afterwards you have to declare many things explicit, like System.Windows.Controls.Button instead of Button, etc.)
Then see that you start the app with something like Startup="Application_Startup" and not an uri, because you want to start many forms and not only one.
Afterwards be absolutly sure to NOT set the Windowstyle to maximized in the XAML (this did cost me nearly 4 hours. In between i grew 56 grey hairs). Use this in the Code-Behind:
System.Windows.Application.Current.Windows.OfType().SingleOrDefault(window => new WindowInteropHelper(window).Handle == active).WindowState = WindowState.Maximized;
Related
I have the following issue:
I have window with two textboxes. When I click in a textbox and then click anywhere else (even outside the window), the mouse click position should be written into the textbox.
I found the MouseKeyHook library, in which a demo shows how the mouse position is updated in a windows form. But I did not manage to apply the code to my problem yet. I don't even know where I should write the code found in the demo.
What I came up with so far is the following:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace LineClicker
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void StarttextBox_GotFocus(object sender, RoutedEventArgs e)
{
Mouse.Capture(StarttextBox);
StarttextBox.Text = string.Format(" x {0} , y {1}", PointToScreen(Mouse.GetPosition(this)).X, PointToScreen(Mouse.GetPosition(this)).Y);
}
}
}
This is the code for one textBox. When I click in it, x and y coordinates are displayed. They are not absolute, I think this is due to the parameter this in the GetPosition method. What do I have to choose instead of this?
Another thing is that the position is not updated always. When I move the mouse to the lower right corner of my desktop and then activate the textbox by tabbing into it, the position doesn't get updated.
What are the steps to do here?
I was able to achieve this result using Cursor.Position:
A Point that represents the cursor's position in screen coordinates.
Example
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void textBox_GotFocus(object sender, RoutedEventArgs e)
{
var postion = System.Windows.Forms.Cursor.Position;
textBox.Text = string.Format($"{postion.X}, {postion.Y}");
}
}
}
You can see from the the Microsoft reference source that Cursor.Position is defined as:
public static Point Position {
get {
NativeMethods.POINT p = new NativeMethods.POINT();
UnsafeNativeMethods.GetCursorPos(p);
return new Point(p.x, p.y);
}
set {
IntSecurity.AdjustCursorPosition.Demand();
UnsafeNativeMethods.SetCursorPos(value.X, value.Y);
}
}
So just like in yan yankelevich's answer, it still uses SetCursorPos, but this way it is easier to call.
Apart from that it probably just depends on whether or not you are happy to include the reference to System.Windows.Forms.
First you will need to get the absolute mouse position (not relative to your window or your controls). To do this you need one of these options (from here : https://stackoverflow.com/a/4232281/4664754) :
By adding a reference to System.Windows.Forms in your project ( go in References in your solution explorer -> Right Click -> Add a Reference -> Assemblys-> Framework -> Tick the box near System.Windows.Forms).
Then add this static funtcion in some class (let's call it MouseHelper.cs) :
public static Point GetMousePositionWindowsForms()
{
System.Drawing.Point point = Control.MousePosition;
return new Point(point.X, point.Y);
}
By pasting this code in your MainWindow.xaml.cs:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetCursorPos(ref Win32Point pt);
[StructLayout(LayoutKind.Sequential)]
internal struct Win32Point
{
public Int32 X;
public Int32 Y;
};
public static Point GetMousePosition()
{
Win32Point w32Mouse = new Win32Point();
GetCursorPos(ref w32Mouse);
return new Point(w32Mouse.X, w32Mouse.Y);
}
Whatever the way you choose you will need to call one of those functions in your OnFocusChanged this way :
private void StarttextBox_GotFocus(object sender, RoutedEventArgs e)
{
Mouse.Capture(StarttextBox);
Point mouseCoord = MouseHelper.GetMousePositionWindowsForms();
// Or if you choose the other way :
//Point mouseCoord = GetMousePosition();
StarttextBox.Text = string.Format(" x {0} , y {1}", mouseCoord.X, mouseCoord .Y);
}
This way the coordinates should be correct.
For your problem of coordinates not displaying at the right time, i think your focus solution is not what you are looking for.
You should try to implement something like this : https://stackoverflow.com/a/2064009/4664754 and change your textboxes values every time the TheMouseMoved event is called
I've been reading and following up on how to write a BHO in IE using C# and I can register it just fine and run it but it only works properly when in the first window\tab I've got open.
I know aspects of it are triggering in every new window but the changes don't "stick" or apply if they're affecting the DOM. So, for example, I load a page that displays some text in the top of the page, it will always be there in the first tab but all the others it may be there are first then disappear or not show up at all.
I'm using c# 4 on Win7x64 using IE11. Protected mode doesn't appear to affect this one way or the other.
My code is just a mix of what's up here tutorial wise, so nothing fancy.
namespace IEExtention
{
[
ComVisible(true),
Guid("e8483cfd-d208-45f7-837c-3cdca573d84a"),
ClassInterface(ClassInterfaceType.None)
]
public class BHO : IObjectWithSite
{
private WebBrowser webBrowser;
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private object mySite;
public int SetSite(object site)
{
if (site != null)
{
mySite = site;
webBrowser = (WebBrowser)site;
webBrowser.DocumentComplete +=
new DWebBrowserEvents2_DocumentCompleteEventHandler(
this.OnDocumentComplete);
}
else
{
webBrowser.DocumentComplete -=
new DWebBrowserEvents2_DocumentCompleteEventHandler(
this.OnDocumentComplete);
webBrowser = null;
}
return 0;
}
public int GetSite(ref Guid guid, out IntPtr ppvSite)
{
IntPtr punk = Marshal.GetIUnknownForObject(webBrowser);
int hr = Marshal.QueryInterface(punk, ref guid, out ppvSite);
Marshal.Release(punk);
return hr;
}
public void OnDocumentComplete(object pDisp, ref object URL)
{
log.Debug("test");
if (pDisp != mySite)
{
return;
}
HTMLDocument document = (HTMLDocument)this.webBrowser.Document;
document.title = "Hello, StackOverflow!";
try
{
IHTMLDOMNode greetings = document.createTextNode("Hi there!");
IHTMLDOMNode body = document.body as IHTMLDOMNode;
body.insertBefore(greetings, body.firstChild);
}
catch (Exception e)
{
//whoo!!
}
}
It's had me stumped for a few days as even something as changing the document.title doesn't always stay.
I was able to work around this issue by threading my BHO and sleeping it for about half a second. Interestingly enough I needed to up the sleep to about 1.5 seconds to deal with outside links (say something coming from outlook) to load up and get everything to display.
I'm not sure if this is the best way to do it but it solved my problem with it only working in the first tab.
I'm trying to write an application that senses when someone taps and holds something. I am using windows forms. I tried using the mouse down even but it doesn't appear to fire all the time. This is also going to be a multi touch application. I'm going to have two buttons , and the user can tap and hold one button, while they press on the other button. Or Just press one button. I'm not even sure how a windows form app can handle that.
All the examples inhave seen for a windows touch app use xaml. Is this really the only way to capture tap and hold ??
I'm essentially making an onscreen keyboard here, and I don't think that isnpossible WITHOUT windows forms. Correct me if I am wrong here.
Any help or guidance in this is greatly appreciated. Thanks.
If your program is running on Windows 8, you can use the WM_POINTER API to get the input you need. Override WndProc to capture the messages. You will have to do some P/Invoke to get it working, but it's not terribly hard. Here's some incomplete code to get you started, you'll need to add cases for up, down, and update events for each type of pointer you want to track. Keep track of the pointer IDs to process multi touch. To handle the press-and-hold you'll need to track the time yourself from WM_POINTERDOWN to WM_POINTERUP and act accordingly. Hope this helps.
public const int WM_POINTERDOWN = 0x0246;
public const int WM_POINTERUP = 0x0247;
public const int WM_POINTERUPDATE = 0x0245;
public enum POINTER_INPUT_TYPE : int
{
PT_POINTER = 0x00000001,
PT_TOUCH = 0x00000002,
PT_PEN = 0x00000003,
PT_MOUSE = 0x00000004
}
public static uint GET_POINTERID_WPARAM(uint wParam) { return wParam & 0xFFFF; }
[DllImport("User32.dll")]
public static extern bool GetPointerType(uint pPointerID, out POINTER_INPUT_TYPE pPointerType);
protected override void WndProc(ref Message m)
{
bool handled = false;
uint pointerID;
POINTER_INPUT_TYPE pointerType;
switch(m.Message)
{
case WM_POINTERDOWN:
pointerID = User32.GET_POINTERID_WPARAM((uint)m.WParam);
if (User32.GetPointerType(pointerID, out pointerType))
{
switch (pointerType)
{
case POINTER_INPUT_TYPE.PT_PEN:
// Stylus Down
handled = true;
break;
case POINTER_INPUT_TYPE.PT_TOUCH:
// Touch down
handled = true;
break;
}
}
break;
}
if (handled)
m.Result = (IntPtr)1;
base.WndProc(ref m);
}
This question has been around for a while and might benefit from a simple approach. You can simulate the "tap and hold" (or click and hold) by measuring the time between the MouseDown event and the Click event (which fires before MouseUp). If the time is greater than some value then you cancel the Click and (perhaps) fire your own TapAndHold event. I have created a test control that anyone can use to try this approach out. Just add a UserControl to your test app (I called mine TestTapAndHold) and then paste in the following:
public partial class TestTapAndHold : UserControl
{
private string showText = "Tap Me";
private DateTime mouseDown;
private const int holdTime = 500;
public TestTapAndHold()
{
InitializeComponent();
this.Paint += drawText;
}
public delegate void OnTapAndHold(EventArgs e);
public event OnTapAndHold TapAndHold;
private void drawText(object sender, PaintEventArgs e)
{
using (var drawBrush = new SolidBrush(Color.Black))
{
e.Graphics.DrawString(showText, Font, drawBrush, new Point(5,3));
}
}
protected override void OnClick(EventArgs e)
{
if (DateTime.Now.Subtract(mouseDown).Milliseconds >= holdTime)
{
showText = "Tap Hold";
TapAndHold?.Invoke(e);
} else
{
base.OnClick(e);
showText = "Tapped";
}
Invalidate();
}
private void TestTapAndHold_MouseDown(object sender, MouseEventArgs e)
{
mouseDown = DateTime.Now;
}
}
Build the app and then pop one of the test controls onto a form. You can then add an event handler to your form like:
private void testTapAndHold1_TapAndHold(EventArgs e)
{
MessageBox.Show("You tapped and Held");
}
This general approach enabled me to add "Tap and Hold" functionality to a Windows Forms app running on a Microsoft Surface 4
I have a WPF application that will show information on a projector through a dedicated window.
I would like to configure what screen to be used for projector display and what to be used for main application window.
This code will generate projector output on specified screen:
var screen = GetProjectorScreen();
_projectorWindow = new ProjectorWindow();
_projectorWindow.Left = screen.WorkingArea.Left;
_projectorWindow.Top = screen.WorkingArea.Top;
_projectorWindow.Owner = _parentWindow;
_projectorWindow.Show();
public static Screen GetProjectorScreen()
{
var screens = Screen.AllScreens;
if (screens.Length > 1 && Settings.Default.DisplayScreen < screens.Length)
{
return screens[Settings.Default.DisplayScreen];
}
return screens[0];
}
I have tried to do the same trick with startup form, but so far without success.
I tried to set Top and Left properties in MainWindow constructor but that did not work.
The startup window is launched from App.xaml.cs by setting StartupUri:
StartupUri = new Uri("Windows/MainWindow.xaml", UriKind.Relative);
Is there any other way to launch startup form?
I tried to just call the constructor but that causes a crash because some resources are no longer loaded.
I got it working. It is necessary to set WindowState to Normal before setting window location. And the setting will not work at all until the window is created, i.e. after constructor call. I therefore call the explicit setting in Windows_Loaded event. That might cause a flickering if window need to be moved, but that is acceptable to me.
The SetScreen method should also be called after screen settings have changed manually by user.
private void SetScreen()
{
var mainScreen = ScreenHandler.GetMainScreen();
var currentScreen = ScreenHandler.GetCurrentScreen(this);
if (mainScreen.DeviceName != currentScreen.DeviceName)
{
this.WindowState = WindowState.Normal;
this.Left = mainScreen.WorkingArea.Left;
this.Top = mainScreen.WorkingArea.Top;
this.Width = mainScreen.WorkingArea.Width;
this.Height = mainScreen.WorkingArea.Height;
this.WindowState = WindowState.Maximized;
}
}
The backup ScreenHandler utility is very simple:
public static class ScreenHandler
{
public static Screen GetMainScreen()
{
return GetScreen(Settings.Default.MainScreenId);
}
public static Screen GetProjectorScreen()
{
return GetScreen(Settings.Default.ProjectorScreenId);
}
public static Screen GetCurrentScreen(Window window)
{
var parentArea = new Rectangle((int)window.Left, (int)window.Top, (int)window.Width, (int)window.Height);
return Screen.FromRectangle(parentArea);
}
private static Screen GetScreen(int requestedScreen)
{
var screens = Screen.AllScreens;
var mainScreen = 0;
if (screens.Length > 1 && mainScreen < screens.Length)
{
return screens[requestedScreen];
}
return screens[0];
}
}
The accepted answer no longer works on Windows 10 with per-monitor DPI in the app’s manifest.
Here’s what worked for me:
public partial class MyWindow : Window
{
readonly Rectangle screenRectangle;
public MyWindow( System.Windows.Forms.Screen screen )
{
screenRectangle = screen.WorkingArea;
InitializeComponent();
}
[DllImport( "user32.dll", SetLastError = true )]
static extern bool MoveWindow( IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint );
protected override void OnSourceInitialized( EventArgs e )
{
base.OnSourceInitialized( e );
var wih = new WindowInteropHelper( this );
IntPtr hWnd = wih.Handle;
MoveWindow( hWnd, screenRectangle.Left, screenRectangle.Top, screenRectangle.Width, screenRectangle.Height, false );
}
void Window_Loaded( object sender, RoutedEventArgs e )
{
WindowState = WindowState.Maximized;
}
}
Just setting Left/Top doesn’t work. Based on my tests, per-monitor DPI awareness only kicks in after window is already created and placed on some monitor. Before that, apparently Left/Top properties of the window scale with DPI of the primary monitor.
For some combinations of per-monitor DPI and monitors layout, this caused a bug where setting Left/Top properties to the pixels values of System.Windows.Forms.Screen rectangle caused the window to be positioned somewhere else.
The above workaround is only suitable for maximizing, it does not always sets the correct size of the window. But at least it sets correct top-left corner which is enough for the maximize to work correctly.
Any advice or links or sample application (for VS2010) re how to develop a "windowless" WPF application?
That is the ones that look quite modern and don't seem to have the historical window chrome around the edges - they seem to have rounded edges etc...
I wrote a project that did exactly what you are talking about, we used the following project from Microsoft,
http://code.msdn.microsoft.com/WPFShell
Initially I tried writing it myself by turning off the chrome, not a good idea unless you don't want to be able to drag your window around in the standard windows method.
Just remove StartupUri and in the Application Startup method dont load a window:
public partial class App
{
public static bool IsTrue ;
public App()
{
Startup += AppStartup;
}
public void DoWork()
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(1000);
Trace.WriteLine("blah");
}
IsTrue = false;
}
void AppStartup(object sender, StartupEventArgs e)
{
IsTrue = true;
new Thread(DoWork).Start();
while (IsTrue)
{ }
Current.Shutdown();
}
}
}