I have a dataform with a richtextbox In it. The user can type some text and have some editing capability, but I'd like to give the user the option to expand the editor to fullscreen to have more richtextbox editing options. How can I implement a function that will allow me to fullscreen (or atleast create a bigger window) the richtexteditor so the user has better overview over the document and more editing options?
This is ment to be possible in OOB mode.
Full screen wont work as you have limit keyboard input in fullscreen:
Up Arrow
Down Arrow
Left Arrow
Right Arrow
Spacebar
Tab
Page Up
Page Down
Home
End
Enter
What you can do is for example is make your element fill the whole space of your silverlight application by making it the exact size of your RootVisual and adjusting your margins to place it correctly in your application:
XAML:
<UserControl x:Class="SilverlightApplication1.MyRichTextBox"
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"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button x:Name="FullScreen" Grid.Row="0" Content="FullScreen" Click="FullScreen_Click" />
<RichTextBox Grid.Row="1" />
</Grid>
Code-behind:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace SilverlightApplication1
{
public partial class MyRichTextBox : UserControl
{
private Thickness _oldMargin;
private double _oldHeight = double.NaN;
private double _oldWidth = double.NaN;
private HorizontalAlignment _oldHorizontalAlignment;
private VerticalAlignment _oldVerticalAlignment;
private bool _fullScreen = false;
public MyRichTextBox()
{
InitializeComponent();
}
private void FullScreen_Click(object sender, RoutedEventArgs e)
{
if (_fullScreen)
{
_fullScreen = false;
Margin = _oldMargin;
Width = _oldWidth;
Height = _oldHeight;
}
else
{
_fullScreen = true;
_oldMargin = Margin;
_oldWidth = Width;
_oldHeight = Height;
_oldHorizontalAlignment = HorizontalAlignment;
_oldVerticalAlignment = VerticalAlignment;
FrameworkElement rootVisual = Application.Current.RootVisual as FrameworkElement;
GeneralTransform generalTransform = TransformToVisual(rootVisual);
Point position = generalTransform.Transform(new Point(0, 0));
Width = rootVisual.ActualWidth;
Height =rootVisual.ActualHeight;
Margin = new Thickness(-position.X - 1, -position.Y - 1
, (ActualWidth + position.X) - rootVisual.ActualWidth - 1
, (ActualHeight + position.Y) - rootVisual.ActualHeight - 1);
}
}
}
}
Related
I have a basic wpf app that basically detects a touch input and moves a rectangle according to the input. My problem is that if that touch comes outside the screen(For example: I touch the bottom bezel of the screen and slide it in the touch area) it won't be detected. Is there a way to get over this problem? I want to detect edge swipes as well.
XAML:
<Window x:Class="touch_test.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"
xmlns:local="clr-namespace:touch_test"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
Stylus.IsPressAndHoldEnabled="False"
>
<Canvas>
<Rectangle Width="50" Height="50" x:Name="rect" Fill="Red"/>
</Canvas>
</Window>
Cs:
protected TouchPoint TouchStart;
public MainWindow()
{
InitializeComponent();
this.PreviewTouchDown += new EventHandler<TouchEventArgs>(BasePage_TouchDown);
this.PreviewTouchMove += new EventHandler<TouchEventArgs>(BasePage_TouchMove);
WindowState = WindowState.Maximized;
WindowStyle = WindowStyle.None;
}
void BasePage_TouchDown(object sender, TouchEventArgs e)
{
TouchStart = e.GetTouchPoint(this);
}
void BasePage_TouchMove(object sender, TouchEventArgs e)
{
Rectangle rectToMove = rect;
rectToMove.RenderTransform = new MatrixTransform();
Matrix matr = ((MatrixTransform)rectToMove.RenderTransform).Matrix;
var currentTouchPoint = e.GetTouchPoint(this);
matr.Translate(currentTouchPoint.Position.X, currentTouchPoint.Position.Y );
rectToMove.RenderTransform = new MatrixTransform(matr);
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Button button1 = new Button();
Point tPosition = Mouse.GetPosition(this);
button1.Margin = new Thickness(tPosition.X,tPosition.Y,0,0) ;
button1.Width = 75;
this.AddChild(button1);
}
}
I think the code is pretty self-explanatory, I used a code that is approved in other thread here in stackoverflow, it doesn't give any error, but it also doesn't show up, do I need to refresh the window? And how?
by request, the XAML
<Window x:Class="Ampeldingensthingy.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">
<Grid MouseLeftButtonDown="Grid_MouseLeftButtonDown" Name="hans">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="398*" />
<ColumnDefinition Width="105*" />
</Grid.ColumnDefinitions>
</Grid>
</Window>
Window can have only one children and I think you already have one that is Grid whose MouseButtonDown you subscribing. Give a name to that Grid and then replace
this.AddChild(button1);
with
grid.Children.Add(button1);
here grid is the name given to Grid.
The object "this" depicts the Window object here. Content of a ContentControl must be a single element. Hence append the Button that is "button1" inside a parent Grid. For example
private void Button_Click(object sender, RoutedEventArgs e)
{
Button button1 = new Button();
Point tPosition = Mouse.GetPosition(this);
button1.Margin = new Thickness(tPosition.X, tPosition.Y, 0, 0);
button1.Width = 75;
MainGrid.Children.Add(button1);
}
And in your Xaml
<Grid x:Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Click="Button_Click" Content="click" Grid.Row="1"/>
</Grid>
public partial class MainWindow : Window
{
public StackPanel SPanel{get;set;}
public MainWindow()
{
InitializeComponent();
SPanel = new StackPanel { Orientation = Orientation.Vertical };
}
private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Button button1 = new Button();
Point tPosition = Mouse.GetPosition(this);
button1.Margin = new Thickness(tPosition.X,tPosition.Y,0,0) ;
button1.Width = 75;
SPanel.Children.Add(button1);
window.Content = SPanel;
}
}
try to do the same with a canvas. the buttons will popup at the position you gave them.
When I create ListBox with virtualization enabled and then update all its items appearance it works very fast. But when i slowly scroll down all items in ListBox and then update all items appearance it takes a lot of time. I think it because VirtualizingStackPanel does not destroy items when they are runs out of viewport.
I wrote simple app to reproduce this behavior.
Code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
for(int i = 0; i < 5000; ++i) // creating 5k text boxes
MyList.Items.Add(new TextBox() { Text = CurrText });
}
private void Button_Click(object sender, RoutedEventArgs e)
{
GC.Collect();
n = (n + 1) % 2; // switch 0 to 1 or 1 to 0
foreach (var item in MyList.Items)
((TextBox)item).Text = CurrText; // set new text
}
static int n = 0;
string CurrText { get { return new string(n.ToString()[0], 50); } }
}
XAML:
<Window x:Class="VPanel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="700" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="5*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ListBox Name="MyList" VirtualizingStackPanel.IsVirtualizing="True"/>
<Button Grid.Row="1" Content="UpdateText" Click="Button_Click"/>
</Grid>
</Window>
Clicking a button "UpdateText" updates all textboxes text. If slowly scroll to end by dragging scroller, "UpdateText" button clicks with a huge lag.
Don't create TextBoxes manually.
The word "virtualize" refers to a technique by which a subset of user interface (UI) elements are generated from a larger number of data items based on which items are visible on-screen. Generating many UI elements when only a few elements might be on the screen can adversely affect the performance of your application.
You create your UI items manually so it's already too late for virtualization. Use bindings and it will create TextBox from ItemTemplate whenever it is required. It will also not refresh TextBox.Text value if it's not currently in the view. To do that change your MainWindow to create ObservableCollection instead of TextBoxes and operate on that:
public partial class MainWindow : Window
{
private readonly ObservableCollection<string> _textBoxes = new ObservableCollection<string>();
public ICollection<string> TextBoxes { get { return _textBoxes; } }
private int n = 0;
private string CurrText { get { return new string(n.ToString()[0], 50); } }
public MainWindow()
{
for (int i = 0; i < 5000; ++i) _textBoxes.Add(CurrText);
InitializeComponent();
DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
n = (n + 1) % 2; // switch 0 to 1 or 1 to 0
for (int i = 0; i < _textBoxes.Count; i++) _textBoxes[i] = CurrText;
}
}
and then change XAML to bind to TextBoxes list property
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="5*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ListBox ItemsSource="{Binding TextBoxes}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=., Mode=TwoWay}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Grid.Row="1" Content="UpdateText" Click="Button_Click"/>
</Grid>
I'm trying to figure out how to constrain a pan so that the image remains entirely within the bounds of it's containing border. Any help this regard would be greatly appreciated. Thanks....
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MapTest.Window1"
Title="PanTest"
Width="484"
Height="400"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Margin="8,8,8,0"
TextWrapping="Wrap">
To pan the image, simply click on it then drag. I'd like to
constrain the pan so that the image remains entirely within
the border, but without resorting to ClipToBounds. Any help
in this regard would be greatly appreciated. Thanks....</TextBlock>
<Border x:Name="border"
Margin="8"
BorderBrush="Black"
BorderThickness="1"
Grid.Row="1">
<Image x:Name="image"
Source="Penguins.jpg"
Opacity="1"
Width="300"
Height="300"
Stretch="Uniform"
RenderTransformOrigin="0.5,0.5" />
</Border>
</Grid>
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace MapTest
{
public partial class Window1 : Window
{
private Point origin;
private Point start;
public Window1()
{
InitializeComponent();
var group = new TransformGroup();
group.Children.Add(new TranslateTransform());
image.RenderTransform = group;
image.MouseLeftButtonDown += image_MouseLeftButtonDown;
image.MouseMove += image_MouseMove;
image.MouseLeftButtonUp += image_MouseLeftButtonUp;
}
private void image_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
image.ReleaseMouseCapture();
}
private void image_MouseMove(object sender, MouseEventArgs e)
{
if (!image.IsMouseCaptured)
return;
var tt = (TranslateTransform)((TransformGroup)image.RenderTransform).
Children.First(tr => tr is TranslateTransform);
var vector = start - e.GetPosition(border);
tt.X = origin.X - vector.X;
tt.Y = origin.Y - vector.Y;
}
private void image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
image.CaptureMouse();
var tt = (TranslateTransform)((TransformGroup)image.RenderTransform).
Children.First(tr => tr is TranslateTransform);
start = e.GetPosition(border);
origin = new Point(tt.X, tt.Y);
}
}
}
The following code gives you the bounds of the transformed Image control in coordinates relative to the Border control. You could easily check if the bounds are located inside the Border control.
var rect = new Rect(image.RenderSize);
var bounds = image.TransformToAncestor(border).TransformBounds(rect);
I've got a StackPanel, and it's perfect for laying out columns that the user adds at runtime. But I'd like the columns to be resizable, and I was reading about the GridSplitter control. Here's what I'm wondering:
Is the GridSplitter the wpf replacement for the WinForms splitter? In other words, is this the de facto way to allow the users to resize regions of the window?
Does it only work inside of a Grid? If I have items inside a stackpanel or a dockpanel, can I still use a gridsplitter the way I used the splitter in WinForms?
If I have to use a Grid, how can I make it behave just like a StackPanel? (hope it doesn't come to that)
GridSplitter only works in a Grid and is the easiest way to allow users to resize controls.
What do you mean that you want your grid (with gridsplitters) to behave just like a stackpanel? A stackpanel will exactly fit each of its children while a grid with gridsplitters will leave it up to the user.
Below is a user control which allows items to be added as columns. Between columns are grid splitters. Users can click on Delete button to remove added columns and columns can be added using behind code. Let me know if that's what you were looking for.
User control SmartGrid XAML:
<UserControl x:Class="SmartGridDemo.SmartGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Name="_grid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
</Grid>
</UserControl>
User control SmartGrid code behind:
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace SmartGridDemo
{
public partial class SmartGrid : UserControl
{
public SmartGrid()
{
InitializeComponent();
}
public void Add(UIElement child)
{
int columnIndex = _grid.ColumnDefinitions.Count();
_grid.ColumnDefinitions.Add(
new ColumnDefinition()
{
Width = new GridLength(columnIndex == 0 ? 0 :5)
});
GridSplitter gridSplitter =
new GridSplitter()
{
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
ResizeDirection = GridResizeDirection.Columns,
Background = Brushes.Black
};
_grid.Children.Add(gridSplitter);
Grid.SetColumn(gridSplitter, columnIndex);
Grid.SetRow(gridSplitter, 0);
Grid.SetRowSpan(gridSplitter, 2);
columnIndex++;
_grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
Button button = new Button();
button.Content = "Delete";
button.Tag = new TagTuple() {Child = child, GridSplitter = gridSplitter};
button.Click += new RoutedEventHandler(DeleteButton_Click);
_grid.Children.Add(button);
Grid.SetColumn(button, columnIndex);
Grid.SetRow(button, 0);
_grid.Children.Add(child);
Grid.SetColumn(child, columnIndex);
Grid.SetRow(child, 1);
}
private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
Button button = sender as Button;
int columnIndex = Grid.GetColumn(button);
TagTuple tagTuple = button.Tag as TagTuple;
_grid.Children.Remove(tagTuple.GridSplitter);
_grid.Children.Remove(tagTuple.Child);
_grid.Children.Remove(button as UIElement);
_grid.ColumnDefinitions.RemoveAt(_grid.ColumnDefinitions.Count() - 1);
_grid.ColumnDefinitions.RemoveAt(_grid.ColumnDefinitions.Count() - 1);
foreach (UIElement child in _grid.Children)
{
int columnIndexForChild = Grid.GetColumn(child);
if (columnIndexForChild > columnIndex)
{
Grid.SetColumn(child, columnIndexForChild - 2);
}
}
}
private class TagTuple
{
public GridSplitter GridSplitter { get; set; }
public UIElement Child { get; set; }
}
}
}
Demo code, add some text in the TextBox and hit Add button to add new columns, XAML:
<Window x:Class="SmartGridDemo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SmartGridDemo"
Title="SmartGridDemo" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox Name="_texBox" Grid.Row="0" Grid.Column="0" />
<Button Content="Add" Click="AddButton_Click" Grid.Row="0" Grid.Column="1" />
<local:SmartGrid x:Name="_smartGrid" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" />
</Grid>
</Window>
Demo, behind code:
using System;
using System.Windows;
using System.Windows.Controls;
namespace SmartGridDemo
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
_smartGrid.Add(new TextBlock() { Text = "AAA" });
_smartGrid.Add(new TextBlock() { Text = "BBB" });
_smartGrid.Add(new TextBlock() { Text = "CCC" });
_smartGrid.Add(new TextBlock() { Text = "DDD" });
_smartGrid.Add(new TextBlock() { Text = "EEE" });
_smartGrid.Add(new TextBlock() { Text = "FFF" });
}
private void AddButton_Click(object sender, RoutedEventArgs e)
{
_smartGrid.Add(new TextBlock() { Text = _texBox.Text });
}
}
}
Here is an open source WPF SplitContainer:
[http://wpfsplitcontainer.codeplex.com/]