Functionality to treat floating tabs as separate from main window - c#

Context: I launch my main window. Within that window I create three new tabs. I float two of the tabs and leave the other within the main window. There are two problems I am currently trying to tackle:
I want to be able to minimize the main window without hiding my other floating tabs as well.
When shifting focus to another program (e.g. Chrome) then clicking back on my floating tab, I don't want all my other floating tabs + the main window to be brought back to front, in effect hiding my other program.
I believe this should be possible since the Visual Studio UI is built using WPF and I can achieve this functionality using floating tabs in VS.

Yes you can do this. The reason why it is being minimized is because the default owner of the floating window is the main window. so you have to set the floatingWindow.Owner = null; then you will also be able to put the main window in front of the floating window. if you want to switch between floating window and main window you can set floatingWindow.ShowInTaskbar = true;.
In my code i put it in a selectionChanged event handler so when i pop out a document it fires the selectionChanged event.
Document creation
private void userItem_Click(object sender, RoutedEventArgs e)
{
LayoutDocument ld = new LayoutDocument();
ld.Title = "All Users";
ld.ToolTip = "Manage all users";
//selection changed event
ld.IsSelectedChanged += Ld_IsSelectedChanged;
ld.IsActiveChanged += Ld_IsSelectedChanged;
Users users = new Users(ld);
ld.Content = users;
LayoutDocumentPane pane = ((todaysPayments.FindParent<LayoutDocumentPane>() ?? (panal.Children?[0] as LayoutDocumentPane)) ?? new LayoutDocumentPane());
pane.Children.Add(ld);
if (panal.ChildrenCount == 0)
{
panal.Children.Add(pane);
}
ld.IsSelected = true;
}
And the event handler
public void Ld_IsSelectedChanged(object sender, EventArgs e)
{
//get the floating windows from the DockingManager
manager.FloatingWindows.ToList().ForEach(floatingWindow =>
{
floatingWindow.Owner = null;
floatingWindow.ShowInTaskbar = true;
var fw = floatingWindow.Model as LayoutDocumentFloatingWindow;
floatingWindow.Title = fw?.RootDocument?.Title ?? "";
});
}

Related

New dialogs cause window to disappear in WPF application

I'm running WPF application which can show windows and dialogs on top of the main screen of the application (.NET Framefork 4.7.2)
I use IWindowManager interface to call ShowWindow and ShowDialog.
When I want to show some window
Execute.OnUIThread(ShowPostProcessingLoadingMsg);
private void ShowPostProcessingLoadingMsg()
{
Logger.Info("PostProcessingToolViewModel: ShowPostProcessingLoadingMsg()");
if (_processingProgressMsg != null)
{
Logger.Warn("PostProcessingToolViewModel: ShowPostProcessingLoadingMsg() Loading msg was actibe already, closing it and creating a new one.");
_processingProgressMsg.TryClose();
}
_processingProgressMsg = new LoadingMessageViewModel()
{
ShowProgressRing = Visibility.Hidden,
ShowProgressBar = Visibility.Visible,
LoadingVisualState = LoadingVisualState.Mini
};
_progress = _processingProgressMsg.Progress;
_progress?.Report(0);
_updateProgressText = _processingProgressMsg.SetMessage;
_WindowManager?.ShowWindow(_processingProgressMsg);
}
And during it I show a dialog on other thread -
private void ShowPopupInDesktop(BatteryViewModel batteryPopupViewModel)
{
_logger.Info("BatteryViewModel::ShowPopupInDesktop: Going to show battery dialog");
_isPopupOpen = true;
SetPopupPosition(batteryPopupViewModel);
_windowManager.ShowDialog(batteryPopupViewModel, BatteryPopupViewContextName);
}
Then the window which I showed disappears.
I don't know how to keep the window opened and why does the dialog make it disappear.

How can I hide a window WITHOUT Visibility property?

