How can I change the selection in an unfocused textbox? - wpf

I have seen this question:
How to keep WPF TextBox selection when not focused?
And have implemented the solution there, so that my textbox shows the selection, even when it does not have focus.
However, when I change the selection start or length, nothing changes visually in the textbox. Also, when I scroll the textbox programatically and it does not have focus, the selection brush does not move with the text as it scrolls.

If you define a separate focus scope in XAML to maintain the selection (see StackPanel below) and you set the focus in the TextBox once (in this case when the Window opens using FocusManager.FocusedElement) then you should see your selection change programatically.
Here is some sample code to get you started:
<Window x:Class="RichTextFont2.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Main Window"
Height="400" Width="400"
FocusManager.FocusedElement="{Binding ElementName=myTextBox}"
FontSize="20">
<DockPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox x:Name="myTextBox"
Grid.Row="0"
Text="Text that does not loose selection."
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto">
</TextBox>
<StackPanel Grid.Row="1" FocusManager.IsFocusScope="True">
<Button Content="Select Text" Click="Button_Click_MoveTextBox"/>
</StackPanel>
</Grid>
</DockPanel>
</Window>
Here is some code to handle the button click event:
private void Button_Click_MoveTextBox(object sender, RoutedEventArgs e)
{
if (myTextBox.SelectionStart >= myTextBox.Text.Length)
{
myTextBox.SelectionStart = 0;
}
else
{
myTextBox.SelectionStart += 9;
}
myTextBox.SelectionLength = 6;
myTextBox.LineDown();
}

Related

Capturing name of StackPanel from Drop event

