C# Display a tooltip on disabled textbox (Form) - c#

I am trying to get a tooltip to display on a disabled textbox during a mouse over. I know because the control is disabled the following won't work:
private void textBox5_MouseHover(object sender, EventArgs e)
{
// My tooltip display code here
}
How can I get the tooltip to display on a mouse over of a disabled control?
Many thanks

MouseHover wont fire if control is disabled. Instead you can check in Form MouseMove event whether you hover the textbox
public Form1()
{
InitializeComponent();
textBox1.Enabled = false;
toolTip.InitialDelay = 0;
}
private ToolTip toolTip = new ToolTip();
private bool isShown = false;
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if(textBox1 == this.GetChildAtPoint(e.Location))
{
if(!isShown)
{
toolTip.Show("MyToolTip", this, e.Location);
isShown = true;
}
}
else
{
toolTip.Hide(textBox1);
isShown = false;
}
}

Late to the party, but had the same problem and found a better solution: you can just wrap your TextBox in another Item and put a ToolTip on it like:
<Grid ToolTip="ToolTip to display">
<TextBox IsEnabled="False" Text="Text to display" />
</Grid>

You can also drag a ToolTip object from the Toolbox in designer onto the form.
Then in the code you just call SetToolTip() and pass in the button or text box etc. you want the tool tip to assign to and the text you want it to show.
myToolTip.SetToolTip(myTextBox, "You just hovered over myTextBox!");

Related

How to use Popup control to show a view?

