I have a silverlight 4 application which has some text boxes that are as wide as the page.
When there is a validation error, a popup is displayed when the user clicks in the control.
The problem is - it only shows the popup for these long text boxes to the left of the text box. It wont go above or below and so as a consequence, most of the popup is displayed out of the page so its chopped off.
I know that I can re-template the text box and try to adjust the popup myself, but before doing that I just wanted to check to see if someone knew of a simple property or something that I can use to prevent that from happening?
Cheers
Rod.
Good question. I guess I would try to solve this via a somewhat "intelligent" AttachedProperty.
Pseudo code ahead:
<TextBox ... my:PopupUtils.KeepPopupWithinScreen="True"/>
And the (pseudo c#) code:
public static class PopupUtils
{
// remember: pseudo code, just to get the idea
static AttachedProperty KeepPopupWithinScreen = type: bool, default: false,
onChanged: HandleKeepPopupWithinScreenChanged;
private static void HandleKeepPopupWithinScreenChanged(
DependencyObject obj, bool value)
{
obj.Loaded += HandleTargetElementLoaded;
}
private staic void HandleTargetElementLoaded(object sender, ...)
{
var popup = VisualTreeHelper.GetDecendantOfType<Popup>(sender);
if ( popup != null )
{
var offsetController = new OffsetController();
offsetController.SetBinding(ObservedOffsetProperty,
new Binding("HorizontalOffset"){Source=popup});
offsetController.ControlledTarget = popup;
//now to prevent garbageCollection...
SetAttachedOffsetController(popup,offsetController);
}
}
public static AttachedProperty AttachedOffsetController = type:OffsetController;
}
I do this sometimes, so this pattern is actually working quite nicely. Maybe it feels a bit "unnatural" at first.
Just letting you know of the solution I used to this problem.
It was another StackOverflow question which I have lost the reference to so I do apologise for not referencing it properly, but the problem is caused by the Text Box and other control styles having a fixed position of to the side of the control when displaying the validation message.
I simply had to create a copy of the style and have the popup appear at the top of the controls instead of beside it.
Problem Solved.
Cheers
Rod.
Related
I want to make my app to be accessible (make my app exposed for screen readers, which are UI automation client, like "Narrator").
I got some ContentControl that when it got keyboard focus, I'm showing a tooltip (taking it from the Tooltip property of this ContentControl). It's a control that used in many ways, for example it can be used like that:
the Content of this ContentControl is a question mark icon image, and the ToolTip is the help text...
Here is a concept code:
class AutoTooltipOnFocus : ContentControl
{
public AutoTooltipOnFocus()
{
this.GotKeyboardFocus += OnGotKeyboardFocus;
}
private void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs keyboardFocusChangedEventArgs)
{
bool automationListens = AutomationPeer.ListenerExists(AutomationEvents.AutomationFocusChanged);
if (automationListens)
{
// don't show tooltip because GetNameCore of MyAutoPeer will represent the ToolTip value
return;
}
// show tooltip (by reading the ToolTip value of this AutoTooltipOnFocus)
}
protected override AutomationPeer OnCreateAutomationPeer()
{
return new MyAutoPeer(this);
}
}
class MyAutoPeer : FrameworkElementAutomationPeer
{
private AutoTooltipOnFocus _owner;
public MyAutoPeer(AutoTooltipOnFocus owner)
: base(owner)
{
}
protected override string GetNameCore()
{
return GetToolTipValueFromOwner();
}
private string GetToolTipValueFromOwner()
{
// just for the simplicity of the example, I return this:
return ToolTipService.GetToolTip(_owner).ToString();
}
}
Narrator, for example, reads the textual representation of the Content (let's say the property AutomationProperties.Name of the image is set to "help icon") and then says "Tooltip: some help text".
I don't want to count on the tooltip been read by all the screen readers (correct me if I'm wrong thinking some of them don't read Tooltips), so I made my GetNameCore return the ToolTip content so that I know it would be read necessarily, and I prevented the appearance of the tooltip (at OnGotKeyboardFocus handler) in order to prevent double reading of the same help text.
The problem is that: I thought that asking AutomationPeer.ListenerExists(AutomationEvents.AutomationFocusChanged) tells me that UI automation is listening to my app, but when narrator is not running, this method returns "false" and the rest of the times it returns true, so no tooltip appears when no one using screen reader, so I need to know what is the way to indicate whether UI automation client is running and listening to my app.
Maybe there is a workaround by adding some code to my custom AutomationPeer.
Thanks for giving your time!
I am using ToolStripDropDown to create a autocomplete popup when user type in a textbox. I want the popup is only displayed at bottom right of the textbox.
But when the textbox's position is near the right or bottom edge of the screen, popup will display at other position.
Can anyone help me?
Code in derived class from ToolStripDropDown:
public void Show(Presenters.IMainView c, Point position)
{
base.Show(c as Control, position, ToolStripDropDownDirection.BelowRight);
}
Code in main view:
private void TextBoxAutocomplete_TextChanged(object sender, EventArgs e)
{
_mPopup.Show((IMainView)this, ((TextBox)sender).Location);
}
I want the popup behave like a normal form, which position is not restricted by screen or working area bounds, but not steal focus from parent form
I decided to use another and easier approach. Instead of using a derived class of ToolStripDropDown, I use a class derived from UserControl, make it not steal focus from it's parent (see this question)
I have a numericupdown control on a winform and I noticed while testing that not only you have the option of changing the value by pressing up and down key but also simply entering the values from your keyboard.
I don't want that. I only want the user to be able to change the numericupdown's value only by clicking the up and down buttons within the box.
So far I simply can't find a solution.
Does anyone know how to do this?
To disable user from editing, set Readonly property to true.
updown.ReadOnly = true;
For more tailoring, you may refer this answer.
Sounds bad for user experience depending on the range of values you are allowing.
To do this you need to create a control with inherits from NumericUpDown and override the OnKeyPress/OnKeyDown methods.
Using updown.ReadOnly = True; does not work for me. It seems to be a reoccuring bug.
But catching any changes and then undo it does. For this bind the function updown_ValueChanged() to the updown.ValueChanged attribute.
decimal spin = 1;
private void updown_ValueChanged(object sender, EventArgs e)
{
if (updown.ReadOnly)
{
if (updown.Value != spin)
{
updown.Value = spin;
}
}
else spin = updown.Value;
}
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'm fairly new to Silverlight but experienced in web development, and I'm finding myself highly annoyed with Silverlight's default combobox. It seems to be lacking any concept of use for regular data entry. Primarily I'm wishing it would function like an HTML select box, where you can hit the drop down, then type a letter and it takes you down to the first item with that letter. Is there an easy way I'm missing to make it function like this, or a third party control that can do this?
Thanks!
You could write an attached behavior to provide this functionality. The problem is that the items in a ComboBox in Silverlight aren't always strings. They may be entire controls that the user has templated as the ItemTemplate. If you know yours are going to be string you can implement a Behavior<ComboBox> to attach to the KeyDown event and select the correct one.
public class HTMLSelectBehavior : Behavior<ComboBox>
{
protected override void OnAttached()
{
AssociatedObject.KeyDown += OnKeyDown;
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
SelectedItem = AssociatedObject.ItemsSource
.FirstOrDefault(i => i.ToString().BeginsWith((char)e.Key));
}
}
This is off the top of my head so it may not be exactly right and definitely lacks many safety checks, but it should give you an idea.