Within WPF I have the following XAML code:
<Page x:Class="com.MyCo.MyProj.Pages.Configuration.ManageLinkage.MasterLinkage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:com.MyCo.MyProj.Pages.Configuration.ManageLinkage"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="MasterLinkage">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TabControl TabStripPlacement="Top" Background="Transparent">
<TabItem Header="Import">
<ListBox Margin="0,5,0,0" Name="lbxImportItems" HorizontalAlignment="Left" VerticalAlignment="Top" Width="110" Background="Transparent"
PreviewMouseLeftButtonDown="lbxImportItems_PreviewMouseLeftButtonDown" >
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Name="DBImport">
<Image Source="/Images/DBImport25px.png" VerticalAlignment="Center" HorizontalAlignment="Center"></Image>
<TextBlock Text="Database" Foreground="AntiqueWhite"/>
</StackPanel>
<StackPanel Orientation="Vertical" Name="CSVImport">
<Image Source="/Images/CSVImport25px.png" VerticalAlignment="Center" HorizontalAlignment="Center"></Image>
<TextBlock Text="CSV Import" Foreground="AntiqueWhite"/>
</StackPanel>
</ListBox>
</TabItem>
</TabControl>
<Canvas x:Name="cnvsLinkScreen" AllowDrop="True" Grid.Column="1" Background="Transparent" Drop="cnvsLinkScreen_Drop" DragOver="cnvsLinkScreen_DragOver" ></Canvas>
</Grid>
The code for capturing the event is here:
private void cnvsLinkScreen_Drop(object sender, DragEventArgs e)
{
Canvas parent = (Canvas)sender;
object data = e.Data.GetData(typeof(string));
StackPanel objIn = (StackPanel)e.Data;
...
}
The drag and drop work great, the event method created the image in the canvas. However, I want to capture the Name="" from the StackPanels which are dropped.
I found the Name buried super deep in the "DragEventArgs e" object. I was think that there should be a way to cast the object (or the object within that object) as a StackPanel to easily work with it. The above code does not convert the StackPanel object( it's not at the root or the child object; I tried both) so it exceptions on "StackPanel objIn = (StackPanel)e.data;"
How do I either translate the incoming object to a StackPanel or how do I access the Name attribute from the Stackpanel?
I got it. I was close with the translation. To translate / typecast the object to what you are working with I needed to use the following line:
StackPanel objIn = (StackPanel)(e.Data.GetData(typeof(StackPanel)));
Which is slightly different than above.

how to set focus on a textbox or passwordbox

how to set focus on this when i log in to my application ,when log in window will open i want to type the password on this without using mouse
<PasswordBox x:Name="passwordbox" Grid.Row="1" Grid.Column="1" Margin="5,35,5,5" Width="280" Height="27" app:PasswordBoxAssistant.BindPassword="true" app:PasswordBoxAssistant.BoundPassword="{Binding TechUserModel.UserId,Mode=TwoWay,ValidatesOnDataErrors=True,UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" VerticalAlignment="Center">
I have tried various solutions for this scenario and the most effective that I have found is using FocusManager.FocusedElement:
<Window x:Class="StackOverflow.Test"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Test" Height="300" Width="300"
FocusManager.FocusedElement="{Binding ElementName=Box}">
<Grid>
<TextBox x:Name="Box"/>
</Grid>
</Window>
SOLUTION:
passwordbox.Focus();
or in .xaml file include the following in the element as its attributes.
FocusManager.FocusedElement="{Binding ElementName=passwordbox}">
NOTE:
If you want to decide which control to give focus to when the form first appears, put the code in the Loaded event.
Loaded += (o, e) => {
passwordbox.Focus();
};

Set ContentControls Content Property from codebehind throws exception 'value does not fall in range'

I got following xaml binding scenario working in WPF. Define UIElements in Grid's ressources. Bind those static resources to a ToggleButton's Tag property. On toggle button click assign the Tag property to the Content property of ContentControl.
<Grid>
<Grid.Resources>
<TextBlock x:Key="t1"
Grid.Row="1"
Text="Text1" />
<TextBlock x:Key="t2"
Grid.Row="1"
Text="Text2" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<ToggleButton Tag="{StaticResource t1}"
Margin="10"
Click="ButtonBase_OnClick"
Content="T1" />
<ToggleButton Tag="{StaticResource t2}"
Margin="10"
Click="ButtonBase_OnClick"
Content="T1" />
</StackPanel>
<ContentControl x:Name="cc"
Grid.Row="1" />
</Grid>
The toggle button click just assigns the Tag value to the Content property.
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
cc.Content = ((FrameworkElement)sender).Tag;
}
While this works in almighty WPF it is not possible in WinRT. WinRT complains with an ArgumentException 'Value does not fall within the expected range.'. I have no clue why?
For testing purposes I tried a direct assignment in the event handler, Which worked as expected:
cc.Content = new TextBlock { Text = "Text1" };
To make it even more bizarre I tried this one in WinRT:
<ContentControl x:Name="cc"
Content="{StaticResource t1}"
Grid.Row="1" />
Result: It works in the designer, but fails at runtime. Even more clueless about that.
First of all what does the ArgumentException is trying to tell me? Second why is it working in WPF? What about the discrepancy between runtime and VS designer?
In Win RT/Windows 8 Store Apps, the Content Control cannot contain an element that is already present in the view somewhere else. As it exists in Grid.Resources, it cannot be added to ContentControl.
I suggest making a DataTemplate instead in the resources:
<Grid>
<Grid.Resources>
<DataTemplate x:Key="t1">
<TextBlock Text="Text1" />
</DataTemplate>
...
And in the button click something like:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var dataTemplate = ((FrameworkElement)sender).Tag as DataTemplate;
cc.Content = dataTemplate.LoadContent() as FrameworkElement;
}
Note: I don't have the chance to test this.

XAML: move the cursor in textbox automatically

I dont know if this works but is there any chance to move the cursor inside a Textbox automaticaly for one position(1 space bar click). For example:
I run the application and the cursor inside the Textbox moves automatically for one space bar
my textbox:
<TextBox TextChanged="Searchbox_TextChanged" x:Name="Testing" Margin="2" Grid.Row="1" Text="{Binding SearchSmthg, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" Controls:TextboxHelper.ClearTextButton="True" Controls:TextboxHelper.Watermark="Search ..."/>
use CaretIndex and FocusManager:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid FocusManager.FocusedElement="{Binding ElementName=Focustext}">
<TextBox x:Name="Focustext" Text=" " CaretIndex="1" MaxHeight="25" />
</Grid>
</Window>
Edit: add a GotFocus event handler and set CaretIndex=1 there
XAML:
<TextBox GotFocus="Testing_GotFocus"
Code Behind:
private void Testing_GotFocus(object sender, RoutedEventArgs e)
{
//make sure your Textbox is not empty..
Testing.CaretIndex = 1;
}

