Skip to content
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

Merged
merged 4 commits into from
Apr 27, 2023

Conversation

batzen
Copy link
Contributor

@batzen batzen commented Jul 3, 2019

This is a fix for #1166

@ghost ghost requested review from vatsan-madhavan, rladuca, ryalanms and stevenbrix July 3, 2019 19:57
@ghost ghost added the PR metadata: Label to tag PRs, to facilitate with triage label Jul 3, 2019
@ghost ghost requested a review from SamBent July 3, 2019 19:58
Base automatically changed from master to main March 17, 2021 17:38
@ryalanms ryalanms requested a review from a team as a code owner March 17, 2021 17:38
@batzen
Copy link
Contributor Author

batzen commented Mar 12, 2022

@dotnet/wpf-developers any news on this one?

@batzen batzen added the Community Contribution A label for all community Contributions label May 5, 2022
@ghost ghost assigned batzen May 5, 2022
@dipeshmsft
Copy link
Member

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.

@batzen batzen force-pushed the ValidationAdornerForNoLoadedUI branch from cac2cd5 to 1d45c75 Compare March 23, 2023 18:19
@batzen
Copy link
Contributor Author

batzen commented Mar 23, 2023

@dipeshmsft There were no conflicts.
I rebased just to be sure.

After pulling in all the changes from main i can't compile anymore as i get the error

C:\DEV\OSS_Own\dotnet\wpf\eng\WpfArcadeSdk\tools\Wpf.Cpp.targets(552,5): error : 'WriteOnlyWhenDifferent' attribute on
"C:\DEV\OSS_Own\dotnet\wpf\artifacts\obj\uce\Win32\Debug\CppSupport\CppSupport_uce.csproj" takes effect only when 'Over
write="true"'. [C:\DEV\OSS_Own\dotnet\wpf\src\Microsoft.DotNet.Wpf\src\WpfGfx\core\uce\uce.vcxproj]
    0 Warning(s)
    179 Error(s)

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;
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Member

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?

Copy link
Contributor

@miloush miloush Apr 4, 2023

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.

Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

@miloush miloush Apr 4, 2023

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?

Copy link
Contributor

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.

Copy link
Contributor Author

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...

Copy link
Contributor Author

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.

@dipeshmsft
Copy link
Member

@dipeshmsft There were no conflicts. I rebased just to be sure.

After pulling in all the changes from main i can't compile anymore as i get the error

C:\DEV\OSS_Own\dotnet\wpf\eng\WpfArcadeSdk\tools\Wpf.Cpp.targets(552,5): error : 'WriteOnlyWhenDifferent' attribute on
"C:\DEV\OSS_Own\dotnet\wpf\artifacts\obj\uce\Win32\Debug\CppSupport\CppSupport_uce.csproj" takes effect only when 'Over
write="true"'. [C:\DEV\OSS_Own\dotnet\wpf\src\Microsoft.DotNet.Wpf\src\WpfGfx\core\uce\uce.vcxproj]
    0 Warning(s)
    179 Error(s)

Any hints on how to get it to compile?

@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.

@dipeshmsft
Copy link
Member

@batzen I have made the necessary changes in this PR #7678, you can try it once now.

@batzen batzen force-pushed the ValidationAdornerForNoLoadedUI branch from 1d45c75 to cc8e414 Compare March 31, 2023 09:45
@dipeshmsft dipeshmsft merged commit e80b23b into dotnet:main Apr 27, 2023
@dipeshmsft
Copy link
Member

@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.

@ghost ghost locked as resolved and limited conversation to collaborators May 27, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Community Contribution A label for all community Contributions PR metadata: Label to tag PRs, to facilitate with triage
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants