change textcolor after textbox loses focus - c#

I would like to change the textbox default textcolor to the original default color after item is added to a list.
XAML
<TextBox Name="AddLocationTextBox" Text="{Binding Path=AddLocationName, UpdateSourceTrigger=PropertyChanged}"
LostFocus="AddLocationTextBox_LostFocus" GotFocus="AddLocationTextBox_GotFocus" HorizontalAlignment="Left" Height="23" Margin="10,37,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="285">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding AddLocationCommand}" />
</TextBox.InputBindings>
</TextBox>
Code behind in View
public LocationManagerView()
{
InitializeComponent();
AddLocationTextBox.Foreground = Brushes.Gray;
}
private void AddLocationTextBox_GotFocus(object sender, RoutedEventArgs e)
{
AddLocationTextBox.Text = string.Empty;
AddLocationTextBox.Foreground = Brushes.Black;
}
private void AddLocationTextBox_LostFocus(object sender, RoutedEventArgs e)
{
AddLocationTextBox.Foreground = Brushes.Gray;
}
ViewModel
public RelayCommand AddLocationCommand { get; private set; }
private void AddLocation()
{
if ( AddLocationName != null)
{
Locations.Add(new Location()
{
Name = AddLocationName,
});
AddLocationName = "Enter New Location";
Keyboard.ClearFocus();
////change textcolor to gray////
}
else
{
return;
}
}
It's after AddLocationName is set again to "Enter New Location" I want to change the textcolor back to gray.
Looks like the Keyboard.ClearFocus() doesn't call the LostFocus method in the View.
Any Idea how I make this work?

If you just want to change the foreground of your TextBox to gray, instead of tying to force AddLocationTextBox to lose it's focus, you should change the foreground manually (i.e. use AddLocationTextBox.Foreground = Brushes.Gray instead of Keyboard.ClearFocus()).
If you're looking for a way to force currently focused element to lose focus, then you can use below code instead of Keyboard.ClearFocus() :
UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;
elementWithFocus.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));

Related

Get TextBlock inside Button

I have a Button with a TextBlock embedded inside. When the Button is clicked, I want to be able to fetch the TextBlock inside it and modify it's members.
Here is how my button is setup:
<Button Click="Select_Click" Style="{StaticResource ButtonStyle}" HorizontalAlignment="Left" Padding="0,20,20,20">
<TextBlock Text="My text" FontSize="20" Style="{StaticResource TextBlockStyle}"/>
</Button>
In my code behind I want to be able to access the embedded TextBlock:
public void Select_Click(object sender, RoutedEventArgs e)
{
// Get the `TextBlock` from `sender` here
}
I've taken a look at the visual tree of the Button but I'm not seeing the TextBlock. I called GetVisualChildren() on the Button but I only see a Grid and no way to get to the Textblock.
The content of the Button is stored in its Content property and in your case, the TextBlock is the content of the Button.
public void Select_Click(object sender, RoutedEventArgs e)
{
Button button = (Button)sender;
TextBlock textBlock = (TextBlock)button.Content;
}
Just do some casting and it's pretty simple
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Establish_handlers();
}
void Establish_handlers()
{
Mybutton.Click += Mybutton_Click;
}
private void Mybutton_Click(object sender, RoutedEventArgs e)
{
Button clicked_button = (Button)sender;
TextBlock desired_text = (TextBlock)clicked_button.Content;
Textbox_Show_Button_Content.Text = desired_text.Text;
}
}
<StackPanel>
<Button x:Name="Mybutton">
<TextBlock>Hello</TextBlock>
</Button>
<TextBox x:Name="Textbox_Show_Button_Content"></TextBox>
</StackPanel>

Slider control is not working properly

I want to change textblock value depending on the slider value each time I change it. But it shouldn't be done in XAML, because I want to make manipulations over return data. But the text in the textblock is not changed. Where is the problem?
My XAML is:
<Slider x:Name="slider" Value="0.2" SmallChange="0.1" Minimum="0" Maximum="10"
HorizontalAlignment="Left" Margin="26,208,0,0" VerticalAlignment="Top"
Width="195" ValueChanged="Slider_ValueChanged"/>
my WP 8 page code is:
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Slider slider = e.OriginalSource as Slider;
if (slider != null)
{
sliderTBk.Text = slider.Value.ToString();
}
}
Use thi XAML without CodeBehind
<TextBlock x:Name="sliderTBk" Text="{Binding Value, ElementName=slider" />
This should work.
And dont forget to remove the ValueChanged Eventhandler.
If you have to use CodeBehind:
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (slider != null)
{
sliderTBk.Text = slider.Value.ToString();
}
}
Try this becuse i think that
Slider slider = e.OriginalSource as Slider;
hides your control x:name="slider"

