I have a usercontrol (UC1) that changes aspect at design time according to what the user wants to show.
A regular button that pops a window with usercontrol UC2 (the window is only shown at runtime)
The UC2 directly hosted in UC1 (the regular button is then not shown)
Since I want to use the same UC2 instance in both situation, I just transfer ownership between UC1 and the form.
public UC1 ()
{
_uc2 = new UC2 ();
}
public bool DisplayModeSimple
{
get { return _displayModeSimple; }
set
{
_displayModeSimple = value;
if (_displayModeSimple)
{
// ... Verify if _uc2 is already in Controls...
Controls.Remove (_uc2);
uiButton.Visible = true;
}
else
{
// ... Verify that _uc2 is not in Controls ...
Controls.Add (_uc2);
uiButton.Visible = false;
}
}
}
private void HandleButtonClick (object sender, EventArgs e)
{
// Not called if DisplayModeSimple=false since button is hidden...
using (var form = new PopupForm (_uc2))
{
form.ShowDialog (this);
}
}
Works fine in both design and runtime mode.
In design mode if I change the display mode UC1 behaves correctly.
However, controls that are on UC2 can be clicked like if it was runtime.
If I then close the form hosting UC1 and reopen it everything is back to normal, i.e., I cannot "click" on any controls in UC2.
The problem is that your first UserControl is hosted on VS, so it knows to be in design mode. The second UserControl is hosted in the first UserControl, so as its host is not a Designer, it thinks to be in a normal container and behaves accordingly. How to solve that is a bit tricky, as there isn't asimple solution AFAIK. Here you can find some workarounds. Another could be to test Site.DesignMode recursively, but it depends on the level of depth of your controls.
Related
I have a user control that is a spinning "wait" graphic. I've added it to a form and I set-up a convention in Caliburn.Micro using the code from this thread
I then created a property following the naming convention and named this user control accordingly:
<uc:LoadSpinner x:Name="Authenticating" />
My property looks like this:
protected bool _authenticatingIsVisible = false;
public bool AuthenticatingIsVisible
{
get { return _authenticatingIsVisible; }
set
{
_authenticatingIsVisible = value;
NotifyOfPropertyChange(() => AuthenticatingIsVisible);
}
}
I can see the control get bound and when the form starts up, the spinner is invisible. However, when I set it visible it still doesn't appear. To simplify things and test the binding I then created a rectangle on the form and named it the same way. It appears/disappears as expected. So it seems like it's either something specific to a user control or animations.
I also tried wrapping the user control inside of a Border control and naming it the same way (the idea was if normal controls worked, then the contained user control should appear/disappear when the Border does). Nope.
Why isn't this working?
Theodosius Von Richthofen is correct. You want to use Visibility not bool. Try this:
protected Visibility _authenticatingIsVisible = Visibility.Hidden;
public Visibility AuthenticatingIsVisible
{
get { return _authenticatingIsVisible; }
set
{
_authenticatingIsVisible = value;
NotifyOfPropertyChange(() => AuthenticatingIsVisible);
}
}
I have an app that has a main window that contains a bunch of stuff. From time to time the user will do something in response to which I want to display something else entirely in the main window, temporarily hiding what is there.
I'm doing this by making the outermost element in the main window a Grid with no rows or columns defined. Every element in the grid, then will completely fill the one single cell in the grid, drawing on top of the others.
My regular bunch stuff, then, is in the first element of the grid, and my temporary something else is a UserControl as the second element of the grid, that is normally set Visibility=Collapsed.
Except for the KeyBinding everything works fine. When the appropriate command is triggered in the regular bunch of stuff, the visibility on the UserControl is set to Visible, and it covers the regular bunch of stuff completely. When the user clicks on the close button on the UserControl, it's visibility is set to Collapsed, again, and it disappears and the regular bunch of stuff is revealed.
My problem is with KeyBindings. I have a few defined on the UserControl - that should not be defined on the main window - and they don't work. Or rather, they work fine once I click inside the UserControl, but they don't work until I do.
I need them to work as soon as the UserControl is made visible, without requiring the user to click or tab into the UserControl proper.
My guess is that this has something to do with keyboard focus - but I've been unable to find a way to set the focus on the UserControl. Here's the thing - the only element within the UserControl is a tab control, all of the tabs of which are dynamically constructed via templates. There are no elements known at compile time that I can reference explicitly and pass to KeyBoard.Focus().
So, am I right in thinking that it's lack of focus that is causing the problem? And if so, how can I set focus to an element in a TabControl, when I don't even know how many tabs there are, let alone which is the selected one?
I wanted this control to have the focus, when it became visible. So in the constructor, I set up a handler on IsVisibleChanged.
public MyControl
{
...
this.IsVisibleChanged += new DependencyPropertyChangedEventHandler(MyControl_IsVisibileChanged);
}
void MyControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (!(bool(e.NewValue)
return;
this.Focusable = true;
Keyboard.Focus(this);
}
I could have set Focusable in the xaml, but I prefer it in the code-behind, so that all of the relevant code is in one place.
For me this worked in the code-behind:
using System.Windows.Input;
namespace MyApplication.Views.Dialogs
{
public partial class MyControl
{
public MyControl()
{
InitializeComponent();
Loaded += (sender, args) =>
{
MyButton.Focus();
Keyboard.Focus(MyButton);
};
}
}
}
I am using ShowDialog() with WindowStyle = WindowStyle.SingleBorderWindow; to open a modal window in my WPF (MVVM) application, but it lets me navigate to parent window using the Windows taskbar (Windows 7).
I've found an answer here: WPF and ShowDialog() but it isn't suitable for me because I don't need an "always on top" tool window.
Thanks in advance
Try setting the Owner property of the dialog. That should work.
Window dialog = new Window();
dialog.Owner = mainWindow;
dialog.ShowDialog();
Edit:
I had a similar problem using this with MVVM. You can solve this by using delegates.
public class MainWindowViewModel
{
public delegate void ShowDialogDelegate(string message);
public ShowDialogDelegate ShowDialogCallback;
public void Action()
{
// here you want to show the dialog
ShowDialogDelegate callback = ShowDialogCallback;
if(callback != null)
{
callback("Message");
}
}
}
public class MainWindow
{
public MainWindow()
{
// initialize the ViewModel
MainWindowViewModel viewModel = new MainWindowViewModel();
viewModel.ShowDialogCallback += ShowDialog;
DataContext = viewModel;
}
private void ShowDialog(string message)
{
// show the dialog
}
}
I had this problem but as the Window was being opened from a view model I didn't have a reference to the current window. To get round it I used this code:
var myWindow = new MyWindowType();
myWindow.Owner = Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
You can use: myWindow.Owner = Application.Current.MainWindow;
However, this method causes problems if you have three windows open like this:
MainWindow
|
-----> ChildWindow1
|
-----> ChildWindow2
Then setting ChildWindow2.Owner = Application.Current.MainWindow will set the owner of the window to be its grandparent window, not parent window.
When the parent window makes (and shows) the child window, that is where you need to set the owner.
public partial class MainWindow : Window
{
private void openChild()
{
ChildWindow child = new ChildWindow ();
child.Owner = this; // "this" is the parent
child.ShowDialog();
}
}
Aditionally, if you don't want an extra taskbar for all the children... then
<Window x:Class="ChildWindow"
ShowInTaskbar="False" >
</Window>
Much of the reason for the MVVM pattern is so that your interaction logic can be unit tested. For this reason, you should never directly open a window from the ViewModel, or you'll have dialogs popping up in the middle of your unit tests.
Instead, you should raise an event that the View will handle and open a dialog for you. For example, see this article on Interaction Requests: https://msdn.microsoft.com/en-us/library/gg405494(v=pandp.40).aspx#sec12
The problem seems to be related to Window.Owner, and indeed if you judge by previous knowledge that you might have of the Win32 API and WinForms, a missing owner would be the typical cause of such a problem, but as many have pointed out, in the case of WPF that's not it. Microsoft keeps changing things to keep things interesting.
In WPF you can have a dialog with a specific owner and you can still have the dialog appear in the taskbar. Because why not. And that's the default behavior. Because why not. Their rationale is that modal dialogs are not kosher anymore, so you should not be using them; you should be using modeless dialogs, which make sense to show as separate taskbar icons, and in any case the user can then decide whether they want to see different app windows as separate icons, or whether they want to see them grouped.
So, they are trying to enforce this policy with complete disregard to anyone who might want to go against their guidelines and create a modal dialog. So, they force you to explicitly state that you do not want a taskbar icon to appear for your dialog.
To fix this problem, do the following in the constructor of your view class:
ShowInTaskbar = false;
(This may happen right after InitializeComponent();
This is equivalent to Xcalibur37's answer, though the way I figure things, since WPF forces you to have both a .cs file and a .xaml file, you might as well put things that are unlikely to change in the .cs file.
Add "ShowInTaskbar" and set it to false.
Even if this post is a bit old, I hope it is OK that I post my solution.
All the above results are known to me and did not exactly yield the desired result.
I am doing it for the other googlers :)
Lets say f2 is your window that you want to display on top of f1 :
f2.Owner = Window.GetWindow(this);
f2.ShowDialog();
That's it , I promise it will not disappear !
HTH
Guy
I have an MVVM setup with a mainwindow that contains a ContentControl.
I set this to a particular viewmodel which then maps to a view.
A view is a usercontrol.
I want to be able to set the default keyboard focus to a default element in the usercontrol(View) when it loads so the application can eventually be driven just by using up, down, left, right and enter.
Some of my failed attempts are setting
FocusManager.FocusedElement="{Binding ElementName=DefaultElement}"
in my content control tag. This sets the logical focus but not the keyboard focus
I'd rather keep the solution in xaml if possable but have tried placing the following in code behind.
Keyboard.Focus(DefaultElement);
This does not work but if I popup a message box first it does. I'm a little confused as to why.
MessageBox.Show(Keyboard.FocusedElement.ToString());
Keyboard.Focus(DefaultElement);
EDIT::::
I just placed this in my onloaded event of my user control. It seems to work but can anyone see any issues that might arrise at this priority level. I.E a circumstance when the action will never run?
Dispatcher.BeginInvoke(
DispatcherPriority.ContextIdle,
new Action(delegate()
{
Keyboard.Focus(DefaultElement);
}));
It seems that this wpf the you have to implement a workaround on a case by case basis. The solution that seemed to work best, most of the time for me was to insert the focus code inside the dispatcher when OnVisible was changed. This sets the focus not only when the View/Usercontrol loads but also if you a changing Views by way of Visibility. If you Hide and then Show a ContentControl that is mapped to your ViewModels then the Loaded event won't fire and you'll be forced to Mouse input, or tabbing (Not so good if you want to navigate your app with a remote control).
VisibilityChanged will always fire however. This is what I ended up with for my listbox.
private void ItemsFlowListBox_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue == true)
{
Dispatcher.BeginInvoke(
DispatcherPriority.ContextIdle,
new Action(delegate()
{
ItemsFlowListBox.Focus();
ItemsFlowListBox.ScrollIntoView(ItemsFlowListBox.SelectedItem);
}));
}
}
I had the same symptom for a WPF UserControl hosted in a Winforms application. Just wanted to note I was about to try this solution when I found a normal TabIndex in the Winforms app fixed it
Per How to set which control gets the focus on application start
"The one with the minimum tab index automatically gets the focus
(assuming the TabStop property is set to true). Just set the tab
indices appropriately."
It's a tricky one with no easy answer. I'm currently doing this, although I'm not sure I like it:
public MyView()
{
InitializeComponent();
// When DataContext changes hook the txtName.TextChanged event so we can give it initial focus
DataContextChanged +=
(sender, args) =>
{
txtName.TextChanged += OnTxtNameOnTextChanged;
};
}
private void OnTxtNameOnTextChanged(object o, TextChangedEventArgs eventArgs)
{
// Setting focus will select all text in the TextBox due to the global class handler on TextBox
txtName.Focus();
// Now unhook the event handler, since it's no longer required
txtName.TextChanged -= OnTxtNameOnTextChanged;
}
And in case you're wondering what the global class handler does, it's this:
protected override void OnStartup(StartupEventArgs e)
{
...
// Register a global handler for this app-domain to select all text in a textBox when
// the textBox receives keyboard focus.
EventManager.RegisterClassHandler(
typeof (TextBox), UIElement.GotKeyboardFocusEvent,
new RoutedEventHandler((sender, args) => ((TextBox) sender).SelectAll()));
which auto selects TextBox text when receiving keyboard focus.
It is need to realize UI settings system - loading/saving some properites of UI elements (which can be modified by user in runtime) from/into persistent storage. For example:
DevExpress grid control - columns width's, visibility, summary area and so on (this control has set of methods pairs like RestoreLayoutFrom/SaveLayoutTo, but SaveLayoutToStream(Xml) doesnt work in grid.Unloaded handler - when grid is disconnected from PresentationSource)
grid rows/columns, which widths/heights can be adjusted by user via GridSplitter
sizeable popup controls
It is easy to set up controls properties from settings storage after controls loading/initializing/etc, but how catch the moment before controls unloading (when they still remains in visual tree) in order to retrieve their settings for saving?
Short description
I intend to create singleton - UISettingsManager, which inside has a Dictionary with pairs of [element Uid, element settings data]. In visual container (Window, UserControl) this manager can be used in a way like this:
public partial class PageHeader : UserControl
{
public PageHeader()
{
InitializeComponent();
UISettingsManager.RestoreSettings(myGridControl);
UISettingsManager.RestoreSettings(myPopup);
}
}
myGridControl & myPopup has unique Uid's (in application scope), so UISettingsManager can retrieve their settings from inner dictionary & apply it to the controls; of course UISettingsManager knows, how to work with some different types of controls.
But when it is the right moment to store settings of controls, which container is Window or UserControl?
I would use the Window's Closing event.
public class MyWindow : Window
{
public MyWindow()
{
this.Closing += new System.ComponentModel.CancelEventHandler(MyWindow_Closing);
}
void MyWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// Save what I want to here
}
}
This would be the safest bet, because you will always, at some point, close the window.
However, there may be alternatives, including the Unloaded event for a user control.