I try to make the button move when I press an arrow key on the keyboard.
But what I get is that I always need to press the button with mouse to get the right focus first, and then I can move it with the left arrow key, otherwise not. However, as what I know, the KeyDown event is triggered by the Grid instead of the button.
Here is how I do it in the Code behind:
private void Panel_KeyDown(object sender, KeyEventArgs e)
{
Button source = Baffle;
if (source != null)
{
if (e.Key == Key.Left)
{
source.Margin = new Thickness(source.Margin.Left - 1, source.Margin.Top,
source.Margin.Right + 1, source.Margin.Bottom);
}
}
}
The XAML:
<Grid Name="Panel" KeyDown="Panel_KeyDown" Background="BlanchedAlmond">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Name="Baffle" Template="{StaticResource ButtonTemplate}"
Grid.Row="1" VerticalAlignment="Bottom" Margin="20" HorizontalAlignment="Center"
Width="50" Height="20"/>
</Grid>
Could anyone explain this? Thanks.
Interesting ... Not sure why, but if you want to solve it in a simple way you can use this:
public partial class MainWindow : Window
{
private Button source;
public MainWindow()
{
InitializeComponent();
source = Baffle;
source.Focus();
}
private void Panel_KeyDown(object sender, KeyEventArgs e)
{
if (source != null)
{
if (e.Key == Key.Left)
{
source.Margin = new Thickness(source.Margin.Left - 1, source.Margin.Top,
source.Margin.Right + 1, source.Margin.Bottom);
}
}
}
}
(simply give that button the focus on load,and you can move it to your heart content).
That's right - your KEYDOWN event fires only when Grid(Panel) has focus on it. But when your application starts it hasn't focus on it and will get it only when you select any control on Grid for example this button or another one. MainWindow has focus on start so just add this event handler to MainWindow KeyDown.
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" KeyDown="Panel_KeyDown">
<Grid Name="Panel" Background="BlanchedAlmond">
.....
This is because Grid by default is not focusable, so the KeyEvent is not going to work until the Grid has focus or one of the controls in the Grid FocusScope has logical focus.
You can set the Grid to Focusable and set the FocusedElement using FocusManager to the Grid and this will work
Example:
<Grid Name="Panel" KeyDown="Panel_KeyDown" Background="BlanchedAlmond" FocusManager.FocusedElement="{Binding ElementName=Panel}" Focusable="True">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Name="Baffle"
Grid.Row="1" VerticalAlignment="Bottom" Margin="20" HorizontalAlignment="Center"
Width="50" Height="20"/>
</Grid>
Related
I have a grid with some ColumnDefinitions and RowDefinitions. What I like to do is drag a control at runtime and have it snap to a given GridColumn/GridRow when the control is over that GridColumn/GridRow. I was not able to find any resources on this. Perhaps I am using the wrong key words. Thanks in advance!
You should extend Grid to handle the drop position. Let the Grid add the dropped element to the appropriate cell.
The following simple but working example shows how to enable dragging of any UIElement from a Panel such as StackPanel or Grid to the custom DrockingGrid.
The custom Grid simply overrides the relevant drag&drop overrides. It's a minimal but working example, therefore only OnDragEnter and OnDrop are overridden.
On drop, you basically have to identify the cell the element was dropped in by using the drop position from the DragEventArgs. Then remove the dropped element from its original parent container (where the drag operation has started) and then insert it into the DockingGrid. You then use Grid.Row and Grid.Column to position the element in the appropriate cell:
DockingGrid.cs
public class DockingGrid : Grid
{
private bool AcceptsDrop { get; set; }
private Brush OriginalBackgroundBrush { get; set; }
public DockingGrid()
{
this.AllowDrop = true;
}
protected override void OnDragEnter(DragEventArgs e)
{
base.OnDragEnter(e);
e.Effects = DragDropEffects.None;
this.AcceptsDrop = e.Data.GetDataPresent(typeof(UIElement));
if (this.AcceptsDrop)
{
e.Effects = DragDropEffects.Move;
ShowDropTargetEffects();
}
}
protected override void OnDragLeave(DragEventArgs e)
{
base.OnDragEnter(e);
ClearDropTargetEffects();
}
protected override void OnDrop(DragEventArgs e)
{
base.OnDrop(e);
if (!this.AcceptsDrop)
{
return;
}
ClearDropTargetEffects();
var droppedElement = e.Data.GetData(typeof(UIElement)) as UIElement;
RemoveDroppedElementFromDragSourceContainer(droppedElement);
_ = this.Children.Add(droppedElement);
Point dropPosition = e.GetPosition(this);
SetColumn(droppedElement, dropPosition.X);
SetRow(droppedElement, dropPosition.Y);
}
private void SetRow(UIElement? droppedElement, double verticalOffset)
{
double totalRowHeight = 0;
int targetRowIndex = 0;
foreach (RowDefinition? rowDefinition in this.RowDefinitions)
{
totalRowHeight += rowDefinition.ActualHeight;
if (totalRowHeight >= verticalOffset)
{
Grid.SetRow(droppedElement, targetRowIndex);
break;
}
targetRowIndex++;
}
}
private void SetColumn(UIElement? droppedElement, double horizontalOffset)
{
double totalColumnWidth = 0;
int targetColumntIndex = 0;
foreach (ColumnDefinition? columnDefinition in this.ColumnDefinitions)
{
totalColumnWidth += columnDefinition.ActualWidth;
if (totalColumnWidth >= horizontalOffset)
{
Grid.SetColumn(droppedElement, targetColumntIndex);
break;
}
targetColumntIndex++;
}
}
private void RemoveDroppedElementFromSourceContainer(UIElement droppedElement)
{
DependencyObject parent = droppedElement is FrameworkElement frameworkElement
? frameworkElement.Parent
: VisualTreeHelper.GetParent(droppedElement);
if (parent is null)
{
return;
}
switch (parent)
{
case Panel panel:
panel.Children.Remove(droppedElement);
break;
case ContentControl contentControl:
contentControl.Content = null;
break;
case ContentPresenter contentPresenter:
contentPresenter.Content = null;
droppedElement.UpdateLayout();
break;
case Decorator decorator:
decorator.Child = null;
break;
default:
throw new NotSupportedException($"Parent type {parent.GetType()} not supported");
}
}
private void ShowDropTargetEffects()
{
this.ShowGridLines = true;
this.OriginalBackgroundBrush = this.Background;
this.Background = Brushes.LightBlue;
}
private void ClearDropTargetEffects()
{
this.Background = this.OriginalBackgroundBrush;
this.ShowGridLines = false;
}
}
Usage
Use it like a normal Grid.
Now the user can drag any control into any of the predefined cells.
<local:DockingGrid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="200" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition Height="300" />
<RowDefinition />
</Grid.RowDefinitions>
</local:DockingGrid>
In the parent host of the drag&drop context for example the Window, enable/start the drag behavior:
MainWindow.xaml.cs
partial class MainWindow : Window
{
protected override void OnPreviewMouseMove(MouseEventArgs e)
{
base.OnPreviewMouseMove(e);
if (e.LeftButton == MouseButtonState.Pressed
&& e.Source is UIElement uIElement)
{
_ = DragDrop.DoDragDrop(uIElement, new DataObject(typeof(UIElement), uIElement), DragDropEffects.Move);
}
}
}
See Microsoft Docs: Drag and Drop Overview to learn more about the feature.
The short answer is to put that control inside something which fills that cell. You could just put it in that grid cell by adding it to the grid children and setting grid row and column attached properties but there is a gotcha.
A grid cell is sort of conceptual.
The grid looks at it's content, looks at it's definitions for rows and columns and works out where to put it's content using measure arrange passes.
Which is a wordy way of saying there's nothing there to drag your control into.
You need a drop target to drag drop anything into. As it's name suggests, you need some sort of a receptacle for the thing you are dragging.
Wpf, however has these things called content controls.
A button actually inherits from content control to allow it to have things like a string in it.
There is also a content control itself. Which is just kind of like a receptacle for something or other.
One of these things can be used in a given cell as a sort of a place holder. And then you have something in a cell that you can drop into.
I think if you just throw a contentcontrol in a grid without anything inside it you might have problems hit testing.
Some experimentation in a scratch project is advisable.
But basically you could have something like:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Rectangle Fill="Red"
Name="DraggAbleThing"
MouseMove="DraggAbleThing_MouseMove"
/>
<ContentControl Grid.Row="1"
Grid.Column="1"
x:Name="BottomRight"
AllowDrop="True"
>
<Rectangle Fill="Yellow"/>
</ContentControl>
</Grid>
There's a fair bit to implement in order to do drag drop but the idea here is you have something in the bottom right cell which you can drop into. You might have to set ishitestable=false on that yellow rectangle.
I'd have to implement all the drag drop methods to try it out.
If I did and drop works ok then when the contentcontrol gets draggablething dropped into it.
Set the content property of the contentcontrol to draggablething and it is now in the bottom right cell.
It will fill that cell because the grid arranges it's contents to fill whichever logical cell it decides they're "in".
I would like to present an example I wrote that is working.
In the Application I wrote I have a Grid with 4 Rows and 4 Columns.
I can place in each Cell a different UserControl that is based on a class I called
BaseDragDropUserControl:
public class BaseDragDropUserControl: UserControl
{
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.LeftButton == MouseButtonState.Pressed)
{
DataObject data = new DataObject();
data.SetData(DataFormats.StringFormat, nameof(BaseDragDropUserControl));
BaseDragDropUserControl tobemMoved = (BaseDragDropUserControl)e.Source;
int row = (int)tobemMoved.GetValue(Grid.RowProperty);
int col = (int)tobemMoved.GetValue(Grid.ColumnProperty);
data.SetData("Source", tobemMoved);
data.SetData("Row", row);
data.SetData("Col", col);
DragDrop.DoDragDrop(this, data, DragDropEffects.Move);
}
}
protected override void OnGiveFeedback(GiveFeedbackEventArgs e)
{
base.OnGiveFeedback(e);
if (e.Effects.HasFlag(DragDropEffects.Copy))
{
Mouse.SetCursor(Cursors.Cross);
}
else if (e.Effects.HasFlag(DragDropEffects.Move))
{
Mouse.SetCursor(Cursors.Pen);
}
else
{
Mouse.SetCursor(Cursors.No);
}
e.Handled = true;
}
protected override void OnDrop(DragEventArgs e)
{
base.OnDrop(e);
// If the DataObject contains string data, extract it.
if (e.Data.GetDataPresent(DataFormats.StringFormat))
{
string dataString = (string)e.Data.GetData(DataFormats.StringFormat);
if (dataString == nameof(BaseDragDropUserControl))
{
int targetRow = (int)this.GetValue(Grid.RowProperty);
int targetCol = (int)this.GetValue(Grid.ColumnProperty);
int originRow = (int)e.Data.GetData("Row");
int originCol = (int)e.Data.GetData("Col");
BaseDragDropUserControl origin = (BaseDragDropUserControl)e.Data.GetData("Source");
this.SetValue(Grid.RowProperty, originRow);
this.SetValue(Grid.ColumnProperty, originCol);
origin.SetValue(Grid.RowProperty, targetRow);
origin.SetValue(Grid.ColumnProperty, targetCol);
}
}
e.Handled = true;
}
}
The above class is the "Heavy one". It handle both the Drag and the Drop functions.
It ships data object with the origin UserControl and also intercept it when it is dropped. It switch the Grid.Row and Grid.Column values between the origin UserControl and the Target UserControl. In doing this the locations are changed.
I created 2 UsserControls.
RedUserControl and BlueUserControl:
<local:BaseDragDropUserControl x:Class="Problem10.RedUserControl"
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:Problem10"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" AllowDrop="True">
<Grid>
<Rectangle Fill="Red"/>
</Grid>
</local:BaseDragDropUserControl>
<local:BaseDragDropUserControl x:Class="Problem10.BlueUserControl"
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:Problem10"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" AllowDrop="True">
<Grid>
<Rectangle Fill="Blue"/>
</Grid>
</local:BaseDragDropUserControl>
The MainWindow is as following:
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<local:RedUserControl Grid.Row="0" Grid.Column="1"/>
<local:BlueUserControl Grid.Row="0" Grid.Column="0"/>
<local:BlueUserControl Grid.Row="0" Grid.Column="2"/>
<local:BlueUserControl Grid.Row="0" Grid.Column="3"/>
<local:RedUserControl Grid.Row="1" Grid.Column="0"/>
<local:BlueUserControl Grid.Row="1" Grid.Column="1"/>
<local:BlueUserControl Grid.Row="1" Grid.Column="2"/>
<local:BlueUserControl Grid.Row="1" Grid.Column="3"/>
<local:RedUserControl Grid.Row="2" Grid.Column="0"/>
<local:BlueUserControl Grid.Row="2" Grid.Column="1"/>
<local:BlueUserControl Grid.Row="2" Grid.Column="2"/>
<local:BlueUserControl Grid.Row="2" Grid.Column="3"/>
<local:RedUserControl Grid.Row="3" Grid.Column="0"/>
<local:BlueUserControl Grid.Row="3" Grid.Column="1"/>
<local:BlueUserControl Grid.Row="3" Grid.Column="2"/>
<local:BlueUserControl Grid.Row="3" Grid.Column="3"/>
</Grid>
</Window>
The Application is ready for you ! Come and play.
I am trying to find this out for days already without luck,
what i want to achieve is to add flowdocument xaml code from string.
String like:
string test = "<Paragraph><Run>Text</Run></Paragraph>";
But i want to add it not at the end of the block or document, but at current caret position.
I need it to be able to enable copying of UIElements across my RichTextbox.
Thanks for help !
The XAML text like <Paragraph><Run>Text</Run></Paragraph> can't be inserted to the FlowDocument directly.
It should be converted to proper Flow Related Classes.
In your case create the Paragraph object and insert it on the current caret position:
The MainWindows.xaml:
<Window x:Class="WpfApp12.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Topmost="True"
Title="MainWindow" Height="350" Width="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ToolBar Margin="0,0,0,0">
<Menu VerticalAlignment="Center" Background="Transparent">
<MenuItem Header="Code Block" Click="InsertBlock_Click"/>
</Menu>
</ToolBar>
<Grid Grid.Row="1">
<RichTextBox x:Name="rtb" Margin="5" IsDocumentEnabled="True">
<FlowDocument>
<Paragraph Margin="0" Padding="0" FontSize="14" FontWeight="Bold">RichTextBox</Paragraph>
<Paragraph>A RichTextBox is a better choice when it is necessary for the user to edit formatted text, images, tables, or other rich content.</Paragraph>
</FlowDocument>
</RichTextBox>
</Grid>
</Grid>
</Window>
The MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void InsertBlock_Click(object sender, RoutedEventArgs e)
{
// <Paragraph><Run>Text</Run></Paragraph>
var paragraph = new Paragraph();
paragraph.Inlines.Add(new Run("Text"));
if (rtb.CaretPosition.IsEndOfBlock())
{
rtb.Document.Blocks.InsertAfter(rtb.CaretPosition.Paragraph, paragraph);
}
else
{
if (rtb.CaretPosition.IsAtLineStartPosition)
{
rtb.Document.Blocks.InsertBefore(rtb.CaretPosition.Paragraph, paragraph);
}
else
{
rtb.Document.Blocks.InsertBefore(rtb.CaretPosition.InsertParagraphBreak().Paragraph, paragraph);
}
}
rtb.Focus();
}
// Implementation of the `IsEndOfBlock()` extension method
public static class TextRangeExt
{
public static bool IsEndOfBlock(this TextPointer position)
{
for (; position != null; position = position.GetNextContextPosition(LogicalDirection.Forward))
{
switch (position.GetPointerContext(LogicalDirection.Forward))
{
case TextPointerContext.ElementEnd:
if (position.GetAdjacentElement(LogicalDirection.Forward) is Paragraph) return true;
break;
default:
return false;
}
}
return false;
}
}
}
So I have a button in my AppBar that adds buttons to a stackpanel that is located in a grid on the page.
I assigned a RightTapped event to the new buttons.
However, when I right click a new button, instead of firing the method I assigned to the RightTapped event, the program inflates the AppBar.
I tried to set IsRightTapEnabled="False" one every item but the new buttons, but that didn't help the issue.
I'm stuck and I need help.
Here is my code behind:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
int index = 0;
private void AppBarButton_Click(object sender, RoutedEventArgs e)
{
index++;
string ButtonName = "Button" + index;
Button dummyButton = new Button
{
Name = ButtonName,
Content = ButtonName,
};
StackPanel1.Children.Add(dummyButton);
dummyButton.RightTapped += new RightTappedEventHandler(DummyButton_RightTapped);
}
private void Button0_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
MenuFlyout myFlyout = new MenuFlyout();
MenuFlyoutItem firstItem = new MenuFlyoutItem { Text = "Right Clicked" };
myFlyout.Items.Add(firstItem);
myFlyout.ShowAt(sender as FrameworkElement);
}
private void DummyButton_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
//var dialog = new MessageDialog("Right clicked");
//await dialog.ShowAsync();
MenuFlyout myFlyout = new MenuFlyout();
MenuFlyoutItem firstItem = new MenuFlyoutItem { Text = "Right Clicked" };
myFlyout.Items.Add(firstItem);
myFlyout.ShowAt(sender as FrameworkElement);
}
}
Here is my XAML code:
<Page
x:Class="Soundboard.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Soundboard"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
IsRightTapEnabled="False">
<Page.TopAppBar >
<AppBar IsSticky="True" IsRightTapEnabled="False" >
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<AppBarButton Label="Add Sound" Icon="OpenFile" Click="AppBarButton_Click" ></AppBarButton>
</StackPanel>
</AppBar>
</Page.TopAppBar>
<Grid Background="#FF004D40" Name="myGrid" IsRightTapEnabled="False">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<StackPanel Name="StackPanel1" Grid.Row="0" Orientation="Horizontal" IsRightTapEnabled="False">
<Button Content="Button0" Name ="Button0" RightTapped="Button0_RightTapped"></Button>
</StackPanel>
</Grid>
The official does not recommend using the AppBar in UWP. The following section references Official AppBar instructions.
You should use the AppBar only when you are upgrading a Universal Windows 8 app that uses the AppBar, and need to minimize changes. For new apps in Windows 10, we recommend using the CommandBar control instead.
Usage
Add CommandBar to <Page.TopAppBar> just like following code.
<Page.TopAppBar>
<CommandBar IsSticky="True">
<AppBarButton
Click="AppBarButton_Click"
Icon="OpenFile"
Label="Add Sound" />
</CommandBar>
</Page.TopAppBar>
So I have a really huge problem:
On my page (It’s about the same as a "messages app" from Microsoft), when I click on my input box and keyboard pop up, my header is moved up and no longer visible.
I’ve searched a little and most of solutions I’ve found were not working (targeting wp7 for them...) . (Like a blog where guy creates a lot of dependency property for then margin of Phoneframe is changed. It works, a little, but the header goes off during animation of keyboard. It’s not enough, it’s really not perfect. )
The Microsoft manages it in standard “Messages” app (With a little bug of font size changing), so it must be possible.
How can realize that ?
I tried this solution and it works just fine :
Try to listen to the TextBox.GotFocus and TextBox.LostFocus events to detect when a TextBox in your application acquires and looses focus.
Put your whole content in a ScrollViewer just as follows :
Code XAML :
<ScrollViewer x:Name="LayoutRoot" Margin="0,0,0,0">
<Grid Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
<TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1">
<TextBox HorizontalAlignment="Left" Height="254" Margin="10,183,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="456" GotFocus="TextBox_GotFocus" LostFocus="TextBox_LostFocus"/>
</Grid>
</Grid>
</ScrollViewer>
Adding the content in a ScrollViewer will give the experience of scrolling even when the keyboard is not open, and that's not really desirable.
For that you need to disable scrolling before the Keyboard is opened and after the keyboard is closed.
In the TextBox_GotFocus event play on the top margin of the ScrollViewer :
in the constructor :
public MainPage()
{
InitializeComponent();
LayoutRoot.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
}
the events :
private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
LayoutRoot.Margin = new Thickness(0, 330, 0, 0);
LayoutRoot.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
}
Add the TextBox_LostFocus event handler also to get the page back to its original view when the keyboard is closed :
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
LayoutRoot.Margin = new Thickness(0, 0, 0, 0);
LayoutRoot.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
}
This helps you get the page to its somehow original position when the keyboard is opened.
Hope this helped.
You can make the UI as listbox so that you can scroll the listbox and check the header which is gone up.
When SIP keyboard is rendered, PhoneApplicationFrame.TranslateTransform.Y is set to specific values (-259 in landscape orientation, -339 in portrait orientation). To update layout, we’ll just set top margin to the specified value(-s) and after that Silverlight layout system will fix the issue.
here XAML part:
<Grid x:Name="LayoutRoot" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="WINDOWS PHONE" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="developer's ?" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<Grid Grid.Row="1" Margin="12,0,12,0"></Grid>
<TextBox Grid.Row="2" LostFocus="TextBoxLostFocus"/>
</Grid>
C# portions
private const double LandscapeShift = -259d;
private const double LandscapeShiftWithBar = -328d;
private const double Epsilon = 0.00000001d;
private const double PortraitShift = -339d;
private const double PortraitShiftWithBar = -408d;
public static readonly DependencyProperty TranslateYProperty = DependencyProperty.Register("TranslateY", typeof(double), typeof(MainPage), new PropertyMetadata(0d, OnRenderXPropertyChanged));
public MainPage()
{
InitializeComponent();
Loaded += MainPageLoaded;
}
public double TranslateY
{
get { return (double)GetValue(TranslateYProperty); }
set { SetValue(TranslateYProperty, value); }
}
private static void OnRenderXPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MainPage)d).UpdateTopMargin((double)e.NewValue);
}
private void MainPageLoaded(object sender, RoutedEventArgs e)
{
BindToKeyboardFocus();
}
private void BindToKeyboardFocus()
{
PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
if (frame != null)
{
var group = frame.RenderTransform as TransformGroup;
if (group != null)
{
var translate = group.Children[0] as TranslateTransform;
var translateYBinding = new Binding("Y");
translateYBinding.Source = translate;
SetBinding(TranslateYProperty, translateYBinding);
}
}
}
private void UpdateTopMargin(double translateY)
{
if(IsClose(translateY, LandscapeShift) || IsClose(translateY,PortraitShift) || IsClose(translateY, LandscapeShiftWithBar) || IsClose(translateY, PortraitShiftWithBar))
{
LayoutRoot.Margin = new Thickness(0, -translateY, 0, 0);
}
}
private bool IsClose(double a, double b)
{
return Math.Abs(a - b) < Epsilon;
}
private void TextBoxLostFocus(object sender, RoutedEventArgs e)
{
LayoutRoot.Margin = new Thickness();
}
You can try following link. I think it will be helpful.
http://sorokoletov.com/2011/08/windows-phone-70-handling-text-entry-screens/
I am trying to figure out how to use a WPF list box in conjunction with a window that has its SizeToContent property set to WidthAndHeight. The MainWindow has a grid with two rows and two columns. In the bottom right quadrant, I have a list box. I want the rest of the controls in the window to control the size of the window, and the list box to simply fill the available space. Currently, the list box is expanding to fit its contents, which causes the entire MainWindow to expand.
Note: I attempted to create a simple example, but want to point out that in my real scenario I'm using MVVM, and the controls that I want to determine the window width/height are bound to properties in a viewmodel that have their values set after the window is loaded.
Edit to add: The list box is bound to its content before the controls that I want to determine size are, and I don't have control over that.
Here is what the MainWindow currently looks like at startup:
Notice the red and blue bars which indicate what I'm not wanting to happen. Content in that area should only be visible by scroll bars.
Here is what I want the MainWindow to look like at startup:
Notice the size of the MainWindow is determined by the text blocks along the top and left sides, and the list box fills the available space and uses scrollbars if necessary.
Here is some sample code...
MainWindow.xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" SizeToContent="WidthAndHeight">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="The window should fit to the width of this" FontSize="15"/>
<Canvas Background="Red" Grid.Column="1"/>
</Grid>
<Grid Grid.Row="1" Grid.RowSpan="2">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="The window should fit to the height of this" FontSize="15">
<TextBlock.LayoutTransform>
<RotateTransform Angle="-90"/>
</TextBlock.LayoutTransform>
</TextBlock>
<Canvas Background="Blue" Grid.Row="1"/>
</Grid>
<Grid Grid.Row="2" Grid.Column="1">
<ListBox Name="ListBox1">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var Messages = new ObservableCollection<string>() { "This is a long string to demonstrate that the list box content is determining window width" };
for (int i = 0; i < 16; i++)
Messages.Add("Test" + i);
for (int i = 0; i < 4; i++)
Messages.Add("this text should be visible by vertical scrollbars only");
ListBox1.ItemsSource = Messages;
}
}
Set the list box ItemsSource, and set SizeToContent=Manual after the Window has loaded.
public MainWindow()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
SizeToContent = SizeToContent.Manual;
var messages = new ObservableCollection<string>
{
"This is a long string to demonstrate that the list" +
" box content is determining window width"
};
for (int i = 0; i < 16; i++)
{
messages.Add("Test" + i);
}
for (int i = 0; i < 4; i++)
{
messages.Add("this text should be visible by vertical scrollbars only");
}
ListBox1.ItemsSource = messages;
}
In this way the main window is initially sized to fit the content (with no data in the listbox), and then the listbox displays its items with scrollbars.