How to show tooltip in code behind in WPF

How can I show a tooltip in code-behind? The code below defines my question better. Obviously I don't want the code to check for mouse position etc, just how to display the tooltip.
private void UIElement_OnMouseMove(object sender, MouseEventArgs e)
{
// if mouse position equals certain coordinates show the tooltip
}
Try like this:
if (control.ToolTip != null)
{
// Main condition
if (control.ToolTip is ToolTip)
{
var castToolTip = (ToolTip)control.ToolTip;
castToolTip.IsOpen = true;
}
else
{
toolTip.Content = control.ToolTip;
toolTip.StaysOpen = false;
toolTip.IsOpen = true;
}
}
The Main condition necessary, because ToolTip for Control can be set in two approaches:
First approach
<Button Name="TestButton"
ToolTip="TestToolTip" />
This approach is most common. In this case, the content of the ToolTip will object and not type of ToolTip.
Second approach
<Button Name="TestButton"
Content="Test">
<Button.ToolTip>
<ToolTip>TestToolTip</ToolTip>
</Button.ToolTip>
</Button>
Is the same as this:
<Button Name="TestButton"
Content="Test">
<Button.ToolTip>
TestToolTip
</Button.ToolTip>
</Button>
In this case, the Content type of ToolTip will be Tooltip. Note that in the second case, the object automatically fills ToolTip object on line TestToolTip, hence this approach will work a bit slower.
Therefore, this check is needed to avoid an exception when we try to assign to the ToolTip the content of the ToolTip type here:
toolTip.Content = control.ToolTip;
Below is a full example:
XAML
<Grid>
<Button Name="TestButton"
Width="100"
Height="25"
Content="Test"
ToolTip="TestToolTip" />
<Button Name="ShowToolTip"
VerticalAlignment="Top"
Content="ShowToolTip"
Click="ShowToolTip_Click" />
</Grid>
Code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ShowToolTip_Click(object sender, RoutedEventArgs e)
{
var toolTip = new ToolTip();
if (TestButton.ToolTip != null)
{
if (TestButton.ToolTip is ToolTip)
{
var castToolTip = (ToolTip)TestButton.ToolTip;
castToolTip.IsOpen = true;
}
else
{
toolTip.Content = TestButton.ToolTip;
toolTip.StaysOpen = false;
toolTip.IsOpen = true;
}
}
}
}

Conditional textboxes with slider binding

I have three texboxes and one slider which changes their Text properties. What i have to do is to bind slider's value property with Text textbox property but in a specific way. When one of textboxes are activated(gotfocused) i need slider to change its Text property. And only that one. I have binded it so far but when i move the slider all textboxes are updated.
Any ideas?
I was reading about converters, but i don't see how to implement it within my program.
http://forums.create.msdn.com/forums/t/95548.aspx here you have got code of my slider and textblock.
What about simply changing the active binding when a textbox receives focus:
Code Behind:
private Binding _activeBinding;
private TextBox _activeTextbox;
private TextBox ActiveTextBox
{
get { return _activeTextbox; }
set
{
// Check if a binding exists, initialize if one does not
if (_activeBinding == null)
{
_activeBinding = new Binding("Value");
_activeBinding.Source = this.sld;
}
if (_activeTextbox != null)
{
// Clear the binding
_activeTextbox.ClearValue(TextBox.TextProperty);
}
_activeTextbox = value;
if (_activeTextbox != null)
{
// Set the new binding
_activeTextbox.SetBinding(TextBox.TextProperty, _activeBinding);
}
}
}
private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
this.ActiveTextBox = sender as TextBox;
}
XAML:
<Grid>
<StackPanel>
<TextBox GotFocus="TextBox_GotFocus">1</TextBox>
<TextBox GotFocus="TextBox_GotFocus">2</TextBox>
<TextBox GotFocus="TextBox_GotFocus">3</TextBox>
<Slider x:Name="sld"></Slider>
</StackPanel>
</Grid>

How do I know that a Silverlight control has been displayed?

