-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixing validation adorner for not yet visible controls #1167
Fixing validation adorner for not yet visible controls #1167
Conversation
src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/validation.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/validation.cs
Outdated
Show resolved
Hide resolved
@dotnet/wpf-developers any news on this one? |
Hey @batzen, we ran the test pass on this PR and are ready to take this PR. Can you please resolve the conflicts in this PR? Thanks a lot for this contribution. |
cac2cd5
to
1d45c75
Compare
@dipeshmsft There were no conflicts. After pulling in all the changes from main i can't compile anymore as i get the error
Any hints on how to get it to compile? |
// This is needed because controls hosted in Expander or TabControl don't have a parent/AdornerLayer till the Expander is expanded or the TabItem is selected. | ||
if (siteUIElement.IsVisible == false) | ||
{ | ||
siteUIElement.IsVisibleChanged += ShowValidationAdornerWhenAdornerSiteGetsVisible; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the element not become IsVisible = true before the loading finishes? Because then the repeated attempt would fail and you would not get the Loaded attempt which you get now otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know how a not loaded control should be visible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@miloush were you able to get any instances where the above condition will hold true? Or if you can suggest a way to check that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about this:
using System;
using System.Collections;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
class AlwaysError : INotifyDataErrorInfo
{
public bool HasErrors => true;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IEnumerable GetErrors(string propertyName) => new[] { "Error" };
}
class Program
{
[STAThread]
static void Main(string[] args)
{
Window w = new();
TextBox t = new() { Margin = new Thickness(50) };
BindingOperations.SetBinding(t, TextBox.TextProperty, new Binding("HasErrors") { Source = new AlwaysError(), Mode=BindingMode.OneWay });
t.Loaded += delegate
{
if (t.Parent is not AdornerDecorator)
{
AdornerDecorator ad = new();
w.Content = ad;
ad.Child = t;
}
};
w.Template = new ControlTemplate(typeof(Window)) { VisualTree = new FrameworkElementFactory(typeof(ContentPresenter)) };
w.Content = t;
new Application().Run(w);
}
}
If I am right this will get a decorator currently but will not after this PR.
EDIT: it would if Window did not come with a decorator by default.
EDIT2: ...so just use a Window template without decorator, amended.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also what if the control never gets visible? Aren't we leaking references by subscribing to IsVisibleChanged?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We won't leak as the handler is static and not an instance member, but i will also test that.
Will have a look at the sample you posted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RenderTargetBitmap might be another scenario that could be affected. EDIT: RTB is broken anyway, I can't get the adorner show up easily.
Since the code already protects against re-entrancy, why don't we just keep the current codepath and add your visibility check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The basic premise is that IsVisible
is set to true for all controls before the Loaded
events are fired (and the controls first displayed) and that is still before the dispatcher gets to the Loaded priority operations. That is a lot of opportunities in between for people to mess up with the tree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good points.
Will have a look at the workaround code i am using in our products again.
It's been nearly four years since i wrote the PR...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dipeshmsft @miloush I made changes that should prevent the code from introducing any regressions.
I also confirmed that the changes don't lead to leaks if an element never gets visible.
@batzen I see, I will put up a workaround that I had for this up after which you will be able to build it locally. |
1d45c75
to
cc8e414
Compare
@batzen, thanks for your contribution. Once, the right area of the test is open-sourced, I think we should add the tests for this fix. |
This is a fix for #1166