I have an application that has a lot of modal popup windows. Some are custom windows displayed with .ShowDialog(), other are generic message boxes using a 3rd party tool (DXMessageBox.Show(...)), and others are system dialogs such as an OpenFileDialog. If the user leaves the application running long enough, it should time out and show a "Session Locked" screen and prevent users from seeing or interacting with the application until they login again. This is problematic because of the modal dialogs.
My current solution is to host the Relogin screen in the current modal window if there is one, and hide all other windows. The problem is that if I set Visibility = Hidden on any window I have called using .ShowDialog(), it treats that dialog as having received a result and processes the code that handles the dialog result. They are also no longer modal after they are re-shown.
So my current attempt is to try to hide the window using something other than Visibility, and prevent it from being activated. The closest I've come is by setting Minimized=true and ShowInTaskbar=false, but this results in an undesirable minimized titlebar above my taskbar.
Is there a way to prevent this from happening, or alternatively is there another way to hide a window and prevent it's activation without causing .ShowDialog to return?
Here's some code to re-create a sample application to test this with. Just add a button to launch the ShowLock_Click event handler.
private readonly Dictionary<System.Windows.Window, WindowStyle> _hiddenWindows = new Dictionary<System.Windows.Window, WindowStyle>();
// Create a button to launch this for testing
private void ShowLock_Click(object sender, RoutedEventArgs e)
{
// Will show another window with .ShowDialog, then 2s timeout will trigger lock window
using (new System.Threading.Timer(OnLockTimerElapsed, null, 2000, System.Threading.Timeout.Infinite))
{
ShowTestDialog();
}
}
private void OnLockTimerElapsed(object state)
{
_hiddenWindows.Clear();
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() =>
{
var mainWindow = Application.Current.MainWindow;
Window host = null;
foreach (Window win in Application.Current.Windows)
{
if (IsModalDialog(win))
host = win;
_hiddenWindows.Add(win, win.WindowStyle);
// Been testing various ways to hide window without using Visibility
win.ShowInTaskbar = false;
win.WindowStyle = WindowStyle.None;
win.WindowState = WindowState.Minimized;
win.Opacity -= 1;
win.IsHitTestVisible = false;
}
ShowLockScreen(host);
}));
}
private void ShowLockScreen(Window owner = null)
{
var lockScreen = new Window
{
Title = "Relogin Window",
Content = "This is a test Relogin Window. Close Window via X to continue",
WindowStartupLocation = WindowStartupLocation.CenterScreen
};
if (owner != null)
lockScreen.Owner = owner;
lockScreen.ShowDialog();
// Once that window closes, restore other windows
RestoreSession();
}
private void RestoreSession()
{
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() =>
{
foreach (var win in _hiddenWindows.Keys)
{
win.ShowInTaskbar = true;
win.WindowStyle = _hiddenWindows[win];
win.WindowState = WindowState.Normal;
win.IsHitTestVisible = true;
win.Opacity += 1;
}
}));
}
private void ShowTestDialog()
{
var test = new Window
{
Title = "Test Modal Dialog",
Content = "This is a test Modal Dialog. Close window via X to continue.",
Height = 100,
Width = 350,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
Owner = this
};
var result = test.ShowDialog();
// This code gets run if I set Visibility=Hidden. I do not want that.
MessageBox.Show($"Test Dialog result returned. Result : {result}. This should ONLY happen when you click X on the dialog window");
}
private static bool IsModalDialog(Window window)
{
return (bool)typeof(System.Windows.Window)
.GetField("_showingAsDialog", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
.GetValue(window);
}

System tray icon with c# Console Application won't show menu

I've got a small C# (.NET 4.0) Console Application that I'd like the user to be able to interact by showing a menu when they right-click the System Tray icon. I can add an icon to the Tray with no problems, but I just cannot get the menu to appear. I'm using the following code:
NotifyIcon trayIcon = new NotifyIcon();
trayIcon.Text = "TestApp";
trayIcon.Icon = new Icon(SystemIcons.Application, 40, 40);
ContextMenu trayMenu = new ContextMenu();
trayMenu.MenuItems.Add("Blah", item1_Click);
trayMenu.MenuItems.Add("Blah2", item1_Click);
trayMenu.MenuItems.Add("Blah3", item1_Click);
trayIcon.ContextMenu = trayMenu;
trayIcon.Visible = true;
... which puts the icon in the tray. However, right-clicking the icon does nothing. I've tried various permutations of MenuItems.Add, but nothing will make the menu appear. I'm sure I'm missing something simple - any ideas what?
Try adding this after you create the icon:
Application.Run()
Note that this method will not return, so you can't do anything after calling it. This means that you'll have to do all your other work in a separate thread.
What happens is that the OS sends your application a message telling it that the tray icon has been right-clicked, but the tray icon code never sees it (because these messages are processed by Application.Run) and so can't respond by opening the menu.
Concerning Application.Run(), this is an alternative to placing all the other code in another thread would be to create the NotifyIcon, menu, events, etc on a thread other than the main thread.
This should include Application.Run() as this allows the standard application message loop to work on the current thread. Then since the events were created on the same thread, the Application.Exit() can be used to close out the notification messaging but still allow the main thread to continue. Here's a small example for a console app...
class Program
{
public static ContextMenu menu;
public static MenuItem mnuExit;
public static NotifyIcon notificationIcon;
static void Main(string[] args)
{
Thread notifyThread = new Thread(
delegate()
{
menu = new ContextMenu();
mnuExit = new MenuItem("Exit");
menu.MenuItems.Add(0, mnuExit);
notificationIcon = new NotifyIcon()
{
Icon = Properties.Resources.Services,
ContextMenu = menu,
Text = "Main"
};
mnuExit.Click += new EventHandler(mnuExit_Click);
notificationIcon.Visible = true;
Application.Run();
}
);
notifyThread.Start();
Console.ReadLine();
}
static void mnuExit_Click(object sender, EventArgs e)
{
notificationIcon.Dispose();
Application.Exit();
}
}
Here is the solution:
You have to use Application.Run() because events of gui in console mode not working.
But you can use this solution:
var task = System.Threading.Tasks.Task.Factory.StartNew(() => ShowTrayIcon());
void ShowTrayIcon()
{
some code with tray icon ...
}
This will start your setup of try icon in new thread ...
Did you add the event-handler for tray Icon mouse click?
trayIcon .MouseDown += new MouseEventHandler(trayIcon_MouseDown);
create context menu and do as following inside the trayIcon_MouseDown function
private void trayIcon_MouseDown (object sender,MouseEventArgs e)
{
//add you menu items to context menu
contextMenu.Items.Add(item);
contextMenu.IsOpen = true;
}
Try this. Think this will help you.

Button Screen Change in Android Mono using delegates

The following code is from the C# portion of my Android Mono application. It is going to eventually be the GUI for a multimeter simulator, but right now just displays text. It is rather straight forward:
-Click one of the buttons to go to that meter (voltmeter, ammeter, ohmmeter)
-Click the "re-scan" button and a TextView tells you how many times you clicked that button.
-Click one of the other meter buttons or the home button to switch views
That much is working flawlessly. Unfortunately, once I switch views, the buttons cease to work. Below is the code for the Ohm button and the Amp button. The Ohm button is the 'complete' one that brings up views of all of the other screens. For testing purposes, I was going to the amp screen but when I go there, its re-scan button does nothing. None of the buttons do anything.
I am fairly certain that the issue is my use of the delegate commands, but none of my research has led me in any way towards a solution.
I can provide more of the main code and the XML code if needed.
ampButton.Click += delegate
{
SetContentView(Resource.Layout.AmpScreen);
Button ampButtonData = FindViewById<Button>(Resource.Id.CurrentButtonamp);
TextView ampData = FindViewById<TextView>(Resource.Id.ampdata);
ampButtonData.Click += delegate
{
ampData.Text = string.Format("{0} clicks!", count2++);
};
Button amp2volt = FindViewById<Button>(Resource.Id.Amp2VoltButton);
Button amp2ohm = FindViewById<Button>(Resource.Id.Amp2OhmButton);
Button amp2home = FindViewById<Button>(Resource.Id.Amp2HomeButton);
};
ohmButton.Click += delegate
{
SetContentView(Resource.Layout.OhmScreen);
Button ohmButtonData = FindViewById<Button>(Resource.Id.CurrentButtonohm);
TextView ohmData = FindViewById<TextView>(Resource.Id.ohmdata);
ohmButtonData.Click += delegate
{
ohmData.Text = string.Format("{0} clicks!", count3++);
};
Button ohm2amp = FindViewById<Button>(Resource.Id.Ohm2AmpButton);
Button ohm2volt = FindViewById<Button>(Resource.Id.Ohm2VoltButton);
Button ohm2home = FindViewById<Button>(Resource.Id.Ohm2HomeButton);
ohm2amp.Click += delegate
{
SetContentView(Resource.Layout.AmpScreen);
};
ohm2volt.Click += delegate
{
SetContentView(Resource.Layout.VoltScreen);
};
ohm2home.Click += delegate
{
SetContentView(Resource.Layout.Main);
};
};
I think your problem is that you are replacing the entire view each time - so the button instances are changing.
What happens inside SetContentView is that the InflatorService gets asked to create a brand new set of UI objects based on the passed in XML, the existing UI is wiped clean and then those new UI objects are put in their place.
It doesn't matter if the new UI objects happen to have the same resource identifiers as the old objects - they are still separate instances.
If you want to continue using your current approach, then you need to rewire all your events after each SetContentView - e.g.
ohm2amp.Click += delegate
{
SetContentView(Resource.Layout.AmpScreen);
RewireEvents();
};
with
private void RewireEvents()
{
var ohm2home = FindViewById<Button>(Resource.Id.ohm2home);
ohm2home.Click += { /* todo */ };
// etc
}
alternatively, maybe consider a different UI:
e.g. you could change the Visibility on different child layouts rather than calling SetContentView to replace everything
e.g. or you could use multiple activities (or tabs) instead of a single activity
Hope that helps

Simple UI issue in winforms

I have a simple winforms application, on performing operations it shows a child window everytime. If I open a browser window (fully maximized) or some other window as usual
the application goes back with its childwindow, on clicking the exe which is in the taskbar
only the child window gets visible,but the application window doesn't come into view. I want to know how to show both the windows when I select it from taskbar.
childwindow is also a winform,whose toplevel property is set as true,apart from it nothing
is new(JUST BY CLICKING A BUTTON OR CELL IN GRID I CREATE AN OBJECT FOR THE FORM AND USES IT SHOW PROPERTY TO SHOW)
AlertMsgWindow _alertMsg;
void dataGridViewAlerts_MouseDoubleClick(object sender, MouseEventArgs e)
{
try
{
if (!string.IsNullOrEmpty(this.dataGridViewAlerts.getValue(0, this.dataGridViewAlerts.SelectedRow)))
{
this.dataGridViewAlerts.setCellImage(0, this.dataGridViewAlerts.SelectedRow, "NewsIconRead");
if (_alertMsg == null || _alertMsg.IsDisposed)
{
if (_alertMsg != null)
{
_alertMsg.onDeleteMessageRequest -= new DeleteMessage(_alertMsg_onDeleteMessageRequest);
_alertMsg.Dispose();
}
_alertMsg = new AlertMsgWindow();
_alertMsg.onDeleteMessageRequest += new DeleteMessage(_alertMsg_onDeleteMessageRequest);
}
_alertMsg.FillDetails(alertDetails[IDcollection[this.dataGridViewAlerts.SelectedRow]]);
if (!_alertMsg.Visible)
{
_alertMsg.Location = PointToScreen(new Point(this.Width / 4, -this.Height));
_alertMsg.Show(this);
}
if (onReadMessageReq != null)
onReadMessageReq(IDcollection[this.dataGridViewAlerts.SelectedRow]);
}
}
catch (Exception)
{ }
}
Note: THIS IS HAPPENING ONLY IN WINDOWS2000
I used a component named Dotnetmagic.dll,i dont know whether it causes the problem.can somebody helps me to solve this
I replaced these lines
_alertMsg.Location = PointToScreen(new Point(this.Width / 4, -this.Height));
With
_alertMsg.Left = x;
_alertMsg.Top = y;
and it solved my problem

Categories

Resources