WPF - Changing Focus from a RichTextBox causes a InvalidOperationException - c#

Running into a strange issue when I have to switch focus from a RichTextBox. The xaml for my application is as follows:
<Window Name="MyWindow" x:Class="WpfBasics.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:WpfBasics"
mc:Ignorable="d"
Title="MainWindow" Height="600" Width="400">
<StackPanel>
<TextBlock>Box 1:</TextBlock>
<RichTextBox x:Name="Box1" TextChanged="Box1_TextChanged" />
<TextBlock>Box 2:</TextBlock>
<RichTextBox x:Name="Box2" />
</StackPanel>
</Window>
With the following codebehind (only the relevant bit):
private void Box1_TextChanged(object sender, TextChangedEventArgs e)
{
Box2.Focus();
}
The moment I use Box1, Focus throws the following exception:
System.InvalidOperationException: 'Cannot Reopen undo unit while another unit is already open.'
Looking into the CallStack I believe the issue is caused by the LostFocus event handler on a RichTextBox.

Based on the information you gave, I created a sample project that seems to work. Give this a shot:
private void Box1_TextChanged(object sender, TextChangedEventArgs e)
{
RichTextBox textBox = sender as RichTextBox;
var text = new TextRange(textBox.Document.ContentStart, textbox.Document.ContentEnd).Text;
if (IsValid(text))
{
Dispatcher.BeginInvoke((Action)ChangeFocus);
}
}
private void ChangeFocus()
{
Box2.Focus();
}
private bool IsValid(string text)
{
var plainText = text.Substring(0, text.Length - 2);
if (plainText == "hello world")
return true;
return false;
}

Related

How can i change a Page in my wpf Main Window?

