I know I have seen this problem before somewhere, but I'm not sure if there was an answer at the time. I'm trying to add SpellCheck to a TextBox in WPF, .NET 4.0. It works fine in terms of finding and marking the incorrect words, and will replace the first word in the TextBox if it's incorrect. Anything past word one though, and it just moves the carat to the start of the TextBox without changing anything? As I said I saw this somewhere about 6-9 months ago, but now everything I come up with in google deals with alternate languages (I'm staying strictly in English for now). I've included the event methods and styling XAML only for completeness, I don't think the issue lies there.
XAML:
<MultiBox:MultiBox Name="callNotes" Grid.Column="1" Width="Auto" Height="Auto" Margin="2,5,15,20" VerticalAlignment="Stretch" AcceptsReturn="True" FontWeight="Bold" GotFocus="callNotes_GotFocus" SelectAllOnGotFocus="False" SpellCheck.IsEnabled="True" xml:lang="en-US" Style="{StaticResource TextBoxStyle}" TextChanged="callNotes_TextChanged" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" />
<Style x:Key="TextBoxStyle" TargetType="{x:Type MyNamespace:MultiBox}">
<Setter Property="CharacterCasing" Value="Upper" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Height" Value="23" />
<Setter Property="Width" Value="Auto" />
<Setter Property="SelectAllOnGotFocus" Value="True" />
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
Code:
private void callNotes_TextChanged(object sender, TextChangedEventArgs e)
{
callNotes.Text.ToUpper();
lineCountOne.Content = ((callNotes.Text.Length / 78) + 1);
}
private void callNotes_GotFocus(object sender, RoutedEventArgs e)
{
callNotes.CaretIndex = callNotes.Text.Length;
}
It would help to see your code which attempts to correct the errors. Here's simple code which loops through all the detected errors and accepts the first suggestion. If you only want to fix particular errors, you'll need to skip to the particular error you're interested in by getting the error at a certain index.
int ndx;
while ((ndx = callNotes.GetNextSpellingErrorCharacterIndex(0, LogicalDirection.Forward)) != -1)
{
var err = callNotes.GetSpellingError(ndx);
foreach (String sugg in err.Suggestions)
{
err.Correct(sugg);
break;
}
}
After trying jschroedl's suggestion and still having no luck (although I do know that his answer should have been correct), I started playing with every possible setting I could think of, even to the point of creating a completely new WPF project with a single, Spellcheck-enabled TextBox just to make sure it wasn't something with the Visual Studio/.NET installation itself. Turns out it wasn't, it was something I had done months ago to ensure that selecting any given TextBox through the program would result in the SelectAll() method being triggered. Once I screened out this particular TextBox from that bit of code, all works great. Again, thanks to jschroedl, I know there is no way he could have known this. The offending code is below, in case anybody comes across a similar issue.
protected override void OnStartup(StartupEventArgs e)
{
EventManager.RegisterClassHandler(typeof(TextBox), UIElement.GotKeyboardFocusEvent, new RoutedEventHandler(SelectAllText), true);
base.OnStartup(e);
}
protected static void SelectAllText(object sender, RoutedEventArgs e)
{
var textBox = e.OriginalSource as TextBox;
if (textBox != null && textBox.Name != "callNotes")
textBox.SelectAll();
}
Adding the && textBox.Name != "callNotes" solved the problem.
Related
I am attempting to create Coded UI tests on a WPF application. I am using Visual Studio 2019 to create / run the tests.
I am running into a strange behavior where a WPF button that was collapsed at startup (but is later made visible/enabled) is not showing any child nodes using any of the FindXXX methods available to the AutomationElement object associated with the button. Other buttons that were not collapsed do not seem to have this problem. I should note that the reason I am expecting child nodes for this WPF button is that in the XAML it is defined similar to the following:
<Button x:Name="ButtonStop" Grid.Row="0" Grid.Column="2" Command="{Binding TheVm.StopCommand}">
<Button.Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource ButtonStyleA}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding TheVm.DisplayButton}" Value="False">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
<StackPanel Style="{StaticResource ControlsStackPanelStyle}">
<Image Source="pack://application:,,,/Assets/icon1.png" Style="{StaticResource ControlsButtonImageStyle}"/>
<ContentPresenter Content="Stop" Style="{StaticResource ControlsButtonTextStyle}"/>
</StackPanel>
</Button>
Using the INSPECT.EXE application I can see the child nodes of this button correctly, but when I traverse the AutomationElements I have access to they are missing.
The test code I am using to check the human-readable text is:
// Wait for 'Stop' button to become enabled, and verify correct text
uIButtonStopButton.WaitForControlEnabled();
var displayText = (!uIButtonStopButton.DisplayText.Equals(""))
? uIButtonStopButton.DisplayText
: GetFirstNodeText(uIButtonStopButton.NativeElement as AutomationElement;
Assert.AreEqual("Stop", displayText, "Stop button doesn\'t have correct text.");
Where the GetFirstNodeText method is as follows:
private static string GetFirstNodeText(AutomationElement automationElement)
{
if (automationElement != null)
{
// Get first AutomationElement node that is a 'text' control-type
var textEl = automationElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.LocalizedControlTypeProperty, "text"));
if (textEl != null) return textEl.Current.Name;
}
return "";
}
An additional (interesting) piece of information: I tried a similar test using Appium/WinAppDriver and had an almost identical experience - no child nodes on the formerly collapsed button.
What could be causing this and do you have any advice for this?
To verify your are working with up-to-date AutomationElement objects, be sure to check this question about refreshing your controls.
But since you mentioned having a almost identical problem using WinAppDriver, I rather think the problem will be with the application under test.
If you have access to the source code / developers working on that code, please take a closer look to the code/xaml involving this button and its children. The problem will most likely be found there.
As I previously said in this question, I'm new at Xamarin.Forms and I'm developing a cross-platform web browser with Microsoft Visual Studio 2017 version 15.5.4. I'm debugging on an Android 5.1 smartphone.
In my layout there's a WebView and two Buttons to go back/forward.
<Button Image="backarrowdisabled.png"
Grid.Row="1"
Grid.Column="0"
x:Name="backButton"
IsEnabled="False"
Clicked="previousPage">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding CanGoBack, Source={Reference appWebView}}"
Value="False">
<Setter Property="IsEnabled" Value="False" />
<Setter Property="Image" Value="backarrowdisabled.png" />
</DataTrigger>
<DataTrigger TargetType="Button"
Binding="{Binding CanGoBack, Source={Reference appWebView}}"
Value="True">
<Setter Property="IsEnabled" Value="True" />
<Setter Property="Image" Value="backarrow.png" />
</DataTrigger>
</Button.Triggers>
</Button>
<Button Image="nextarrowdisabled.png"
Grid.Row="1"
Grid.Column="5"
x:Name="nextButton"
IsEnabled="False"
Clicked="nextPage">
/* triggers */
</Button>
<WebView Grid.Row="3"
Grid.Column="0"
Grid.ColumnSpan="6"
x:Name="appWebView"
Source="https://www.google.it/"
Navigating="onPageLoading"
Navigated="onPageLoaded"/>
As you can see there are two methods to manage Navigating and Navigated events, which are
private void onPageLoading(object sender, WebNavigatingEventArgs e)
{
URLEntry.Text = e.Url; //Entry where I can see the page URL
//other code
}
private void onPageLoaded(object sender, EventArgs e)
{
//some code
}
When I click on a link or something like that in my WebView everything works correctly, but when I have to go back/forward in my history the Entry doesn't update the URL to the previous/next one. It seems it doesn't even call the onPageLoading method, but the WebView loads the page.
These are the methods called by the Buttons
private void previousPage (object sender, EventArgs e)
{
appWebView.GoBack();
}
private void nextPage (object sender, EventArgs e)
{
appWebView.GoForward();
}
Is it a WebView bug or am I doing something wrong?
Edit: I think the pages are cached, is there a way to make it not do it?
One thing you can do, is to create another event handler for the WebView's PropertyChanged or PropertyChanging event. There, you can check to see if the Source property was changed; If so, you can update the TextView with the new source. (I'm not sure exactly, but it seems like whe navigating back or forward, the Navigating event does not get called, possibly because the page is already cached?)
See here: https://developer.xamarin.com/api/member/Xamarin.Forms.WebView.OnPropertyChanged/p/System.String/
So your code can look like
<WebView x:Name="MyWebView" PropertyChanged="OnWebViewPropertyChanged" />
and then your code behind:
private void OnWebViewPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == WebView.SourceProperty.PropertyName)
{
URLEntry.Text = MyWebView.Source.ToString(); // May need to check this
}
}
I am looking for a solution to making touch able to handle toggling a toggle button when IsManipulationEnabled = true. I have to keep on IsManipulationEnabled due to underlying 3d map.
Here is the test project I have been using.
<Window x:Class="TestingEventManager.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" IsManipulationEnabled="True">
<StackPanel HorizontalAlignment="Stretch">
<ToggleButton Height="40">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Setter Property="Content" Value="OFF"/>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="ON"/>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
<ComboBox SelectedIndex="0" Height="40">
<ComboBoxItem>Test 1</ComboBoxItem>
<ComboBoxItem>Test 2</ComboBoxItem>
</ComboBox>
</StackPanel>
I have looked into setting it in the app.xaml style, but setting it just for togglebutton seems to not extend down into the combobox style and it can be easily overridden by another style.
I also would not like to make a custom class because then everyone would need to remember to use this derived class.
Here is a msdn blog article that describes some of these issues with mixing touch
MSDN blog article
And here is an article with someone having a similar problem, but she just extended the button.
MSDN Social Article
Well last night I came up with somewhat of a solution that I am going to roll with in our code. It is not the best solution due to it always turning on ManipulationEnabled for every togglebutton and its manually handling the IsChecked now, but its the only thing I could come up with to always manipulate every togglebutton.
private void EnableTouchDownTogglingOfToggleButton()
{
EventManager.RegisterClassHandler( typeof( ToggleButton ), ToggleButton.LoadedEvent, new RoutedEventHandler( TurnOnManipulaitonEnabled ) );
EventManager.RegisterClassHandler( typeof( ToggleButton ), ToggleButton.TouchDownEvent, new RoutedEventHandler( EnableTouchDownTogglingHandler ) );
}
private void TurnOnManipulaitonEnabled( object sender, RoutedEventArgs e )
{
// need to make sure all toggle buttons behave the same so we always assume IsManipulationEnabled is true
// otherwise it can open then close right after due to it firing again from mousedown being able to go through
ToggleButton toggle = sender as ToggleButton;
if ( toggle != null )
toggle.IsManipulationEnabled = true;
}
private void EnableTouchDownTogglingHandler( object sender, RoutedEventArgs e )
{
ToggleButton toggle = sender as ToggleButton;
if ( toggle != null )
toggle.IsChecked ^= true;
}
Some days ago I've faced with strange behaviour of text inside Button (I guess the same behaviour I would got for other ContentControls). Let me explain the situation. I have a style definition in App.xaml for TextBlock:
<Application.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="10"/>
</Style>
</Application.Resources>
In MainWindow.xaml I have the same style definition, that should override style that defined in App.xaml. Also I have 3 buttons in Window. In first button explicitly defined TextBlock control inside button's content. For second button I set a string as content in codebehind. For third button I set an integer value as content in codebehind. Here is code of MainWindow.xaml:
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="0"/>
</Style>
</StackPanel.Resources>
<Button Name="Button1">
<Button.Content>
<TextBlock Text="Button with text block"/>
</Button.Content>
</Button>
<Button Name="Button2" />
<Button Name="Button3" />
</StackPanel>
and MainWindow.xaml.cs:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Button2.Content = "Button with string";
Button3.Content = 16;
}
And now what we see? Text in first and third buttons, as expected, have margins 0px, but text in second button have margins 10px! The question is: why second button has 10px margins and how set zero margins for second button (removing style from App.xaml is not possible)?
Thank you!
When I change
Button2.Content = "Button with string";
to
Button2.Content = "Button with _string";
the button's margin changes from 10 to 0.
This is a bug in WPF; it already has been reported on Microsoft Connect.
I am not 100% sure but I think the behavior you saw is caused by the same root cause.
By the way: the correct behavior would be that buttons 2 and 3 have Margin=10; this is because resource lookup is performed along the logical tree, not along the visual tree. The TextBlocks in the buttons 2 and 3 are not inside the logical tree of the StackPanel.
I can't give you a definitive answer, but I notice that it's the difference between setting a string and an integer which causes the different styles to be applied.
Since setting Content to a value that requires a conversion results in correct style being applied, I tried this:
private void WindowLoaded(object sender, RoutedEventArgs e)
{
Button2.Content = new TextHolder("Button with string");
Button3.Content = 16;
}
public class TextHolder
{
private readonly string _text;
public TextHolder(string text)
{
_text = text;
}
public override string ToString()
{
return _text;
}
}
and the margin is now 0. I would be interested in understanding exactly what is going on.
I'm having a problem where I have a DataGridColumnHeader that is receiving text with underscores as the content, and the first underscore is hidden unless you press alt ("data_grid_thing" displays as 'datagrid_thing"). I searched around for a bit, and found some solutions to this problem for Labels, since if you turn RecognizesAccessKey to false, then the text won't be considered 'AccessText' (. This however doesn't work for DataGridColumnHeader, as it removes all the other styling, and so instead of a header with text inside of it, I just get whitespace with text. I tried using the BasedOn property as well to no effect.
I am open to solutions either through the C# side (modifying the RecognizesAccessKey property by somehow finding the ContentPresenter perhaps), or through modification of XAML (figuring out a way to preserve the default style).
My XAML looks something like this:
<Style x:Key="DataGridColumnHeaderStyle" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridColumnHeader">
<Border>
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
RecognizesAccessKey="False" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Thanks!
It's because of AccessKey handling. Just write an event handler like this to temporarily escape the underscores in the datagrid header.
private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
string header = e.Column.Header.ToString();
// Replace all underscores with two underscores, to prevent AccessKey handling
e.Column.Header = header.Replace("_", "__");
}
This blog post says that you can escape the underscore by doubling it: "data__grid_thing".
Another approach can be found in the accepted answer to this question
I like umbreon222's solution. If you're like me and use DataGrids all the time and have a library you always reference (like I do), you can create a child of the DataGrid class that registers that event handler all the time:
using System.Windows.Controls;
namespace MCLBZ7.Controls
{
public class MCLDataGrid : DataGrid
{
public MCLDataGrid() : base()
{
this.AutoGeneratingColumn += DG_AG_Header;
}
private void DG_AG_Header(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
string header = e.Column.Header.ToString();
e.Column.Header = header.Replace("_", "__");
}
}
}