I am unable to disable ContextMenu, if I use WindowChrome.WindowChrome style.
Please let me know your input to resolve this problem.
Without WindowChrome i am able to disable context menu with same piece of code.
<Window x:Class="ConextMenu_Sample.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">
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="35"
CornerRadius="0"
ResizeBorderThickness="5"
UseAeroCaptionButtons="False" />
</WindowChrome.WindowChrome>
<Grid>
</Grid>
</Window>
Code behind
public partial class MainWindow : Window
{
private const uint WP_SYSTEMMENU = 0x02;
private const uint WM_SYSTEMMENU = 0xa4;
public MainWindow()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
IntPtr windIntPtr = new WindowInteropHelper(this).Handle;
HwndSource hwndSource = HwndSource.FromHwnd(windIntPtr);
hwndSource.AddHook(new HwndSourceHook(WndProc));
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
if ((msg == WM_SYSTEMMENU) && (wparam.ToInt32() == WP_SYSTEMMENU))
{
handled = true;
}
return IntPtr.Zero;
}
}
Perhaps you didn't need this,but I solved it and want to share it to someone need it.
if (((msg == WM_SYSTEMMENU) && (wParam.ToInt32() == WP_SYSTEMMENU)) || msg == 165){
//ShowContextMenu();
handled = true;
}
Use this Code:
U need to set the windowstyle property None.
Property:- WindowStyle = "None"
<Window x:Class="ConextMenu_Sample.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" WindowStyle="None">
[OR]
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
if ((msg == WM_SYSTEMMENU) && (wparam.ToInt32() == WP_SYSTEMMENU))
{
handled = false; // Change the Boolean Value to false //
}
return IntPtr.Zero;
}
Related
I am using Caliburn.Micro for a WPF application.
One of the feature I am using wraps a view in the a popup control and let me choose the settings.
But I came to the conclusion that this is a behaviour I cannot solve.
In the code behind when I click the Button a popup appears and when I click elsewhere on the screen it goes away as expected.
When I click on an item in the list, the popup appears but does not disappear if I click elsewhere on the window. (it does though if i click somewhere else, like another application)
Basically I cannot create a PopUp with StaysOpen = false behaviour when handling a selected item event. What can i do to solve this?
<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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox Name="ListBox" Width="250" HorizontalAlignment="Left" SelectionChanged="ListBox_SelectionChanged">
</ListBox>
<Button Name="Button" HorizontalAlignment="Right" Content="ShowPopUp" Click="Button_Click" />
</Grid>
</Window>
and the code behind
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.ListBox.ItemsSource = new System.Collections.ObjectModel.ObservableCollection<MainWindowItem>()
{
new MainWindowItem {Name = "Test 001" },
new MainWindowItem {Name = "Test 002" },
new MainWindowItem {Name = "Test 003" },
};
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selection = this.ListBox.SelectedItem as MainWindowItem;
if (selection == null)
{
return;
}
var popUp = new System.Windows.Controls.Primitives.Popup();
popUp.Child = new TextBox { Text = selection.Name , MinWidth = 200 , MinHeight = 32};
popUp.StaysOpen = false;
popUp.AllowsTransparency = true;
popUp.PlacementTarget = sender as FrameworkElement;
popUp.IsOpen = true;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var popUp = new System.Windows.Controls.Primitives.Popup();
popUp.Child = new TextBox { Text = "This is button Clicked" , MinWidth = 200, MinHeight = 32 };
popUp.StaysOpen = false;
popUp.AllowsTransparency = true;
popUp.PlacementTarget = sender as FrameworkElement;
popUp.IsOpen = true;
}
}
public class MainWindowItem
{
public string Name { get; set; }
public string Value { get; set; }
}
}
Hi please try the next solution. It based on the mouse down event hooking (from here), each time it happened will collapse the Popup(and reset list item selection).
Code behind
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow
{
public static readonly DependencyProperty SelectedProperty = DependencyProperty.Register(
"Selected", typeof (object), typeof (MainWindow), new PropertyMetadata(default(object)));
//property to monitor selection
public object Selected
{
get { return (object) GetValue(SelectedProperty); }
set { SetValue(SelectedProperty, value); }
}
private Popup _popUp;
public MainWindow()
{
InitializeComponent();
_popUp = new Popup {IsOpen = false};
ListBox.ItemsSource = new System.Collections.ObjectModel.ObservableCollection<MainWindowItem>()
{
new MainWindowItem {Name = "Test 001" },
new MainWindowItem {Name = "Test 002" },
new MainWindowItem {Name = "Test 003" },
};
Loaded += OnLoaded;
Unloaded += OnUnloaded;
}
//will stop hookig here
private void OnUnloaded(object sender, RoutedEventArgs routedEventArgs)
{
Unloaded -= OnUnloaded;
Loaded -= OnLoaded;
MouseHook.MouseAction -= MouseHookOnMouseAction;
MouseHook.Stop();
}
//will collapse the popup and reset selection
private void MouseHookOnMouseAction(object sender, EventArgs eventArgs)
{
Selected = null;
_popUp.IsOpen = false;
}
//will start hookig here
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
MouseHook.MouseAction += MouseHookOnMouseAction;
MouseHook.Start();
}
//here is your logic without any changes
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selection = ListBox.SelectedItem as MainWindowItem;
if (selection == null)
{
return;
}
_popUp.Child = new TextBox { Text = selection.Name, MinWidth = 200, MinHeight = 32 };
_popUp.StaysOpen = false;
_popUp.AllowsTransparency = true;
_popUp.PlacementTarget = sender as FrameworkElement;
_popUp.IsOpen = true;
}
//here is your logic without any changes
private void Button_Click(object sender, RoutedEventArgs e)
{
_popUp.IsOpen = false;
_popUp.Child = new TextBox { Text = "This is button Clicked", MinWidth = 200, MinHeight = 32 };
_popUp.StaysOpen = false;
_popUp.AllowsTransparency = true;
_popUp.PlacementTarget = sender as FrameworkElement;
_popUp.IsOpen = true;
}
}
public class MainWindowItem
{
public string Name { get; set; }
public string Value { get; set; }
}
/// <summary>
/// Mouse hooking helper
/// </summary>
public static class MouseHook
{
public static event EventHandler MouseAction = delegate { };
/// <summary>
/// Starts hooking
/// </summary>
public static void Start()
{
_hookID = SetHook(_proc);
}
/// <summary>
/// Stops hooking
/// </summary>
public static void Stop()
{
UnhookWindowsHookEx(_hookID);
}
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
//actually set a hook
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
IntPtr hook = SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle("user32"), 0);
if (hook == IntPtr.Zero) throw new System.ComponentModel.Win32Exception();
return hook;
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
//is the mouse hook callback
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
MouseAction(null, new EventArgs());
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
XAML code
<Window x:Class="WPFPopupStrangeIssueSOHelpAttempt.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" x:Name="This">
<Grid>
<ListBox Name="ListBox" Width="250" HorizontalAlignment="Left"
SelectedItem="{Binding ElementName=This, Path=Selected, UpdateSourceTrigger=PropertyChanged}"
SelectionChanged="ListBox_SelectionChanged">
</ListBox>
<Button Name="Button" HorizontalAlignment="Right" Content="ShowPopUp" Click="Button_Click" />
</Grid></Window>
Let me know if you need any explanations.
Regards.
When getting an icon from the OS using SHGetFileInfo and converting it to a BitmapSource it is appearing blurry. How can I prevent this?
My XAML:
<Window x:Class="IconBug.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">
<Grid>
<Image x:Name="image" Stretch="None"
VerticalAlignment="Center" HorizontalAlignment="Center"
SnapsToDevicePixels="True" />
</Grid>
</Window>
And the code:
public partial class MainWindow : Window
{
[DllImport("Shell32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SHGetFileInfo(string path, UInt32 attrs, ref SHFILEINFO info, UInt32 size, UInt32 flags);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct SHFILEINFO
{
public IntPtr hIcon;
public int iIcon;
public uint dwAttrs;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string displayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string typeName;
}
public MainWindow()
{
InitializeComponent();
string filename = "C:\\Windows\\System32\\Shell32.DLL";
SHFILEINFO info = new SHFILEINFO();
IntPtr res = SHGetFileInfo(filename, 0, ref info, (uint)Marshal.SizeOf(info), 0x101);
BitmapSource src = Imaging.CreateBitmapSourceFromHIcon(info.hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
image.Source = src;
}
}
You need to set UseLayoutRounding="True" in your window declaration.
Window x:Class="IconBug.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" UseLayoutRounding="True" >
I created a control derived from HwndHost in a WPF application. The HwndHost derived control is inside a UserControl.
I would like to be able to set the background color of the window created inside the HwndHost (it's white by default, I'd like for it to be black). What is the simplest way to do that?
I was having the same problem changing the background color of an HwndHost as well and I found this on StackOverflow:
Registering a custom win32 window class from c#
I have modified it change the background color to black and it looks like this:
public class CustomWindow : IDisposable
{
#region Constants
private const int ERROR_CLASS_ALREADY_EXISTS = 1410;
#endregion
#region Fields
private bool m_disposed;
private IntPtr m_hwnd;
private WndProc m_wnd_proc_delegate;
#endregion
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="CustomWindow"/> class.
/// </summary>
/// <param name="class_name">The class_name.</param>
/// <exception cref="System.Exception">
/// class_name is null
/// or
/// class_name is empty
/// or
/// Could not register window class
/// </exception>
public CustomWindow(string class_name)
{
if (class_name == null)
{
throw new Exception("class_name is null");
}
if (class_name == String.Empty)
{
throw new Exception("class_name is empty");
}
this.m_wnd_proc_delegate = CustomWndProc;
// Create WNDCLASS
var wind_class = new WNDCLASS();
wind_class.lpszClassName = class_name;
wind_class.lpfnWndProc =
Marshal.GetFunctionPointerForDelegate(this.m_wnd_proc_delegate);
wind_class.hbrBackground = CreateSolidBrush(0);
var class_atom = RegisterClassW(ref wind_class);
var last_error = Marshal.GetLastWin32Error();
if (class_atom == 0 && last_error != ERROR_CLASS_ALREADY_EXISTS)
{
throw new Exception("Could not register window class");
}
// Create window
this.m_hwnd = CreateWindowExW(
0,
class_name,
String.Empty,
0,
0,
0,
0,
0,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero);
}
#endregion
/// <summary>
/// Creates the solid brush.
/// </summary>
/// <param name="theColor">The color.</param>
/// <returns>IntPtr.</returns>
[DllImport("gdi32.dll", EntryPoint = "CreateSolidBrush", CharSet = CharSet.Unicode)]
internal static extern IntPtr CreateSolidBrush(uint theColor);
/// <summary>
/// Gets the black window.
/// </summary>
/// <value>The black window.</value>
public IntPtr BlackWindow
{
get
{
return this.m_hwnd;
}
}
#region Delegates
private delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
#endregion
#region Public Methods and Operators
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
#region Methods
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr CreateWindowExW(
UInt32 dwExStyle,
[MarshalAs(UnmanagedType.LPWStr)] string lpClassName,
[MarshalAs(UnmanagedType.LPWStr)] string lpWindowName,
UInt32 dwStyle,
Int32 x,
Int32 y,
Int32 nWidth,
Int32 nHeight,
IntPtr hWndParent,
IntPtr hMenu,
IntPtr hInstance,
IntPtr lpParam);
private static IntPtr CustomWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
return DefWindowProcW(hWnd, msg, wParam, lParam);
}
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr DefWindowProcW(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool DestroyWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern UInt16 RegisterClassW([In] ref WNDCLASS lpWndClass);
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
private void Dispose(bool disposing)
{
if (!this.m_disposed)
{
if (disposing)
{
// Dispose managed resources
}
// Dispose unmanaged resources
if (this.m_hwnd != IntPtr.Zero)
{
DestroyWindow(this.m_hwnd);
this.m_hwnd = IntPtr.Zero;
}
this.m_disposed = true;
}
}
#endregion
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct WNDCLASS
{
public readonly uint style;
public IntPtr lpfnWndProc;
public readonly int cbClsExtra;
public readonly int cbWndExtra;
public readonly IntPtr hInstance;
public readonly IntPtr hIcon;
public readonly IntPtr hCursor;
public IntPtr hbrBackground;
[MarshalAs(UnmanagedType.LPWStr)]
public readonly string lpszMenuName;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpszClassName;
}
}
Then I used the the window that the CustomWindow creates and parent that in the HwndHost.
I wanted to have a customized window so followed a few tutorials which enable this by setting the window style to none, and then adding the title-bar/restore/minimize/close buttons yourself. The minimize is achieved by simply handling the click event and setting the Window-state to minimized, but this doesn't show the minimize animation you see on Windows 7, and just instantly hides the window, which feels very odd when used with other windows that do animate, as you tend to feel the application is closing.
So, is there anyway of enabling that animation? .. it seems to be disabled when you change the WindowStyle to none.
Edit : Test code
public partial class MainWindow : Window
{
public MainWindow()
{
WindowStyle = WindowStyle.None;
InitializeComponent();
}
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
// this doesnt seem to animate
SendMessage(new WindowInteropHelper(this).Handle, 0x0112, (IntPtr)0xF020, IntPtr.Zero);
}
protected override void OnMouseRightButtonDown(MouseButtonEventArgs e)
{
base.OnMouseRightButtonDown(e);
WindowStyle = WindowStyle.SingleBorderWindow;
WindowState = WindowState.Minimized;
}
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => WindowStyle = WindowStyle.None));
}
}
A newer feature of .NET has solved this problem.
Leave your WindowStyle="SingleBorder" or "ThreeDBorder"
Leave ResizeMode="CanResize"
Then add this to the xaml inside the
<Window>
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="0" CornerRadius="0" CaptionHeight="0" UseAeroCaptionButtons="False" ResizeBorderThickness="7"/>
</WindowChrome.WindowChrome>
</Window>
The window will not have any of the default border, but will still allow resizing and will not cover the task bar when maximized. It will also show the minimize animation as before.
EDIT
Unfortunately, when using WindowStyle="None" it still disables the animation and covers the taskbar. So this method does not work if you're trying to make a transparent window.
Edited the answer after experimenting a bit.
There are two options:
1. You can change the Style just before minimising and activating the window:
private void Button_OnClick(object sender, RoutedEventArgs e)
{
//change the WindowStyle to single border just before minimising it
this.WindowStyle = WindowStyle.SingleBorderWindow;
this.WindowState = WindowState.Minimized;
}
private void MainWindow_OnActivated(object sender, EventArgs e)
{
//change the WindowStyle back to None, but only after the Window has been activated
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => WindowStyle = WindowStyle.None));
}
This solution has one limitation - it doesn't animate the window if you minimise it from the taskbar.
2. Minimise the Window by sending it WM_SYSCOMMAND message with SC_MINIMIZE parameter and changing the border style by hooking into the message (HwndSource.FromHwnd(m_hWnd).AddHook(WindowProc)).
internal class ApiCodes
{
public const int SC_RESTORE = 0xF120;
public const int SC_MINIMIZE = 0xF020;
public const int WM_SYSCOMMAND = 0x0112;
}
private IntPtr hWnd;
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
private void Window_Loaded(object sender, RoutedEventArgs e)
{
hWnd = new WindowInteropHelper(this).Handle;
HwndSource.FromHwnd(hWnd).AddHook(WindowProc);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
SendMessage(hWnd, ApiCodes.WM_SYSCOMMAND, new IntPtr(ApiCodes.SC_MINIMIZE), IntPtr.Zero);
}
private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == ApiCodes.WM_SYSCOMMAND)
{
if (wParam.ToInt32() == ApiCodes.SC_MINIMIZE)
{
WindowStyle = WindowStyle.SingleBorderWindow;
WindowState = WindowState.Minimized;
handled = true;
}
else if (wParam.ToInt32() == ApiCodes.SC_RESTORE)
{
WindowState = WindowState.Normal;
WindowStyle = WindowStyle.None;
handled = true;
}
}
return IntPtr.Zero;
}
Neither of the above methods are great, because they are just hacks. The biggest downside is that you can actually see the border reappearing for a moment when you click the button. I'd like to see what others come up with as I don't consider this as a good answer myself.
If you handle the WM_NCCALCSIZE message by returning 0, handle the WM_NCHITTEST message using either your own code (if you want to do manual hit-testing) or also returning 0, and set the WindowStyle to SingleBorder, the window will function like a borderless window but it will have the animations enabled.
If completely necessary, you may also need to handle the WM_GETMINMAXINFO to fix the maximize size - it clips the borders off because the window's style is SingleBorder.
I have found another solution, if you need AllowTransparency = True.
It is not beautiful, rather a bit hacky.
But it is very simple and works great. This uses a empty Window, which is shortly shown when you Minimize/Maximize/Restore your Window, and it has the same position, widht, size and height as your Window. It always has the same Window State as your Window, and it does the animations, which YourWindow lacks because of WindowStyle None and AllowTransparency True. The empty Window has a Window Style SingleBorderWindow and AllowTransparency = false. (by default, so i dont need to set it manually) This is a must or it would not animate. After it has animated, it is completely hidden. You could adjust the look of the Fake Window (BackgroundColor etc...) to YourWindow if it doesnt look good.
public partial Class YourWindowClass : Window
{
Window w;
public YourWindowClass()
{
InitializeComponent();
w = new Window();
w.Width = Width;
w.Height = Height;
w.WindowStartupLocation = this.WindowStartupLocation;
}
Then, you place this in your state changed event:
private void YourWindowClass_StateChanged(object sender, EventArgs e)
{
w.Left = Left;
w.Top = Top;
w.Width = Width;
w.Height = Height;
w.Show();
if (WindowState == WindowState.Minimized)
{
if (w.WindowState == WindowState.Minimized) w.WindowState = WindowState.Normal;
w.WindowState = WindowState.Minimized;
CloseWindow();
}
if (WindowState == WindowState.Normal)
{
w.WindowState = WindowState.Normal;
w.Left = this.Left;
Activate();
CloseWindow();
}
if (WindowState == WindowState.Maximized)
{
w.WindowState = WindowState.Maximized;
Activate();
CloseWindow();
}
}
Finally, create this async Task in YourWindowClass. It will wait shortly and then hide the extra Window.
public async Task CloseWindow()
{
await Task.Delay(600);
w.Visibility = Visibility.Hidden;
}
This will remove the hidden hack Window, so if you close the real Window, the hacky animation Window will close too. Else it wouldnt be Visible to the user because its hidden, but it will still be open and so parts of your App are open. This is a behaviour we dont want, so put this as your Closed Event:
private void YourWindowClass_Closed(object sender, EventArgs e)
{
w.Close();
}
I am trying to host an ILPanel in a WindowsFormsHost Control in WPF. Here's my code:
XAML:
<Window x:Class="ILNumericsCharacteristicViewer.ILView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:forms="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
Title="ILView"
Width="300"
Height="300"
Loaded="ILView_OnLoaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<forms:WindowsFormsHost x:Name="WindowsFormsHost" Margin="5" />
<Button x:Name="ButtonClose"
Grid.Row="1"
HorizontalAlignment="Right"
Click="ButtonClose_OnClick"
Content="Close" />
</Grid>
Code Behind:
public partial class ILView : Window
{
private ILPanel ilPanel;
public ILView()
{
InitializeComponent();
}
private void IlPanelOnLoad(object sender, EventArgs eventArgs)
{
ILArray<float> A = ILMath.tosingle(ILMath.rand(3, 10000));
var scene = new ILScene {
new ILPlotCube(twoDMode: false) {
new ILPoints {
Positions = A,
Color = null,
Colors = A,
Size = 2,
}
}
};
var pcsm = scene.First<ILPlotCube>().ScaleModes;
pcsm.XAxisScale = AxisScale.Logarithmic;
pcsm.YAxisScale = AxisScale.Logarithmic;
pcsm.ZAxisScale = AxisScale.Logarithmic;
ilPanel.Scene = scene;
}
private void ButtonClose_OnClick(object sender, RoutedEventArgs e)
{
Close();
}
private void ILView_OnLoaded(object sender, RoutedEventArgs e)
{
ilPanel = new ILPanel();
ilPanel.Load += IlPanelOnLoad;
WindowsFormsHost.Child = ilPanel;
}
}
The line WindowsFormsHost.Child = ilPanel; throws an Argument Exception: "Parameter is not valid." Stack Trace:
at System.Drawing.Bitmap..ctor(Int32 width, Int32 height,
PixelFormat format) at
ILNumerics.Drawing.ILBackBuffer.set_Rectangle(Rectangle value) at
ILNumerics.Drawing.ILGDIDriver.set_Size(Size value) at
ILNumerics.Drawing.ILOGLControl.OnResize(EventArgs e) at
System.Windows.Forms.Control.OnSizeChanged(EventArgs e) at
System.Windows.Forms.Control.UpdateBounds(Int32 x, Int32 y, Int32
width, Int32 height, Int32 clientWidth, Int32 clientHeight) at
System.Windows.Forms.Control.UpdateBounds() at
System.Windows.Forms.Control.WmWindowPosChanged(Message& m) at
System.Windows.Forms.Control.WndProc(Message& m) at
System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd,
Int32 msg, IntPtr wparam, IntPtr lparam)
If the rendering controls of ILNumerics are not loaded from a regular application, you will have to give a hint, in order to distinguish regular rendering from design time behavior. Frameworks, which load the library dynamically at runtime (VSTO, devenv, LinqPad and obviously MEF) may cause ILNumerics controls to 'think' to be used in a designer. Hence the design time replacement ('circle') you found.
In order to make ILNumerics render the 'runtime way' instead, add the following setting to your app.config:
key="ILNIsHosted" value="true"
In the context of the app.config settings file:
<configuration>
<appSettings>
<add key="ILNIsHosted" value="true"/>
</appSettings>
</configuration>
The use of the app.config enables the application of the setting even in those scenarios, where the framework does not allow user code to be executed before the setup of any control. If your framework provides some initialization hook, you may just as well do the configuration by code:
ILNumerics.Settings.IsHosted = true;
Keep in mind, that this code needs to be executed early in the application setup. At latest before ILPanel is initialized. Otherwise, the use of app.config is recommended.