Paragraph mark of UWP RichEditBox is not resized - c#

With this code (Editor.Document.Selection.CharacterFormat.Size = 20;) I change the font size of a UWP RichEditBox in the Page_Loaded-handle. When I start typing some characters, everything works fine. But when I select the paragraph mark and then type something, this text appears in the wrong font size (10.5).
What I've tried is to expand the selection before setting the font size, but it seems that there is no paragraph mark when there's no text. But when the rich edit box is empty and I press Shift+Right Arrow ⟶ (as I would normally select the paragraph mark), the font size is set back to 10.5.
Is there any workaround to prevent that the font size is set back to 10.5 in any case?
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock x:Name="FontSizeBlock" Grid.Row="0"></TextBlock>
<RichEditBox x:Name="Editor" Grid.Row="1" SelectionChanged="HandleRichEditBox_SelectionChanged"></RichEditBox>
</Grid>
public sealed partial class MainPage : Page {
public MainPage() {
this.InitializeComponent();
this.Loaded += Page_Loaded;
}
private void Page_Loaded(object sender, RoutedEventArgs e) {
Editor.Document.Selection.SetRange(0, 1);
Editor.Document.Selection.CharacterFormat.Size = 20;
}
private void HandleRichEditBox_SelectionChanged(object sender, RoutedEventArgs e) {
FontSizeBlock.Text = "FontSize: " + Editor.Document.Selection.CharacterFormat.Size;
}
}

Is there any workaround to prevent that the font size is set back to 10.5 in any case?
For your requirement, you could force font size to 20 when you press Shift+Right. Please refer the following code.
private void HandleRichEditBox_SelectionChanged(object sender, RoutedEventArgs e)
{
FontSizeBlock.Text = "FontSize: " + Editor.Document.Selection.CharacterFormat.Size;
if (Editor.Document.Selection.CharacterFormat.Size == 10.5)
{
Editor.Document.Selection.SetRange(0, 1);
Editor.Document.Selection.CharacterFormat.Size = 20;
}
}

When further investigating my problem, I noted that my issue doesn't occur when there has already been some text in the RichEditBox which was deleted.
Therefore, I have tried to programmatically append, select and remove characters in the Page_Loaded-handle, and this approach worked for me.
private void Page_Loaded(object sender, RoutedEventArgs e) {
// set any character
Editor.Document.SetText(Windows.UI.Text.TextSetOptions.None, "a");
Editor.Document.Selection.Expand(Windows.UI.Text.TextRangeUnit.Paragraph);
Editor.Document.Selection.CharacterFormat.Size = 20;
Editor.Document.SetText(Windows.UI.Text.TextSetOptions.None, "");
}

Related

Loading XAML and displaying it properly

I am able to save the Xaml data and then load it again however it doesnt display as I would like it too, this is what it looks like before loading saved data Before loading saved data However after loading all of the buttons disappear After loading I would like to keep the buttons where they are and only load the saved data into its allocated space. Below is the code any help would be great thanks.
public MainWindow()
{
InitializeComponent();
}
// button and code to save canvas
public void Button_Click(object sender, RoutedEventArgs e)
{
string savedCanvas = XamlWriter.Save(cnv);
File.WriteAllText("canvas.xaml", savedCanvas);
}
// button and code for loading canvas
void Button_Click_1(object sender, RoutedEventArgs e)
{
var savedCanvas = File.ReadAllText("canvas.xaml");
StringReader stringReader = new StringReader(savedCanvas);
XmlReader xmlReader = XmlReader.Create(stringReader);
Canvas readerLoadCanvas = (Canvas)XamlReader.Load(xmlReader);
Content = readerLoadCanvas;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
Block b = new Block();
hor.Children.Add(b);
}
welcome to SO! From the code that you've provided, the culprit is this line:
Content = readerLoadCanvas;
What you are doing here is replacing your MainWindow's entire "Content" with the canvas.xaml code, therefore it will replace all of your buttons along with the original canvas. Because I can't see your xaml code (not posted yet), I can't tell what container your Canvas resides in (i.e. Grid, StackPanel, etc.).
But if I were to assume that you put your Canvas inside of a Grid, for example, then I can give you an answer. Example:
<Grid x:Name="mainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel x:Name="PanelOfButtons">
<Button Content="Load" .../>
<Button Content="Save" .../>
</StackPanel>
<Canvas x:Name="cnv" Grid.Column="1" Background="Green">
The answer would be to replace the offending line with this to replace the canvas with your new canvas:
// Remove the original canvas
mainGrid.Children.Remove(cnv);
// Add the new canvas
mainGrid.Children.Add(readerLoadCanvas);