I need to show a view on a click of a button. This is the code for the event Click
private void Button_Click(object sender, RoutedEventArgs e)
{
Button s = sender as Button;
//some stuff needed to recognise which button was pressed
myPopup.PlacementTarget = s;
myPopup.Placement = System.Windows.Controls.Primitives.PlacementMode.Top;
myPopup.IsOpen = true;
}
this is the element defined in xaml
<Popup IsOpen="False" StaysOpen="True" Name="myPopup">
<view:myCustomView />
</Popup>
I have 2 problem with this.
1- The background of my view is black, even if i didn't set it (i think it should be transparent?)
2- When i click anywhere inside the Popup, this simply disappear
Which is the proper way to show my view? I don't want to bind anything of the ViewModel that own the button to this new view, which has his own viewmodel
Note that on the event Button_Click i will send some parameters to the ViewModel of myCustomView that will change some of its functionality (that's why i need to create a new instance of the view every time the Button_Click event is fired)
EDIT 1: Thanks to the answer of EdPlunkett i was able to solve the problem with the background. I just need to set AllowsTransparency="True"
EDIT2:
I defined my Popup via Code Behind as suggested, so my code now is:
private void Button_Click(object sender, RoutedEventArgs e)
{
Button s = sender as Button;
System.Windows.Controls.Primitives.Popup popup = new System.Windows.Controls.Primitives.Popup();
popup.AllowsTransparency = true;
popup.Child = new myCustomView();
popup.PlacementTarget = s;
popup.Placement = System.Windows.Controls.Primitives.PlacementMode.Top;
popup.IsOpen = true;
popup.StaysOpen = true;
}
The problem is, that when i click inside any of the controls defined inside myCustomView, the Popup lose the focus and close.
I suspect that the Popup is defined inside another Popup like for example the dropdown of a ComboBox, right?
You could try to create the Popup element programmatically in the click event handler:
private void Button_Click(object sender, RoutedEventArgs e)
{
Button s = sender as Button;
System.Windows.Controls.Primitives.Popup popup = new System.Windows.Controls.Primitives.Popup();
popup.AllowsTransparency = true;
popup.Child = new myCustomView();
//some stuff needed to recognise which button was pressed
popup.PlacementTarget = s;
popup.Placement = System.Windows.Controls.Primitives.PlacementMode.Top;
popup.IsOpen = true;
popup.StaysOpen = true;
}
This should let you click within the pop up view without the Popup being closed. Make sure that the view has a Background set:
popup.Child = new myCustomView() { Background = Brushes.White };
I tried your solution, and while it's true that the situation is slightly better, i still have the closing problem. I can click inside the Popup without this being closed, but when i click inside any of the textbox that i defined inside my view, the Popup close
So set the PlacementTarget to the parent ItemsControl and then set the VerticalOffset and HorizontalOffset properties of the Popup to specify its exact location on the screen, e.g.:
private void btn_Click(object sender, RoutedEventArgs e)
{
Button s = sender as Button;
System.Windows.Controls.Primitives.Popup popup = new System.Windows.Controls.Primitives.Popup();
popup.AllowsTransparency = true;
popup.Child = new myCustomView();
//some stuff needed to recognise which button was pressed
popup.PlacementTarget = ic; //<-- "ic" is the name of the parent ItemsControl
Point p = s.TranslatePoint(new Point(0, 0), ic);
popup.VerticalOffset = p.Y;
popup.HorizontalOffset = p.X;
popup.IsOpen = true;
popup.StaysOpen = true;
}
You should adjust the values of the VerticalOffset and HorizontalOffset to fit your requirements.

Accessing a text box inside a user control

I'm having problems binding a user control. I have a main window, which with a press of a button gets my value. However when i use my user control in the main window i cant set the text box to add my value. Instead of 'text' i want my user control text box? I have tried to declaring the text box but no luck any ideas?
private void button1_Click(object sender, RoutedEventArgs e)
{
text.Clear();
text.AppendText( tc.FTemp + "F");
}
<my:UserControl1 Height="172" HorizontalAlignment="Left" Margin="12,197,0,0" VerticalAlignment="Top" Width="151" Loaded="userControl11_Loaded" />
Two solutions:
Create a public property in your user control
Use 'Controls.Find' (the slowest, but easiest way)
public Form1()
{
InitializeComponent();
Control[] control = userControl1.Controls.Find("textbox1", true);
control.First().Text = "Found!";
}

Popup with StaysOpen to false is not closing

I have a telerik grid view and when I right click the header, I'm showing a with a ListBox inside containing the list of columns.
The item template is redefined to show a check box so I can set the column visible or not.
I can also drag/drop columns to reorder them.
So here is how I create my Popup:
var view = new ColumnsOrderer.ColumnsOrderer
{
DataContext = new ColumnsOrderer.ViewModelColumnsOrderer(Columns)
};
var codePopup = new Popup
{
Child = view,
MaxHeight = 400,
StaysOpen = false,
Placement = PlacementMode.Mouse
};
codePopup.IsOpen = true;
Now everything seems to work correctly, but it's not.
If I set columns visible or hidden and then click outside the popup, it closes correctly.
Though if I drag an item to reorder it, the popup seems to lose focus and then it won't close if I click outside the popup. I have to click back in the list box inside the popup and then it closes by clicking outside.
Here is my drag/drop events:
public ColumnsOrderer()
{
InitializeComponent();
InitialiazeListBoxDragDrop();
}
private void InitialiazeListBoxDragDrop()
{
var itemContainerStyle = new Style(typeof(ListBoxItem));
itemContainerStyle.Setters.Add(new Setter(AllowDropProperty, true));
itemContainerStyle.Setters.Add(new EventSetter(PreviewMouseMoveEvent, new MouseEventHandler(OnMouseMove)));
itemContainerStyle.Setters.Add(new EventSetter(DropEvent, new DragEventHandler(OnDrop)));
listColumns.ItemContainerStyle = itemContainerStyle;
}
void OnMouseMove(object sender, MouseEventArgs e)
{
if (e.OriginalSource is CheckBox || e.LeftButton == MouseButtonState.Released)
return;
if (sender is ListBoxItem)
{
var draggedItem = sender as ListBoxItem;
draggedItem.IsSelected = true;
DragDrop.DoDragDrop(draggedItem, draggedItem.DataContext, DragDropEffects.Move);
}
}
void OnDrop(object sender, DragEventArgs e)
{
if (!(sender is ListBoxItem))
return;
}
An interesting thing is that if I remove the OnDrop handler, the problem is not there.
I tried many ways to set back the focus to the popup, but it's not working.
Could anyone help me on that?
How about trying to re-focus your Popup control after the drag and drop operation?
void OnDrop(object sender, DragEventArgs e)
{
if (!(sender is ListBoxItem))
return;
codePopup.Focus();
}

TextBox ScrollToEnd Glitches When Selecting if Text is Appeneded

I'm making a textbox to autoscroll to the end when text is added. However I wanted the option to not scroll the textbox when the mouse is over the textbox. I've done all that, but when the user selects text and the textbox receives an event to update the text, everything goes haywire.
Here's what I'm working with:
<TextBox Text="{Binding ConsoleContents, Mode=OneWay}" TextWrapping="Wrap"
IsReadOnly="True" ScrollViewer.VerticalScrollBarVisibility="Visible"
TextChanged="TextBox_TextChanged" MouseEnter="TextBox_MouseEnterLeave"
MouseLeave="TextBox_MouseEnterLeave" AllowDrop="False" Focusable="True"
IsUndoEnabled="False"></TextBox>
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox == null) return;
// ensure we can scroll
if (_canScroll)
{
textBox.Select(textBox.Text.Length, 0); //This was an attempt to fix the issue
textBox.ScrollToEnd();
}
}
private void TextBox_MouseEnterLeave(object sender, MouseEventArgs e)
{
TextBox textBox = sender as TextBox;
// Don't scroll if the mouse is in the box
if (e.RoutedEvent.Name == "MouseEnter")
{
_canScroll = false;
}
else if (e.RoutedEvent.Name == "MouseLeave")
{
_canScroll = true;
}
}
To further explain what haywire means, when the textbox receives and propertychanged event it sets the text and scrolls down to the end if the mouse is not hovering over it. If the mouse is hovering over it does not scroll. But if I select text and the textbox recives the propertychanged event the content gets updated, but the box does not scroll down. This is expected. The problem is that my selection then goes from where the cursor currently is to the top of the text. If I remove the cursor from the box, it continues fine but once the cursor returns, the box gets stuck at the top and cannot scroll down. I thought it might have been the cursor so I try to move it to the end but that solves nothing.
Any ideas?!
I've been ripping my hair out! Thanks!
You will need to handle the extra case of PropertyChanged event. Because the text is changed the control is updated. Because it updates it resets certain values, like cursor location and selected text and such.
You can try to temporarily save these settings like CaretIndex, SelectionStart and SelectionLength. Although I have no experience with this, so you will have to find out for yourself what values you want to keep.
You could also apply the same _canScroll check when the PropertyChanged event is triggered for the TextBox. This allows you to work with the text. But if the mouse leaves the Textbox you must wait for a new event before the latest text is shown.
You might also want to look into using IsFocused property. In my opinion it gives a nicer solution than the MouseEnter and MouseLeave event. But that's up to you of course.
Well it took all morning but here's how to do it:
<TextBox Text="{Binding ConsoleContents, Mode=OneWay}"
TextWrapping="Wrap" IsReadOnly="True" ScrollViewer.VerticalScrollBarVisibility="Visible" TextChanged="TextBox_TextChanged"
MouseEnter="TextBox_MouseEnterLeave" MouseLeave="TextBox_MouseEnterLeave" SelectionChanged="TextBox_SelectionChanged" AllowDrop="False" Focusable="True"
IsUndoEnabled="False"></TextBox>
public partial class ConsoleView : UserControl
{
private bool _canScroll;
// saves
private int _selectionStart;
private int _selectionLength;
private string _selectedText;
public ConsoleView(ConsoleViewModel vm)
{
InitializeComponent();
this.DataContext = vm;
_canScroll = true;
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox == null) return;
// ensure we can scroll
if (_canScroll)
{
// set the cursor to the end and scroll down
textBox.Select(textBox.Text.Length, 0);
textBox.ScrollToEnd();
// save these so the box doesn't jump around if the user goes back in
_selectionLength = textBox.SelectionLength;
_selectionStart = textBox.SelectionStart;
}
else if (!_canScroll)
{
// move the cursor to where the mouse is if we're not selecting anything (for if we are selecting something the cursor has already moved to where it needs to be)
if (string.IsNullOrEmpty(_selectedText))
//if (textBox.SelectionLength > 0)
{
textBox.CaretIndex = textBox.GetCharacterIndexFromPoint(Mouse.GetPosition(textBox), true);
}
else
{
textBox.Select(_selectionStart, _selectionLength); // restore what was saved
}
}
}
private void TextBox_MouseEnterLeave(object sender, MouseEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox == null) return;
// Don't scroll if the mouse is in the box
if (e.RoutedEvent.Name == "MouseEnter")
{
_canScroll = false;
}
else if (e.RoutedEvent.Name == "MouseLeave")
{
_canScroll = true;
}
}
private void TextBox_SelectionChanged(object sender, RoutedEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox == null) return;
// save all of the things
_selectionLength = textBox.SelectionLength;
_selectionStart = textBox.SelectionStart;
_selectedText = textBox.SelectedText; // save the selected text because it gets destroyed on text update before the TexChanged event.
}
}

In WPF, what is the best way to make buttons that insert special characters into multiple TextBoxes?

If I have multiple TextBoxes and other text insertion controls and I want to create some buttons that insert special characters into whichever TextBox is in focus, what is the best control for this and what properties should be set?
Requirements for the buttons:
Buttons do not steal focus when clicked.
Buttons can insert text (e.g. special characters) into any control that accepts keyboard input.
The cursor should move as if the user had entered the text on the keyboard.
If #2 is not possible, it will suffice to limit the controls to only TextBoxes.
NOTE: I do not want to make the buttons unfocusable, only such that they do not steal focus when clicked.
I'm not aware of any button that is not stealing focus when it is clicked, but in button click event handle you can return focus to previous owner. If I had to implement this I'd create an behavior that is attached to parent panel of all special textboxes and all buttons that are to insert some text.
<StackPanel>
<i:Interaction.Behaviors>
<local:TextBoxStateTracker/>
</i:Interaction.Behaviors>
<TextBox />
<Button Content="description" Tag="?" />
</StackPanel>
For sample simplicity I've put text that is to be inserted to textbox in Tag property.
public class TextBoxStateTracker : Behavior<Panel>
{
private TextBox _previouslySelectedElement;
private int _selectionStart;
private int _selectionLength;
protected override void OnAttached()
{
//after control and all its children are created find textboxes and buttons
AssociatedObject.Initialized += (x, y) =>
{
var textBoxElements = FindChildren<TextBox>(AssociatedObject);
foreach (var item in textBoxElements)
{
item.LostFocus += new RoutedEventHandler(item_LostFocus);
}
var buttons = FindChildren<Button>(AssociatedObject);
foreach (var item in buttons)
{
item.Click += new RoutedEventHandler(item_Click);
}
};
}
private void item_Click(object sender, RoutedEventArgs e)
{
if (_previouslySelectedElement == null) return;
//simply replace selected text in previously focused textbox with whatever is in tag property
var button = (Button)sender;
var textToInsert = (string)button.Tag;
_previouslySelectedElement.Text = _previouslySelectedElement.Text.Substring(0, _selectionStart)
+ textToInsert +
_previouslySelectedElement.Text.Substring(_selectionStart + _selectionLength);
_previouslySelectedElement.Focus();
_previouslySelectedElement.SelectionStart = _selectionStart + textToInsert.Length;
}
private void item_LostFocus(object sender, RoutedEventArgs e)
{
//this method is fired when textboxes loose their focus note that this
//might not be fired by button click
_previouslySelectedElement = (TextBox)sender;
_selectionStart = _previouslySelectedElement.SelectionStart;
_selectionLength = _previouslySelectedElement.SelectionLength;
}
public List<TChild> FindChildren<TChild>(DependencyObject d)
where TChild : DependencyObject
{
List<TChild> children = new List<TChild>();
int childCount = VisualTreeHelper.GetChildrenCount(d);
for (int i = 0; i < childCount; i++)
{
DependencyObject o = VisualTreeHelper.GetChild(d, i);
if (o is TChild)
children.Add(o as TChild);
foreach (TChild c in FindChildren<TChild>(o))
children.Add(c);
}
return children;
}
}
This does more or less what you described but it is far from perfect I think it is enough to get you started.
You need to do override the template of a Label and a TextBox.
requirements 1 and 2 - can be done inside the template for the Label which will act as a button.
requirement 3 - can be done inside the the template for the Textbox.
It's not easy...
you might need to learn alot of WPF styling, XAML and overriding the Control Template. maybe even creating a custom control.

Categories