wpf: After user click the Expander header, IsExpanded not work by trigger.
- .NET Core Version:
.NET SDK (反映任何 global.json):
Version: 5.0.201
Commit: a09bd5c86c
运行时环境:
OS Name: Windows
OS Version: 10.0.19042
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\5.0.201\
Host (useful for support):
Version: 5.0.4
Commit: f27d337295
.NET SDKs installed:
2.2.207 [C:\Program Files\dotnet\sdk]
5.0.201 [C:\Program Files\dotnet\sdk]
- Windows version:
Win10 20H2
- Does the bug reproduce also in WPF for .NET Framework 4.8?: I don’t know.
- Is this bug related specifically to tooling in Visual Studio (e.g. XAML Designer, Code editing, etc…)? If yes, please file the issue via the instructions here.
- Security issues and bugs should be reported privately, learn more via our responsible disclosure guidelines.
Problem description:
I want to expand the Expander
when the TextBox
has validation error. But after I click the Expander
header by mouse once, the IsExpanded
property never works.
Let’s see, its background is changed, so the trigger is no problem.
Actual behavior:
After user click the Expander
header, Expander.IsExpanded
no longer expand the content.
Expected behavior:
After user click the Expander
header, Expander.IsExpanded
should expand the content when it is True
.
Minimal repro:
About this issue
- Original URL
- State: open
- Created 3 years ago
- Comments: 15 (7 by maintainers)
@GF-Huang - I can explain why this is happening, but I don’t see how to achieve the effect you want. I think it needs a new feature.
The problem is an unfortunate interaction between your declaration
and a declaration for the Expander’s ToggleButton (from the theme style):
When you click the button, the second binding writes a new value into the expander, essentially calling expander.SetValue(IsExpandedProperty, true). The first time this happens, it overwrites the first binding, which goes away never to return. You can see this using the VS Live Property Explorer: look at the expander’s IsExpanded property in the “Local” section and be prepared to refresh or re-select the expander (the explorer in my version of VS is not as “live” as it should be); before clicking it shows a BindingExpression, after clicking it shows a raw boolean value.
This overwriting wouldn’t happen if your binding were two-way, or if the second binding used SetCurrentValue instead of SetValue. But I don’t see how to use a two-way binding to get your effect, and there’s no way to tell the second binding to use SetCurrentValue. And I haven’t found any other tricks to work around this problem (replacing the second binding, using intermediate properties, intercepting the SetValue call, etc.). Maybe someone in the community is up to the challenge?
Feature request: A setting on Binding that tells it to use SetCurrentValue to write values, if possible. Update Expander’s theme style to use the setting. Locate and update all similar uses.
Alternatively: Breaking change to make Binding always use SetCurrentValue. Of course, only if a deep study proves that it’s always the right thing to do.
History: WPF controls used to use SetValue to change their own properties, which caused hundreds of bugs similar to yours because SetValue overwrites one-way bindings and hides values from styles, triggers, and templates. We introduced SetCurrentValue in .NET 4.0 to fix this, but didn’t consider the indirect case of a two-way binding doing the change. And yours is the first complaint I’m aware of in the 12 years since then. So it’s apparently not a common scenario.
Ran into the same problem, but could replace the Expander with a “selfmade” Expander that is made up of a ToggleButton and content area. The binding with the isChecked Property of the ToggleButton does work as expected unlike the Expanders property.
@lindexi - no, not today. [I would have mentioned it if there were.]