question

mauede-6322 avatar image
0 Votes"
mauede-6322 asked Edelweiss-9244 commented

Erratic behavior of TextBox "TextChanged" event

I have inserted in the GUI a TextBox. It must hold a number between 0 and 1 that represents a lower threshold for accepting a structure name guessed
by the Dice coefficient. I have set a default but the user can edit the threshold. Therefore I have to check the number entered is between 0 and 1.
The TextBox is implemented as follows:

TextBox TextChanged event:
<TextBox x:Name="DiceTol" Grid.Column="1" HorizontalAlignment="Left" Margin="655,0,0,0" Grid.Row="1" Text="{Binding DiceThreshold , Mode=TwoWay}" VerticalAlignment="Bottom"
Background="Wheat" FontFamily="Arial Black" FontWeight="Bold" FontSize="20" Width="100" Height="46" Grid.RowSpan="1" TextChanged="DiceTol_TextChanged" TargetUpdated="DiceTol_TargetUpdated" TextInput="DiceTol_TextInput"/>

I developed the code that checks the newly entered number using three different pre-existent TextBox events., namely, "TextChanged", "TargetUpdated", TextInput".
The only event that is triggered is "TextChanged" but it does not work all the times a new number is entered in the TextBox. During the debugging session
first, I erase the default value and then I type in a new value that is on purpose greater than 1 but the "TextChange" event is not triggered. Sometimes it is triggered when I click on a GUI button. The other two events are never triggered.

Here is the code I developed to check the number entered in the TextBox:

private void DiceTol_TextChanged(object sender, TextChangedEventArgs e)
{
if(DiceThreshold < 0 | DiceThreshold > 1)
{
MessageBox.Show("Please, enter a number between 0 and 1", "Warning ", MessageBoxButton.OK, MessageBoxImage.Warning);
DiceThreshold = DiceThresholdDefault;
DiceTol.Text = DiceThresholdDefault.ToString();
emptyEditableStructsListBox();
return;
}
}

I would appreciate your help in fixing the above-illustrated problem.
Thank you



dotnet-csharpwindows-wpf
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi,@mauede-6322. Did my answer solve your problem? If so, you could accept it as the answer. It's helpful for community members with similar questions.

0 Votes 0 ·
HuiLiu-MSFT avatar image
0 Votes"
HuiLiu-MSFT answered HuiLiu-MSFT edited

For the problem of validating the bound data, you could refer to the following code.

MainWindow.xaml.cs:

 public partial class MainWindow : Window
   {
     public double DiceThreshold { get;set;}= 0.3;
     public MainWindow()
     {
       InitializeComponent();
       DataContext=this;
     }
   }
 public class DoubleRangeRule : ValidationRule
       {
         public double Min { get; set; }
        
         public double Max { get; set; }
        
         public override ValidationResult Validate(object value,   CultureInfo cultureInfo)
         {
           double parameter = 0;
        
           try
           {
             if (((string)value).Length > 0)
             {
               parameter = Double.Parse((String)value);
             }
           }
           catch (Exception e)
           {
             return new ValidationResult(false, "Illegal characters or "    + e.Message);
           }
        
           if ((parameter < this.Min) || (parameter > this.Max))
           {
             return new ValidationResult(false,
                 "Please enter value in the range: "
                 + this.Min + " - " + this.Max + ".");
           }
           return new ValidationResult(true, null);
         }
       }

MainWindow.xaml:

 <Window.Resources>
         <local:DoubleRangeRule x:Key="DoubleRangeRule"/>
         <Style x:Key="textBoxInError" TargetType="{x:Type TextBox}">
             <Style.Triggers>
                 <Trigger Property="Validation.HasError" Value="true">
                     <Setter Property="ToolTip"  Value="{Binding RelativeSource={x:Static RelativeSource.Self},  Path=(Validation.Errors)/ErrorContent}"/>
                 </Trigger>
             </Style.Triggers>
         </Style>
         <ControlTemplate x:Key="validationTemplate">
             <DockPanel>
                 <TextBlock Foreground="Red" FontSize="20">!</TextBlock>
                 <AdornedElementPlaceholder/>
             </DockPanel>
         </ControlTemplate>
     </Window.Resources>

 <Grid>
     <TextBox x:Name="DiceTol"    Background="Wheat" Width="100" Height="46"  Validation.ErrorTemplate="{StaticResource validationTemplate}"   Style="{StaticResource textBoxInError}">
                 <TextBox.Text>
                     <Binding Path="DiceThreshold" StringFormat="N2"  UpdateSourceTrigger="PropertyChanged">
                         <Binding.ValidationRules>
                             <local:DoubleRangeRule Min="0.0" Max="1.0"/>
                         </Binding.ValidationRules>
                     </Binding>
                 </TextBox.Text>
             </TextBox>
 </Grid>

The result:

191590-image.png

191701-image.png


If the response is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


