i'm trying to call AnimateWindow to animate the show and hide of a WinForms window.
Here's a copy of the win32 translation:
private static class NativeMethods
{
public const int AW_ACTIVATE = 0x20000;
public const int AW_HIDE = 0x10000;
public const int AW_BLEND = 0x80000;
public const int AW_CENTER = 0x00000010;
public const int AW_SLIDE = 0X40000;
public const int AW_HOR_POSITIVE = 0x1;
public const int AW_HOR_NEGATIVE = 0X2;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int AnimateWindow(IntPtr hwand, int dwTime, int dwFlags);
}
But the problem is how to fit a call to AnimateWindow into the) WinForms scheme. One person suggests OnLoad:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
AnimateWindow(this.Handle, 200, AW_ACTIVATE | AW_HOR_NEGATIVE | AW_SLIDE);
}
and OnClosing:
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
base.OnClosing(e);
if (e.Cancel == false)
{
AnimateWindow(this.Handle, 200, AW_HIDE | AW_HOR_POSITIVE | AW_SLIDE);
}
}
Except that it doesn't work.
the form doesn't use any animation while appearing
during hide the form animates its horizontal slide off the screen, then reappears, before hiding the normal way
What is the correct way to mix AnimateWindow with WinForms?
See also
.NET AnimateWindow: this guy asked the same question. But since it was trying to achieve something else, people solved his problem rather than answering his question.
C# WinForms AnimateWindow issue: This guy was interested in using AnimateWindow with child controls, rather than a top-level window.
Bonus Chatter
i was perusing through the Form -> Show -> Visible -> SetVisibleCore, when i discovered this bug:
protected virtual void SetVisibleCore(bool value)
{
try
{
HandleCollector.SuspendCollect();
//...snip...
}
finally
{
HandleCollector.ResumeCollect();
}
}
Nice to know that everyone can introduce these subtle errors.
I think AnimateWindow has it's limitations to work properly. For example, it doesn't play well with Aero, so to animate a sliding form, you would need to set the BorderStyle to None. Also, make sure the StartPosition is set to Manual.
Simple example:
public partial class Form1 : Form {
public const int AW_ACTIVATE = 0x20000;
public const int AW_HIDE = 0x10000;
public const int AW_BLEND = 0x80000;
public const int AW_CENTER = 0x00000010;
public const int AW_SLIDE = 0X40000;
public const int AW_HOR_POSITIVE = 0x1;
public const int AW_HOR_NEGATIVE = 0X2;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int AnimateWindow(IntPtr hwand, int dwTime, int dwFlags);
public Form1() {
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) {
Form toastForm = new Form();
toastForm.ShowInTaskbar = false;
toastForm.StartPosition = FormStartPosition.Manual;
toastForm.FormBorderStyle = FormBorderStyle.None;
toastForm.Size = new Size(256, 64);
toastForm.Location = new Point(Screen.PrimaryScreen.WorkingArea.Right - toastForm.Width,
Screen.PrimaryScreen.WorkingArea.Bottom - toastForm.Height);
Button closeButton = new Button();
closeButton.Text = "Close";
toastForm.Controls.Add(closeButton);
closeButton.Click += delegate { toastForm.Close(); };
AnimateWindow(toastForm.Handle, 200, AW_ACTIVATE | AW_HOR_NEGATIVE | AW_SLIDE);
toastForm.Show();
}
}
I'm not sure what your AnimateWindow call does, but when you need to change underlying native 'stuff' to do with windows forms, I've always used the CreateParams() override. You may
find a similar function for what you are trying to achieve.
Here's an example of a transparent tool window, that doesn't activate when it is shown.
Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
Get
Dim baseParams As Windows.Forms.CreateParams = MyBase.CreateParams
baseParams.ExStyle = baseParams.ExStyle Or NativeMethods.ExtendedWindowsStyles.WS_EX_LAYERED Or NativeMethods.ExtendedWindowsStyles.WS_EX_TRANSPARENT Or NativeMethods.ExtendedWindowsStyles.WS_EX_NOACTIVATE Or NativeMethods.ExtendedWindowsStyles.WS_EX_TOOLWINDOW
Return baseParams
End Get
End Property
Related
The user often moves my XAF Winforms app between monitors.
However dialogs invoked by the PopUpWindowShowAction remain on the old monitor
This issue can be repeated with Dev Express's Main Demo ( although to debug it there I think I would need to get into the API code).
Run Main Demo and move the application window to the second monitor.
Select Users, right click a user and select Print Preview.
The Print Preview will appear on the first monitor.
In my similar case, my controller is
public partial class JobHeadFilterController : ViewController, IClassicController
{
public JobHeadFilterController()
{
InitializeComponent();
TargetViewNesting = Nesting.Root;
}
protected override void OnActivated()
{
base.OnActivated();
popupWindowShowFilterAction.QuickAccess = true;
}
private void popupWindowShowFilterAction_CustomizePopupWindowParams(object sender,
CustomizePopupWindowParamsEventArgs e)
{
var holder = new JobHeadFilterHolder();
var npProvider = new NonPersistentObjectSpaceProvider(XafTypesInfo.Instance, null);
var os = (NonPersistentObjectSpace)npProvider.CreateObjectSpace();
var view = Application.CreateDetailView(os, holder);
e.View = view;
}
I have tried browsing the properties of CustomizePopupWindowParamsEventArgs but cant see what to set.
I can get the main form using
var mainform = Application.MainWindow.Template as Form;
I think I need to do something like the following inside popupWindowShowFilterAction_CustomizePopupWindowParams
var template = e.Application.MainWindow.Template;
var window = new Window(Application, ); // having trouble figuring out the parameters
e.DialogController.SetWindow(window);
Studying the docs
[Update]
I tried
var window = e.Application.MainWindow;
e.DialogController.SetWindow(window);
but got an error
The 'DevExpress.ExpressApp.SystemModule.DialogController' controller
is active.
I tried making my own dialog controller inheriting from the Dev DevExpress.ExpressApp.SystemModule.DialogController but got the same error.
using System;
using System.Windows.Forms;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Templates;
using DevExpress.ExpressApp.Win.Templates;
namespace MyNameSpace;
public partial class CustomizeFormsWindowController : WindowController
{
public CustomizeFormsWindowController()
{
InitializeComponent();
TargetWindowType = WindowType.Child;
}
protected override void OnActivated()
{
base.OnActivated();
Window.TemplateChanged += WindowsTemplateChanged;
}
private void WindowsTemplateChanged(object sender, EventArgs e)
{
if (Window.Template is Form &&
Window.Template is ISupportStoreSettings)
((ISupportStoreSettings)Window.Template).SettingsReloaded +=
OnFormReadyForCustomizations;
}
private void OnFormReadyForCustomizations(object sender, EventArgs e)
{
if (sender is not PopupForm popupForm) return;
var mainForm = Application.MainWindow.Template as Form;
var X = mainForm.Location.X + (mainForm.Width - popupForm.Width) / 2;
var Y = mainForm.Location.Y + (mainForm.Height - popupForm.Height) / 2;
popupForm.SetDesktopLocation(X, Y);
}
protected override void OnDeactivated()
{
Window.TemplateChanged -= WindowsTemplateChanged;
base.OnDeactivated();
}
}
I am using GMAPS in C# (Winforms) and I would like to add a marker with a label. I followed the answer at GMAP.NET adding labels underneath markers and noticed that there is an issue with the implementation. The markers are not plotted in the correct place and the labels are all plotted on top of each other. I think it is not correctly calling the OnRender method for the marker? Can anyone point me in the right direction?
In ran into the same issue and just calling base.OnRender(g); wasn't fixing it for me. The trick is to derive from GMarkerGoogle instead of GMapMarker as done in the answer you provided.
Also I had to do some tweaks with the text rendering. I came up with this solutions, works fine for me:
public class GmapMarkerWithLabel : GMarkerGoogle, ISerializable
{
private readonly Font _font;
private GMarkerGoogle _innerMarker;
private readonly string _caption;
public GmapMarkerWithLabel(PointLatLng p, string caption, GMarkerGoogleType type)
: base(p, type)
{
_font = new Font("Arial", 11);
_innerMarker = new GMarkerGoogle(p, type);
_caption = caption;
}
public override void OnRender(Graphics g)
{
base.OnRender(g);
var stringSize = g.MeasureString(_caption, _font);
var localPoint = new PointF(LocalPosition.X - stringSize.Width / 2, LocalPosition.Y + stringSize.Height);
g.DrawString(_caption, _font, Brushes.Black, localPoint);
}
public override void Dispose()
{
if (_innerMarker != null)
{
_innerMarker.Dispose();
_innerMarker = null;
}
base.Dispose();
}
#region ISerializable Members
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
GetObjectData(info, context);
}
protected GmapMarkerWithLabel(SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
#endregion
}
I need to use an OnScreenKeyboard Component like Native Windows OSK in my Wpf application. I can call the UI by Process.Start("osk.exe") but the UI appears on top of the main ui window. I want to start the OSK app just bottom of my app. Is this possible with any arguments? -e.g. process.StartInfo.WindowPosition=xxx- I'd prefer to use it before I create my own Component.
OK. I solved my problem with Win32 SetWindowPos method. Sharing if it might help others. Below code is opening and resizing/positioning the Native OSK.exe. It places the keyboard relative to the mouse position.
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
public static implicit operator Point(POINT point)
{
return new Point(point.X, point.Y);
}
}
[DllImport("user32.dll")]
public static extern bool GetCursorPos(out POINT lpPoint);
public static Point GetCursorPosition()
{
POINT lpPoint;
GetCursorPos(out lpPoint);
//bool success = User32.GetCursorPos(out lpPoint);
// if (!success)
return lpPoint;
}
private void OSKMenuItem_Click(object sender, RoutedEventArgs e)
{
Process osk = new Process();
osk.StartInfo.FileName = "osk.exe";
osk.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
osk.Start();
Task.Delay(1000).ContinueWith((a) => {
Point p = GetCursorPosition();
try
{
IntPtr target_hwnd = FindWindowByCaption(IntPtr.Zero, "On-Screen Keyboard");
if (target_hwnd == IntPtr.Zero)
{
Microsoft.Windows.Controls.MessageBox.Show("Error");
}
SetWindowPos(target_hwnd, IntPtr.Zero, (int)p.X - 200, (int)p.Y, 1300, 600, 0);
}
catch (Exception ex)
{
//throw;
}
});
It so happened that the application I'm working on doesn't operate on documents, so there's no need in displaying the recently opened documents list in the application menu.
But - annoyingly - there are no properties readily available in the RibbonApplicationMenu class to hide the unused AuxiliaryPane (for which, curiously, the property does exist, but is marked as "internal").
Of course, I can just leave it there - but that's... untidy.
So, here's the solution I came up with.
Hope it will be helpful for anyone else :-)
The general idea is to subclass the RibbonApplicationMenu, find the template child corresponding to the menu's Popup, and overrule its Width (after a number of frustrating experiments it became evident that doing that neither for PART_AuxiliaryPaneContentPresenter nor for PART_FooterPaneContentPresenter - nor for the both - could achieve anything).
Well, without further ado, here's the code:
public class SlimRibbonApplicationMenu : RibbonApplicationMenu
{
private const double DefaultPopupWidth = 180;
public double PopupWidth
{
get { return (double)GetValue(PopupWidthProperty); }
set { SetValue(PopupWidthProperty, value); }
}
public static readonly DependencyProperty PopupWidthProperty =
DependencyProperty.Register("PopupWidth", typeof(double),
typeof(SlimRibbonApplicationMenu), new UIPropertyMetadata(DefaultPopupWidth));
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.DropDownOpened +=
new System.EventHandler(SlimRibbonApplicationMenu_DropDownOpened);
}
void SlimRibbonApplicationMenu_DropDownOpened(object sender, System.EventArgs e)
{
DependencyObject popupObj = base.GetTemplateChild("PART_Popup");
Popup popupPanel = (Popup)popupObj;
popupPanel.Width = (double)GetValue(PopupWidthProperty);
}
}
As a side note, I tried to find any way to resolve the desired width based on the max width of the ApplicationMenu's Items (rather than setting it explicitly through the DependencyProperty in XAML) - but to no avail.
Given my despise to "magic numbers", any suggestion on that will be deeply appreciated.
I know this has been a while, but I've got another solution to this. This one does not provide the Popup width property, instead a ShowAuxilaryPanel boolean. It then goes to Bind the width of the Popup, to the width of the menu item area of the menu.
public class SlimRibbonApplicationMenu : RibbonApplicationMenu
{
public bool ShowAuxilaryPanel
{
get { return (bool)GetValue(ShowAuxilaryPanelProperty); }
set { SetValue(ShowAuxilaryPanelProperty, value); }
}
public static readonly DependencyProperty ShowAuxilaryPanelProperty =
DependencyProperty.Register("ShowAuxilaryPanel", typeof(bool),
typeof(SlimRibbonApplicationMenu), new UIPropertyMetadata(true));
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.DropDownOpened += SlimRibbonApplicationMenu_DropDownOpened;
}
void SlimRibbonApplicationMenu_DropDownOpened(object sender, EventArgs e)
{
DependencyObject popupObj = base.GetTemplateChild("PART_Popup");
Popup panel = (Popup)popupObj;
var exp = panel.GetBindingExpression(Popup.WidthProperty);
if (!this.ShowAuxilaryPanel && exp == null)
{
DependencyObject panelArea = base.GetTemplateChild("PART_SubMenuScrollViewer");
var panelBinding = new Binding("ActualWidth")
{
Source = panelArea,
Mode = BindingMode.OneWay
};
panel.SetBinding(Popup.WidthProperty, panelBinding);
}
else if (this.ShowAuxilaryPanel && exp != null)
{
BindingOperations.ClearBinding(panel, Popup.WidthProperty);
}
}
}
worked for me
<telerik:ApplicationMenu RightPaneVisibility="Collapsed" >
I am currently working on a little app that scrolls a message across the top of the form - nothing complex however i have ran into a issue where i can not get it to work with a toolstriplabel on my c# winform. I currently have it working by the following method using a normal label but toolstriplabels dont appear to have the .Left option i require to make it scroll. This is the code i am currently using in a timer.
private void timer1_Tick(object
sender, System.EventArgs e)
{
this.label1.Left = this.label1.Left - 1;
if (this.label1.Left + this.label1.Width < 0)
{
this.label1.Left = this.label1.Width;
}
}
Does anyone know how i can make this work with a toolstrip label as i would really like this scrolling text on a toolstrip so the user can drag it to where there require?
Thanks
How about something like this:
namespace WindowsFormsApplication7
{
public partial class Form1 : Form
{
string _labelText = "Hello out there!";
int _scrollOffset = 0;
public Form1()
{
InitializeComponent();
}
private void timer1_Tick( object sender, EventArgs e )
{
string textToDisplay = _labelText.Substring( _scrollOffset++ );
this.toolStripLabel1.Text = textToDisplay;
if ( _scrollOffset > _labelText.Length )
{
_scrollOffset = 0;
}
}
}
}