I have a list box displaying the names of help topics which can be added to and the names of the topics changed. Originally it was just displaying strings, but to get the inline editing working I changed it to use a custom type consisting of a string and an InEdit property so the UI can determine whether to display the TextBlock or TextBox:
XAML:
<ListBox ItemsSource="{Binding HelpTopics, Mode=TwoWay}"
SelectedValuePath="Description"
SelectedValue="{Binding SelectedPageId, Mode=TwoWay}"
SelectionChanged="ListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Description, Mode=TwoWay}"
VerticalAlignment="Center"
MouseLeftButtonUp="TopicTextBlock_MouseLeftButtonUp"
Visibility="{Binding InEdit, Converter={StaticResource boolToVisibilityConverter}, ConverterParameter=contra}"/>
<TextBox Text="{Binding Description, Mode=TwoWay}"
Visibility="{Binding InEdit, Converter={StaticResource boolToVisibilityConverter}, ConverterParameter=pro}"
LostFocus="EditTopicTextBox_LostFocus"
HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Margin="5" Content="Add Topic" Command="{Binding AddTopicCommand}"/>
HelpTopics is an ObservableCollection<EditableHelpTopic>.
SelectedPageId is a string.
boolToVisibilityConverter is a converter that does what it says.
What works:
Adding a topic creates a new item and adds it to the list and put the item in to edit mode.
Double clicking on an existing item puts that item into edit mode sets the focus to the TextBox and selects all the text so it can be overwritten.
When the TextBox loses focus the edit is saved and the display returns to the TextBlock.
What doesn't work:
When a new topic is added the TextBox should have focus and the text selected so the user can enter a new name.
So my question is is there a point in the code or an event where I know that the TextBox has been created and is visible so I can set focus and select its contents. I've tried hooking into the SelectionChanged event but when that fires the TextBox hasn't yet been displayed. I also added an event to the OnAddTopicExecute method in the view model which I handled in the view, but again that fired before the TextBox was visible.
Below is the code that supports the above XAML. I've tried to cut it down, but there still seems to be a lot of it, so you can skip this if you're not interested ;)
Code behind:
private DateTime lastClickTime = DateTime.MinValue;
private Point lastClickPosition;
private void TopicTextBlock_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
UIElement element = sender as UIElement;
if ((DateTime.Now - this.lastClickTime).TotalMilliseconds > 300)
{
this.lastClickPosition = e.GetPosition(element);
this.lastClickTime = DateTime.Now;
}
else
{
Point position = e.GetPosition(element);
if (Math.Abs(this.lastClickPosition.X - position.X) < 4 && Math.Abs(this.lastClickPosition.Y - position.Y) < 4)
{
var textBlock = sender as TextBlock;
var editableHelpTopic = textBlock.DataContext as EditableHelpTopic;
editableHelpTopic.InEdit = true;
var parent = textBlock.Parent as Grid;
TextBox textBox = parent.Children.First(c => c.GetType() == typeof(TextBox)) as TextBox;
textBox.Focus();
textBox.SelectAll();
}
}
}
private void EditTopicTextBox_LostFocus(object sender, RoutedEventArgs e)
{
var textBox = sender as TextBox;
var editableHelpTopic = textBox.DataContext as EditableHelpTopic;
editableHelpTopic.InEdit = false;
if (!textBox.Text.Equals(editableHelpTopic.Description))
{
this.editViewModel.RenameTopic(textBox.Text);
}
}
View Model:
public EditViewModel()
{
...
this.AddTopicCommand = new DelegateCommand(this.OnAddTopicExecute, this.OnAddTopicCanExecute);
...
}
where DelegateCommand is an implemetation of ICommand.
private void OnAddTopicExecute(object parameter)
{
var newTopic = new EditableHelpTopic
{
Description = "NewTopic",
InEdit = true
};
this.HelpTopics.Add(newTopic);
this.SelectedPageId = newTopic.Description;
}
Definitions:
public class EditableHelpTopic : INotifyPropertyChanged
{
public bool InEdit { ... }
public string Description { ... }
}
It turned out to be simpler than I thought.
I just needed to add a Loaded event handler to the TextBox:
private void EditTopicTextBox_Loaded(object sender, RoutedEventArgs e)
{
var textBox = sender as TextBox;
var editableHelpTopic = textBox.DataContext as EditableHelpTopic;
if (editableHelpTopic.InEdit)
{
textBox.Focus();
textBox.SelectAll();
}
}

Categories

Resources