Button in Custom ViewCell Xamarin Tableview C#

Looking forward to your assistance once again :)
I'm trying to have the buttons on the far right be able to delete their row in the tableview control. Right now they now about which row they are on but I cannot connect this information to the parent. The table view is populated with a custom viewcell.
The custom view cell contains two different pickers, two entry fields and a button. I haven't found a cleaner way to execute this as I have the picker's data which isn't related to the # of rows in the data table control.
Currently when you click a button on the right it posts to the console what row was selected but I don't know of a way to connect that to its parent in order to actually delete that row on the data table
View Cell Code Behind
public partial class RecipeIngredientViewCell : ViewCell
{
ObservableCollection<clIngredient> _listIngredients = new ObservableCollection<clIngredient>();
public ObservableCollection<clIngredient> listIngredients { get { return _listIngredients; } }
ObservableCollection<clUnit> _listUnit = new ObservableCollection<clUnit>();
public ObservableCollection<clUnit> funclistUnit { get { return _listUnit; } }
clRecipeIngredient _recipeIngredient;
int _row;
public RecipeIngredientViewCell(clRecipeIngredient passedrecipeIngredient, ObservableCollection<clIngredient> passedlistIngredients, ObservableCollection<clUnit> passedlistUnits, int row)
{
InitializeComponent();
_listIngredients = passedlistIngredients;
_listUnit = passedlistUnits;
_recipeIngredient = passedrecipeIngredient;
_row = row;
this.BindingContext = _recipeIngredient;
//INGREDIENT PICKER
pickerIngredient.ItemsSource = _listIngredients;
for(int x = 0; x < _listIngredients.Count; x++)
{
if (_listIngredients[x].IngredientName == _recipeIngredient.IngredientName)
{
pickerIngredient.SelectedIndex = x;
}
}
//UNIT PICKER
pickerUnit.ItemsSource = _listUnit;
for (int x = 0; x < _listUnit.Count; x++)
{
if (_listUnit[x].UnitName == _recipeIngredient.UnitName)
{
pickerUnit.SelectedIndex = x;
}
}
}
private void btnDeleteRecipeIngredient_Clicked(object sender, EventArgs e)
{
//NOT IMPLEMENTED YET!
Console.WriteLine(_recipeIngredient.IngredientName + " AT ROW " + _row.ToString());
}
private void txtQuantity_TextChanged(object sender, TextChangedEventArgs e)
{
_recipeIngredient.Quantity = txtQuantity.Text.ToDouble();
}
private void txtComment_TextChanged(object sender, TextChangedEventArgs e)
{
_recipeIngredient.Comments = txtComment.Text;
}
private void pickerIngredient_SelectedIndexChanged(object sender, EventArgs e)
{
_recipeIngredient.IngredientName = pickerIngredient.SelectedItem.ToString();
}
private void pickerUnit_SelectedIndexChanged(object sender, EventArgs e)
{
_recipeIngredient.UnitName = pickerIngredient.SelectedItem.ToString();
}
}
View Cell XAML
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="RecipeDatabaseXamarin.Views.RecipeIngredientViewCell">
<Grid VerticalOptions="CenterAndExpand" Padding = "20, 0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
<Picker Grid.Column = "0" x:Name="pickerIngredient" HorizontalOptions = "StartAndExpand" SelectedIndexChanged="pickerIngredient_SelectedIndexChanged"/>
<Entry Grid.Column = "1" x:Name ="txtQuantity" HorizontalOptions = "StartAndExpand" Text = "{Binding Quantity}" TextChanged="txtQuantity_TextChanged" />
<Picker Grid.Column = "2" x:Name ="pickerUnit" HorizontalOptions = "StartAndExpand" SelectedIndexChanged="pickerUnit_SelectedIndexChanged"/>
<Entry Grid.Column = "3" x:Name="txtComment" HorizontalOptions = "StartAndExpand" Text = "{Binding Comments}" TextChanged="txtComment_TextChanged" WidthRequest="150"/>
<Button Grid.Column = "4" x:Name="btnDeleteRecipeIngredient" HorizontalOptions = "StartAndExpand" Text = "Delete Ingredient" Clicked="btnDeleteRecipeIngredient_Clicked"/>
</Grid>
Code Behind for Page
var section = new TableSection();
for(int i = 0;i<_downloadedRecipeIngredients.Count;i++)
{
var cell = new RecipeIngredientViewCell(downloadedRecipeIngredients[i], listIngredients, listUnit, i);
section.Add(cell);
}
tblData.Root.Add(section);
In the main page code behind I want the button to run a block of code to execute something such as
tblData.Root.del(ROW_INDEX);
Thanks!
I believe I have this solved. Will post the solution when I get back from the 4th weekend.
The solution to this problem is answered on another post. Basically the solution is easier once MVVM is implemented even though it was a pain to get it to work on the picker withing the listView control.
This other thread has sample code which you can run.
Trying to set picker within listview MVVM Xamarin
If anyone runs into the same issue please post and I'll try to respond back as this issue was a PAIN!!!!
I am not a notorious xamarin programmer, but you have your width to auto, which most likely changes the whole grid the moment the width changes. Therefore it will align the buttons differently too.
It seems you could position the horizontalOptions to "End" to at least put the buttons to the end of the screen. If you want to have it always the same, I would give them a certain width per section.