i want to switch pages that are hosted on my main window. The first page (at App Start) is beeing shown correctly. But if i want to change the page it won´t happen. I even don´t get an error. It just shows the first page! Here´s my code:
The constructor of MainWindow:
public MainWindow(SchraubUser _schraubUser, string page = "")
{
schraubUser = _schraubUser;
db = new AccessDatabase(schraubUser._DATABASE_PATH);
ViewModel.ViewModel wzViewModel = new ViewModel.ViewModel(schraubUser, db);
InitializeComponent();
if (page == "")
{
Main.Content = new View.Werkzeug_Window(wzViewModel);
}
else
{
Main.Content = new View.Freigaben(wzViewModel);
}
}
At Application start the optional variable is "" so the mainwindow will display View.Werkzeug_Window (works correctly).
Here`s the code for changing the page:
private void Button_Freigaben_Click(object sender, RoutedEventArgs e)
{
mainWindow = new MainWindow(sb_vm.schraubUser, "Freigabe");
}
But it will still show the first page. Why is that?
XAML of MainWindow:
<Window x:Class="SchrauberDB.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:SchrauberDB"
mc:Ignorable="d"
Title="MainWindow" Height="750" Width="1100"
WindowState="Maximized">
<Grid x:Name="mainGrid">
<Frame x:Name="Main" />
</Grid>
</Window>
This is so embarrassing...
private void Button_Freigaben_Click(object sender, RoutedEventArgs e)
{
mainWindow = new MainWindow(sb_vm.schraubUser, "Freigabe");
mainWindow.Show();
}

RichTextBox becomes ReadOnly when binding it to content from inside FlowDocumentReader

Question: In the btnRevert_Click(...) event of the following code, how can we make the RichTextBox editable?
In my WPF .NET5 app, the btnTest_Click(...) event successfully displays the contents of a RichTextBox into a FlowDocumentReader (fdReader). Then the btnRevert_Click(...) event successfully takes the content back from fdReader and displays it back into RichTextBox, but it makes the RichTextBox ReadOnly.
I tested the scenario by entering simple text "This is a test" inside RichTextBox, and noted that the above back and forth scenario works fine except that the btnRevert_Click(...) event makes the text "This is a test" ReadOnly.
MainWindow.xaml:
<Window x:Class="Wpf_RTBFlowDocTest.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:Wpf_RTBFlowDocTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<DockPanel Name="mainPanel">
<ToolBar Name="mainToolBar" Height="30" DockPanel.Dock="Top">
<Button x:Name="btnTest" Content="Test" Click="btnTest_Click"/>
<Button x:Name="btnRevert" Content="Revert" Click="btnRevert_Click"/>
</ToolBar>
<RichTextBox Name="rtbTest" AcceptsTab="True"></RichTextBox>
<FlowDocumentReader x:Name="fdReader" Visibility="Collapsed">
<FlowDocument>
<Paragraph>Text inside paragraph.</Paragraph>
</FlowDocument>
</FlowDocumentReader>
</DockPanel>
</Grid>
</Window>
MainWindow.xaml.cs:
private void btnTest_Click(object sender, RoutedEventArgs e)
{
FlowDocument RTBflowDoc = rtbTest.Document;
rtbTest.Visibility = Visibility.Collapsed;
rtbTest.Document = new FlowDocument();
fdReader.Document = RTBflowDoc;
fdReader.Visibility = Visibility.Visible;
}
private void btnRevert_Click(object sender, RoutedEventArgs e)
{
FlowDocument fdReaderFlowDoc = fdReader.Document;
fdReader.Document = new FlowDocument();
rtbTest.IsReadOnly = false;
rtbTest.Document = fdReaderFlowDoc;
rtbTest.Visibility = Visibility.Visible;
}
The FlowDocumentReader provides a control to view a flow content (doesn't support edit).
The following lines in btnRevert_Click() method, from question above, just set rtbTest.Document to fdReader.Document:
FlowDocument fdReaderFlowDoc = fdReader.Document;
fdReader.Document = new FlowDocument();
rtbTest.Document = fdReaderFlowDoc;
But because of the FlowDocument in the FlowDocumentReader control doesn't support editing, the easiest way to obtain document from the FlowDocumentReader control for editing is to clone it like below:
private void btnRevert_Click(object sender, RoutedEventArgs e)
{
var range = new TextRange(fdReader.Document.ContentStart, fdReader.Document.ContentEnd);
if (!range.IsEmpty)
{
using (var stream = new MemoryStream())
{
range.Save(stream, DataFormats.XamlPackage);
var copyto = new TextRange(rtbTest.Document.ContentEnd, rtbTest.Document.ContentEnd);
copyto.Load(stream, DataFormats.XamlPackage);
}
}
rtbTest.Visibility = Visibility.Visible;
fdReader.Visibility = Visibility.Collapsed;
}

How to show programmatically FocusVisualStyle?

Afters attemps I could tell that the FocusVisualStyle is only activated by the keyboard (tab and arrows keys).
Try to make the FocusVisualStyle to be applied after the component is loaded, it is impossible to do, There is an easy way to get around this problem?
I found this:
- focus visual not showing when navigating focus programically
- How do WPF buttons decide to show FocusVisualStyle?
- http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/99856840-f8ef-4547-9150-c4c46ec2f3df
But none shows a definite solution (without overwriting the component), and I could not write, can someone help?
I am not pretty sure I understand your issue, but I tried the example in one of the links and I was able to move focus to next component from code behind exactly as you would do using keyboard. Here is the code.
<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" Height="350" Width="525"
xmlns:local="clr-namespace:WpfApplication1" Loaded="OnLoaded"
>
<StackPanel Margin="10">
<TextBox Margin="10" x:Name="a" >A</TextBox>
<TextBox Margin="10" x:Name="b" >B</TextBox>
<Button Focusable="False" Click="OnClick">Move Focus</Button>
</StackPanel>
</Window>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void OnLoaded(object sender, RoutedEventArgs e) {
a.Focus();
}
private void OnClick(object sender, RoutedEventArgs e) {
var request = new TraversalRequest(FocusNavigationDirection.Next);
var elementWithFocus = FocusManager.GetFocusedElement(FocusTest) as UIElement;
if (elementWithFocus != null)
elementWithFocus.MoveFocus(request);
}
}

WPF Clear UserControl's children

I'm creating a UserControl in WPF, and the UserControl works so that when the user moves mouse over the control, it's childcontrols should be removed, but I don't seem to find the Children property or anything like that..
XAML is here:
<UserControl x:Class="myTextBox"
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"
Name="thisTextBox"
mc:Ignorable="d" d:DesignWidth="300" Height="57" MouseEnter="UserControl_MouseEnter_1" MouseLeave="UserControl_MouseLeave_1">
<TextBlock Name="TypeText" TextWrapping="NoWrap" Text="" />
</UserControl>
And in code I need to do something like this to get the TextBlock go away:
private void UserControl_MouseEnter_1(object sender, MouseEventArgs e)
{
Children.Clear(); // There is no such thing as children here!!!
}
The "child element" of the UserControl is contained in the Content property. You can set it to null in order to remove the content.
private void UserControl_MouseEnter_1(object sender, MouseEventArgs e)
{
Content = null;
}

Why isn't change button content working

I have this code:
private void ModifyButton_Click(object sender, RoutedEventArgs e)
{
ModifyButton.Content = "Another button name";
}
But it doesn't work. I mean, the modify button content doesn't change but the program doesn't fail or throw any exception.
I'm trying to modify the button name in order to change it's behavior (kinda Edit/Save) within the same button. Is this not possible using C#/WPF?
Thanks in advance.
EDIT:
XAML:
<Button Name="ModifyButton" Content="Modificar" Margin="5,10,0,0" Height="23" Width="120" HorizontalAlignment="Left" Click="ModifyButton_Click"></Button>
WEIRD BEHAVIOR: If I put a MessageBox.Show call after the change of the button content, then, while the message box is displayed the button dislay the new (changed) name, but after the message box is closed, then it shows it's original text.
I guess that the XAML of your UI is not bound to the value of your button. Did you check the DataBinding?
[EDIT]
Your magic information here is that you use ShowDialog(). As you already guessed, this influences your UI thread and therefore the display behavior. ShowDialog() displays the Form as a modal dialog and blocks your UI thread and therefore blocks the refresh of it. This may cause all sorts of weird behavior.
This is what i have and it works:
Window 1
<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>
<Button Name="ModifyButton" Content="Open Dialog" Margin="80,104,78,0" Height="23" Click="ModifyButton_Click" VerticalAlignment="Top"></Button>
</Grid>
</Window>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void ModifyButton_Click(object sender, RoutedEventArgs e)
{
Window2 win2 = new Window2();
win2.ShowDialog();
}
}
Window 2
<Window x:Class="WpfApplication1.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2" Height="300" Width="300">
<Grid>
<Button Name="ModifyButton" Content="Modificar" Margin="80,104,78,0" Height="23" Click="ModifyButton_Click" VerticalAlignment="Top"></Button>
</Grid>
</Window>
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
}
private void ModifyButton_Click(object sender, RoutedEventArgs e)
{
ModifyButton.Content = "Another button name";
}
}

Categories