dotnet / wpf

WPF is a .NET Core UI framework for building Windows desktop applications.
MIT License
7.1k stars 1.17k forks source link

Please add properties to WPF for traversing Parent/Children nodes #10095

Open SetTrend opened 1 week ago

SetTrend commented 1 week ago

I'm trying to write a converter to convert a text selection from FlowDocument to some other text format.

Current Situation

Currently, this is impossbile as all the navigating methods and properties are internal to the WPF framework.

The only workaround is to serialize the selected nodes to XAML using a XamlWriter and using an XmlReader or similar to traverse the generated XML.

The current solution is very cumbersome, slow, memory intensive and unnecessary.

Desired Situation

Please add Parent and Children properties to the DependencyObject class, so we can traverse through any WPF object tree.

miloush commented 1 week ago

Can you please clarify what you have and what you are missing? DepdencyObject does not have children or parents. You can use VisualTreeHelper to navigate the visual tree.

SetTrend commented 1 week ago

I'm trying to write converters from a selection within a WPF FlowDocument into Markdown/HTML and vice versa. Yet, whatever I do, I'm not able to traverse through the selection. Browsing the WPF source code I noticed all the required methods seem to be available, but their protection level is internal.

It would be very desirable to be able to traverse through the WPF DOM like browsing through other DOMs, like XML and HTML. The VisualTreeHelper is just a crook to this regard.

SetTrend commented 1 week ago

It would also be very helpful to have a DependencyObject.Clone() method, returning a (deep) copy of the actual object.

Symbai commented 1 week ago

Browsing the WPF source code I noticed all the required methods seem to be available, but their protection level is internal.

Can you give examples of these methods?

miloush commented 1 week ago

It would also be very helpful to have a DependencyObject.Clone() method, returning a (deep) copy of the actual object.

That's the same as asking there to be a general object.Clone(). That's just not possible, some objects are not cloneable by their nature, and it puts an unreasonable burden to anyone writing any derived class.

miloush commented 1 week ago

Also what is wrong with doing the conversion from XAML? Even when you want to save the selection as RTF, it serializes to XAML and then does XAML to RTF. Furthermore the XAML structure will be very similar to HTML structure, so you likely need to do minimal changes to it, and it takes care of things like inherited properties.

(Note you wouldn't use XamlWriter to turn selection into XAML, it is better to use TextRange.Save)

SetTrend commented 1 week ago

@Symbai:

Sure, see TextRangeSerialization. I didn't wade too deep into these methods as they are internal and, thus, of no avail to me. Yet TextRangeSerialization.FindSerializationCommonAncestor seems a good candidate.


@miloush:

That's the same as asking there to be a general object.Clone().

You are right, I have been too general in my second comment above. Instead, though, I feel it would be reasonable for many classes, particularly the WPF document classes, to implement the ICloneable interface, thereby cloning only all public properties having setters available. As you may know, assigning a Block class from one Block element parent to another one removes the original Block element.

Copying/modifying document elements is way too complicated at the moment. This is particularly true as these classes don't implement common interfaces. FlowDocument and Section, for instance, both provide the property BlockCollection Blocks and both derive from FrameworkContentElement, but they don't implement a common interface (e.g. something like BlockContainer), so you need to write duplicate code if you want to inspect their corresponding Blocks collection.


Note you wouldn't use XamlWriter to turn selection into XAML, it is better to use TextRange.Save()

That's what I'm actually doing right now.

Also what is wrong with doing the conversion from XAML?

What's wrong is that it doubles execution time by first converting an in-memory object tree into XAML and then, in a second iteration, into another format.

Serializing into XAML requires exactly the same steps as serializing into any other format would require (except for plain text). So this is a sluggish, non-performant solution, particularly for larger documents.