How to set width/height in code without breaking Grid star-size?

I have some XAML code like this:
<ScrollViewer VerticalScrollMode="Auto">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid x:Name="g1" Grid.Row="0" Background="Pink"/>
<Grid x:Name="g2" Grid.Row="1" Background="Green"/>
</Grid>
</ScrollViewer>
<Button Content="Update Size" Width="150" Height="50" Click="Button_Click" Margin="105,342,0,248"/>
and code behind:
private void Button_Click(object sender, RoutedEventArgs e)
{
g1.Width = mainGrid.ActualWidth;
g1.Height = mainGrid.ActualHeight / 2;
}
it shows before clicking the button like this:
after clicking the button and drag the window to a bit larger, it looks like this:
so my question is, before clicking the button if you drag the window around the star-sizing works and resize both top/bottom grids as window resizes, however after clicking the buttom, which sets g1 width and height, it breaks star-sizing. how do i bring the star-sizing back to work again after set the width and height?
thanks in advance.
how do i bring the star-sizing back to work again after set the width and height?
After you set the width and height for Grid g1, you broke the auto star-sizing. But you can use the Window.SizeChanged event to monitor the size changing of the application window view instead. When window size changed, dynamically set new height and width for g1 by yourself to fit the parent control mainGrid.
Code like follows will meet you current requirements.
public Strangelaout()
{
this.InitializeComponent();
Window.Current.SizeChanged += Current_SizeChanged;
}
private void Current_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
g1.Width = mainGrid.ActualWidth;
g1.Height = mainGrid.ActualHeight / 2;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
g1.Width = mainGrid.ActualWidth;
g1.Height = mainGrid.ActualHeight / 2;
}

How to change the location of wpf grid at run time?

I have created a WPF Grid. That grid contains Textbox and Button controls.Here i want to relocate the grid at run time .How its possible please answer this if you know.Like a movable window.
I don't know if you want to relocate after mouse events or in code after some different event? If second you can change grid margins in event/method where you want to do it and call UpdateLayout() method after it. If first here is my answer for similar question:
Check time after a mousebuttondown before the mousebuttonup
I found this solution on stackoveflow
<Grid x:Name="grid" Background="Blue"
Width="100" Height="100"
MouseDown="Grid_MouseDown" MouseMove="Grid_MouseMove" MouseUp="Grid_MouseUp">
<Grid.RenderTransform>
<TranslateTransform x:Name="tt"/>
</Grid.RenderTransform>
Place it in a window
<Window x:Name="window" ...>
<Grid x:Name="grid"...
And code:
Point m_start;
Vector m_startOffset;
private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
{
m_start = e.GetPosition(window);
m_startOffset = new Vector(tt.X, tt.Y);
grid.CaptureMouse();
}
private void Grid_MouseMove(object sender, MouseEventArgs e)
{
if (grid.IsMouseCaptured)
{
Vector offset = Point.Subtract(e.GetPosition(window), m_start);
tt.X = m_startOffset.X + offset.X;
tt.Y = m_startOffset.Y + offset.Y;
}
}
private void Grid_MouseUp(object sender, MouseButtonEventArgs e)
{
grid.ReleaseMouseCapture();
}