image.png (1007 B)
image.png (1.1 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

mauede-6322 avatar image
0 Votes"
mauede-6322 answered Edelweiss-9244 commented

Thank you for the very sophisticated solution.
I wonder whether I can use "Mode=TwoWay" in the binding statement for DiceThreshold. The code needs to use the entered value when it is within the established range.

· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi,@mauede-6322. You could bind "Mode=TwoWay" in code.

 <Binding Path="DiceThreshold" Mode="TwoWay" StringFormat="N2"  UpdateSourceTrigger="PropertyChanged">
0 Votes 0 ·

@HuiLiu-MSFT
I like the red arrow appearing beside the TextBox containing the wrong. However, your code does not allow the entered value, whatever it is (wrong or right) to be passed back from the TextBox Text to the C# variable "DiceThreshold".
I modified your definition of the Text including the TwoWay option:

 <TextBox.Text>
                      <Binding Path="DiceThreshold, Mode=TwoWay" StringFormat="N2"  UpdateSourceTrigger="PropertyChanged">

Unluckily this change inactivates the data validation mechanism. Whatever data is entered in the TextBox Text no error is detected and no red arrow appears. Why?

It would be great if I could still have the data validation mechanism working and also have any value entered pushed back from the GUI to the variable "DiceThreshold"
Thank you


0 Votes 0 ·
mauede-6322 avatar image
0 Votes"
mauede-6322 answered HuiLiu-MSFT commented

@HiuLiu-MSFT
Thank you very much. I got that TextBox working on adopting a simpler solution. Basically, I check the TextBox content when a Button is clicked launching the code stub that uses the TextBox content. If the TextBox numerical content falls outside the range a messageBox alerts the user and the TextBox content is set back to a default value.

However, now I am facing a new challenge and wonder whether the code you sent me could be adapted to my new task.
In MainWindow.XAML I have a ListBox that is used to display a list of strings that can be edited:

  • <ListBox x:Name="EditableStructs" Grid.Row="5" Grid.Column="1" Margin="930,62,0,40" SelectionMode="Single" Grid.ColumnSpan="2" Background="PowderBlue" Height="500"
    ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.CanContentScroll="True" ItemsSource="{Binding AutoNames,Mode=TwoWay}" HorizontalAlignment="Left" Width="220" >
    <ListBox.ItemTemplate>
    <DataTemplate>
    <Grid>
    <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto"/>
    <ColumnDefinition Width="Auto"/>
    <ColumnDefinition Width=""/>
    </Grid.ColumnDefinitions>
    <TextBlock Name="TextInd" Text="{Binding NamInd, Mode=OneWay}" Grid.Column="0" Padding="1,5" HorizontalAlignment="Stretch"/>
    <CheckBox IsChecked="{Binding IsAccepted, Mode=TwoWay}" Grid.Column="1" Padding="5,5" VerticalAlignment="Center" HorizontalAlignment="Center" />
    <TextBox Text="{Binding StrName, Mode=TwoWay}" Grid.Column="2" HorizontalAlignment="Stretch"/>
    </Grid>
    </DataTemplate>
    </ListBox.ItemTemplate>
    </ListBox>
    *



The code-behind in MainWindow.XAML.cs I populate the above ListBox upon clicking a Button:

  •  public class EditableStructures
         {
             public int NamInd { get; set; } = new int();
             public bool IsAccepted { get; set; } = new bool();
             public string StrName { get; set; } = "";
         }
    
         public static List<EditableStructures> AutoNames { get; set; } = new List<EditableStructures>();***
    

  • PTAccess pt = new PTAccess();
    List<string> EditedList = new List<string>();
    EditedList = pt.StructuresAutomaticRename(structures);
    int j = 1;
    foreach (string str in EditedList)
    {
    AutoNames.Add(new EditableStructures { StrName = str, IsAccepted = false, NamInd = j});
    j++;
    }
    // string DbgList = "" ; // DEBUG PURPOSE
    // DbgList = String.Join(" , ", AutoNames.Select(x => x.StrName)); // DEBUG PURPOSE
    // MessageBox.Show($"AUTOMATICALLY RENAMED STRUCTURES: \n {DbgList}"); // DEBUG PURPOSE
    //............................ Compare Number of Guessed Structure Names With Number Of Structure Names From Velocity DataBase
    // ............................ Alert User If Less Than 50% Structures Could Not Be Guessed
    int NumGuessed = 0;
    int NumOriginal = 0;
    var Guessed = AutoNames.Where(m => !string.IsNullOrWhiteSpace(m.StrName)).ToList();
    NumGuessed = Guessed.Count;
    NumOriginal = strucNames.Count;
    MessageBox.Show($" {NumGuessed} structures automatically renamed out of {NumOriginal} patient structures\n", "Is this patient belonging to this trial? ", MessageBoxButton.OK, MessageBoxImage.Information);
    UpdateAutoStrucNames();***

public void UpdateAutoStrucNames()
{
EditableStructs.ItemsSource = (System.Collections.IEnumerable)AutoNames;
}
``
**

Some of the ListBox items contain strings that have been "guessed" through the dice coefficient. The code knows the indexes of the items containing "guessed" strings.
My questions:
How can I draw the user's attention to such ListBox elements? Maybe changing their background color or showing the red "!" symbol as you implemented, or some other way.

I would appreciate some help.
Thank you in advance.



· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi,@mauede-6322. For the new question, I replied under your new question.
Did my answer solve the problem with your TextBox numeric content out of range alert? If so, you could accept it as the answer. It's helpful to community members with similar issues.


0 Votes 0 ·