WPF add header to ListBox so it scrolls like DataGrid

I'm trying to create a layout that uses a ListBox and my custom header that looks like a ruler, but for dates (with explicit start and end dates). The goal is to have an appearance and feel similar to a DataGrid, except that the column header row would be replaced by my DateTape object. When the user scrolls horizontally, the DateTape and ListBox both scroll, but when the user scrolls vertically, only the ListBox scrolls and the DateTape stays at the top (like the column header row in the DataGrid).
So far, the best I've been able to do is as follows:
<Window x:Class="ProjectNS.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:ProjectNS"
Title="MainWindow" Height="350" Width="600">
<Window.Resources>
<DataTemplate x:Key="itemTemplate">
<my:CustomRectangle HorizontalAlignment="Left" VerticalAlignment="Top" />
</DataTemplate>
</Window.Resources>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="File" />
</Menu>
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<DockPanel>
<my:DateTape DockPanel.Dock="Top" VerticalAlignment="Top">
<my:DateTape.Dates>
<CalendarDateRange Start="10/4/2011" End="11/4/2011" />
</my:DateTape.Dates>
</my:DateTape>
<ListBox ItemTemplate="{StaticResource itemTemplate}" />
</DockPanel>
</ScrollViewer>
</DockPanel>
</Window>
The only problem I have with this solution is that the vertical scrollbar for the ListBox is at the extreme right of the control which means the user has to scroll horizontally to make the scrollbar appear. I need the scrollbar visible at all times.
I tried placing the DateTape and ListBox into a ScrollViewer, but then the DateTape scrolls out of view when scrolling vertically.
FYI - My CustomRectangle object is a UserControl that allows the user to adjust the horizontal position and width real-time to position it as desired in line with the DateTape.
I ended up having to restructure a bit. The ListBox is now an ItemsControl nested within a ScrollViewer with the vertical scroll bar hidden (not disabled). I also have an independent ScrollBar docked to the right side that is tied to the vertical scroll bar in the ScrollViewer in the code-behind. This handles the vertical scrolling. Finally, a secondary ScrollViewer contains the DateTape and the ItemsControl set to handle the horizontal scrolling.
XAML
<DockPanel x:Name="dockPanel">
<Menu DockPanel.Dock="Top">
<MenuItem Header="File" />
</Menu>
<ScrollBar x:Name="verticalScrollBar"
DockPanel.Dock="Right"
SmallChange="1"
LargeChange="3"
Scroll="verticalScrollBar_Scroll"
SizeChanged="verticalScrollBar_SizeChanged"
Style="{StaticResource scrollBarHiderStyle}"
Maximum="{Binding ElementName=listScroller, Path=ScrollableHeight}" />
<ScrollViewer x:Name="dateScroller"
VerticalScrollBarVisibility="Disabled"
HorizontalScrollBarVisibility="Auto"
DockPanel.Dock="Top">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<my:DateTape x:Name="dateTape"
DockPanel.Dock="Top"
VerticalAlignment="Top"
Dates="{Binding Source={StaticResource dateRange}}" />
<ScrollViewer x:Name="listScroller" VerticalScrollBarVisibility="Hidden" Grid.Row="1" Foreground="{x:Null}" Panel.ZIndex="1">
<ItemsControl x:Name="itemsList"
ItemTemplate="{StaticResource itemTemplate}"/>
</ScrollViewer>
</Grid>
</ScrollViewer>
</DockPanel>
C#
// this function merely sets the scroll bar thumb size
private void verticalScrollBar_SizeChanged(object sender, SizeChangedEventArgs e)
{
verticalScrollBar.Track.ViewportSize = itemsList.ActualHeight / 2;
}
// this function links the scroll bar to the scrollviewer
private void verticalScrollBar_Scroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e)
{
listScroller.ScrollToVerticalOffset(e.NewValue);
}
I tried to tie the independent ScrollBar to the scroll bar in the ItemsControl through use of a ItemsPanelTemplate, but I couldn't get that to work.

Resources