UserControl BringIntoView() not working properly

Background:
I have a usercontrol defined in a ScrollViewer along with a ContentControl, the ContentControl will be visible all the time, and within it there is a Button, when the button is clicked will set the usercontrol to Visible, and when the usercontrol shows (Visiblility="Visible") I want it to be scrolled into the view. I have
XAML
<ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="465">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ContentControl Content="{Binding MyOtherViewModel}" Width="960" ></ContentControl>
<local:MyView IsVisibleChanged="MyView_IsVisibleChanged" Grid.Row="1" Visibility="{Binding IsNonCompliant, Converter={StaticResource BooltoVisible}, UpdateSourceTrigger=PropertyChanged}" />
</ScrollViewer>
Code Behind
private void MyView_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
(sender as Control).BringIntoView();
}
Problem: this is not working, or more precisely, my usercontrol scrolled into the view first then revert back to the bottom of the ScrollViewer in a blink.
Weird thing: show a messagebox before calling BringIntoView will correctly display my usercontrol into the middle of the view
Current hack solution: you can see this works even to close the Window immediately after its loaded
private void MyView_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
Window ss = new Window();
ss.Loaded += new RoutedEventHandler(ss_Loaded);
ss.ShowDialog();
(sender as Control).BringIntoView();
}
private void ss_Loaded(object sender, RoutedEventArgs e)
{
(sender as Window).Close();
}
Question: I know there must be something else going on, but I just can't identify it, but I really want to know what happened when a window showing with ShowDialog? Is this because it refreshes the window so that the BringIntoView will happen only after the usercontrol been loaded? (Not as the problem I have now: BringIntoView happened first, and then the window get refreshed and put the scrollbar back to the top). And what is the correct fix for my problem?
It looks like BringIntoView called before my Usercontrol getting rendered, as a result when it gets fully rendered, the scrollbar is revert back to the top (as I have described in my question). And thanks for the answer from #Evgeny posted for another question, I get a better solution now (less hack maybe?). Still want to see if there are better solutions.
private void MyView_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var border = (FrameworkElement)sender;
if (border.IsVisible)
{
//Window ss = new Window();
//ss.Loaded += new RoutedEventHandler(ss_Loaded);
//ss.ShowDialog();
using (BackgroundWorker bg = new BackgroundWorker())
{
bg.DoWork += new DoWorkEventHandler(bg_DoWork);
bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted);
Tuple<FrameworkElement, double> b = new Tuple<FrameworkElement, double>(border, border.Height);
bg.RunWorkerAsync(b);
}
}
}
private void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
(e.Result as UserControl).BringIntoView();
}
private void bg_DoWork(object sender, DoWorkEventArgs e)
{
int maxwait = 300 //not scrolled to the view is not a disaster, but if the program hangs forever it will be a disaster, so set this to prevent that from happening
while (maxwait!=0
&&
(e.Argument as Tuple<FrameworkElement, double>).Item1.ActualHeight != (e.Argument as Tuple<FrameworkElement, double>).Item2)
{
Thread.Sleep(1);
maxwait --;
}
e.Result = (e.Argument as Tuple<FrameworkElement, double>).Item1;
}
I cannot believe that using background worker is a correct solution for this! You can use LayoutUpdated event to easily find when control is loaded and finally displayed.
userControl.LayoutUpdated+=OnLayoutUpdated;
private bool loaded=false;
private void OnLayoutUpdated(object sender,EventArgs e)
{
if (!loaded && (view.ActualHeight > 0 || view.ActualWidth > 0))
{
// Unsubscribe or set a flag.
userControl.LayoutUpdated -= OnLayoutUpdated;
loaded = true;
}
}
So you can execute that code when layout is updated and height or width is set. This will means that control is loaded and displayed.
Than you can unsubscribe or set a flag that initialization is complated.

Categories