C
C#3mo ago
πR

ObeservableProperty onChange is called twice?

I am using the avalonia mvvm project. in my ViewModel I have this part of code:
c#
public ObservableCollection<MarkdownBlock> MarkdownBlocks { get; } = new ObservableCollection<MarkdownBlock>();

[ObservableProperty]
private string _bottomEditorContent = "";

private bool _isHandlingContentChange = false;

// Partial method that will be called when `BottomEditorContent` changes
partial void OnBottomEditorContentChanged(string value)
{
// Prevent recursive triggering of the property change
if (_isHandlingContentChange)
return;

_isHandlingContentChange = true;

try
{
HandleNewLines(BottomEditorContent);
}
finally
{
_isHandlingContentChange = false; // Reset flag after handling
}
}


private void HandleNewLines(string content)
{
if (!string.IsNullOrEmpty(content) && content.Contains("\n"))
{
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
AddBlock(BottomEditorContent, pipeline);
BottomEditorContent = "";
}
}
c#
public ObservableCollection<MarkdownBlock> MarkdownBlocks { get; } = new ObservableCollection<MarkdownBlock>();

[ObservableProperty]
private string _bottomEditorContent = "";

private bool _isHandlingContentChange = false;

// Partial method that will be called when `BottomEditorContent` changes
partial void OnBottomEditorContentChanged(string value)
{
// Prevent recursive triggering of the property change
if (_isHandlingContentChange)
return;

_isHandlingContentChange = true;

try
{
HandleNewLines(BottomEditorContent);
}
finally
{
_isHandlingContentChange = false; // Reset flag after handling
}
}


private void HandleNewLines(string content)
{
if (!string.IsNullOrEmpty(content) && content.Contains("\n"))
{
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
AddBlock(BottomEditorContent, pipeline);
BottomEditorContent = "";
}
}
however when I enter something inside the TextBox (bottom) the content gets added twice as textblock. HandleNewLine is called with content\n then it sets BottomEditorContent to "", which again calls the onChanged listener (returns in this case). The listener finished after this. Then however the listener is called again with the old content\n ???? Why? The relevant part of my axaml as screenshot:
No description
5 Replies
πR
πROP3mo ago
this is so weird. lets say I hav entered test in the textbox. then I press enter. Now OnBottomEditorContentChanged gets called with oldValue="test" and newValue ="test\n" it then calls HanldeNewLines, which sets the value to "". So OnBottomEditorContentChanged gets called again with oldValue="test\n" and newValue="". But as _isHandlingContentChange is still set to false, it returns. The first call then comes to the finally block and sets _isHandlingContentChange to false. But now the thing I don't understand: OnBottomEditorContentChanged gets called AGAIN with oldValue="" and newValue="test\n" Why this last call??? is it from the UI being behind? am I missing something?
Keswiik
Keswiik3mo ago
Not sure exactly why this is happening, but my guess is some kind of race condition / wonkiness due to how you're checking for content. Might have better luck using KeyDown or KeyUp events - you can check to see if enter was pressed and, if so, take the content of your text box (assuming it isn't empty) and append it to your content. Would prevent updates from potentially re-triggering that logic and doing weird stuff.
πR
πROP3mo ago
When I commented the line BottimEditorContent="" out, it was just called once, as it should. If it is due to some sort of race condition, would there be a way of using semaphore/mutex/whatever? I also might try it with keyUp
Keswiik
Keswiik3mo ago
KeyUp sounds like a better approach to me personally, I'd try it before attempting to use locks
πR
πROP3mo ago
Using this, which basically does the same es keyup with a check for enter:
<TextBox Text="{Binding BottomEditorContent, Mode=TwoWay}"
TextWrapping="Wrap"
Background="Chartreuse">
<TextBox.KeyBindings>
<KeyBinding Command="{Binding HandleBottomEditorEnterCommand}" Gesture="Enter" />
</TextBox.KeyBindings>
</TextBox>
<TextBox Text="{Binding BottomEditorContent, Mode=TwoWay}"
TextWrapping="Wrap"
Background="Chartreuse">
<TextBox.KeyBindings>
<KeyBinding Command="{Binding HandleBottomEditorEnterCommand}" Gesture="Enter" />
</TextBox.KeyBindings>
</TextBox>
it now works.
Want results from more Discord servers?
Add your server