-
-
Notifications
You must be signed in to change notification settings - Fork 2.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
Make binding internals a private API #9512
Comments
I use |
Thanks for the feedback @jp2masa - that's good to know. Would an alternative API, be OK though? Something like this (naming to be decided): IObservable<object> instancedBinding = BindingOperations.InstanceAsObservable(binding, myControl); (I'm assuming you're using |
It was actually |
Use |
Will this also prevent or impact creating custom binding types? I currently use |
It won't allow binding back easily. The best approach I have in mind is making a base binding class with an abstract method like that:
That should be enough for custom bindings without exposing too much, and WPF is about to make bindings the same except that you have no way to make expressions, but In the proposal above I don't like one thing .NET has, but without which it would be unusable, I mean generic virtual dispatch. It does a great job, but heck as slow, so if it's possible to avoid it, then better to do that. Therefore, the code can be slightly changes:
In this snippet we have two base types instead of one, but no more virtual generic dispatch. At the same time type safety is still preserved since there's a class instances of which represent bindings. No one can inherit from it except
I like the second option mostly because it solves problem C# has, explicitly telling what type a generic parameter has. The complier cannot deduce it and won't deduce it in the foreseeable feature. There's an issue already explaining why it's hard to implement it, but in short, it would slow down the compiler a lot. The proposal also changes the design of value converters by making them strongly typed. That's actually how Visual Studio implements them: while they inherit
The proposal also solves #9525, but instead of an expression there's an observable to be returned or even a pair of an observer and a disposal object to kill the binding, but I would suggest going with two separate methods, one for getting an abservable, another for cleaning up the binding. |
To be kept in mind, API replacement should not use ISubject. Some optional extensions with ISubject might be added though. |
Yeah, the proposed API actually removes that dependency at all, but if there's a need on the old behavior, when an object combines |
Thanks for the writeup @YohDeadfall - some of that is very similar to some of the changes that we'd like to do during the 11.x timeframe, which is why I opened this issue really: to make a lot of our binding machinery internal so that we have the space to change things. I'll take a look at reworking the public binding API with the comments in this thread mind, and also with a mind to removing any public uses of |
@dmirmilshteyn yes it definitely will impact this. Could you explain what you're doing, and what you need a little more? |
There is |
@kekekeks regarding that API:
|
@grokys, compiled bindings can produce an instance of |
@YohDeadfall is this about an upcoming change to WPF? Do they still make changes to WPF?! Do you have a link? |
Nah, it's stale and receives fixes only as far as I know. The thing I wrote is about markup extensions in general which get a service provider containing any available info about the ambient environment which isn't limited to the target only. That's how bindings decide should they return themself (happens in setters) or expressions (happens for properties of real objects). I learned all that stuff about ten years ago when was a WPF dev while doing localization, custom converters producing a dependency object with bindings from a template (yeah, WPF can make a So, from my experience I can say that WPF could be a good framework, but there's a mess with access modifiers and return types, and no flexibility at all. UWP is even worse here, it's limited as hell, but has cool ideas on deferrals and property system inherited from WPF. It's a bit off topic, but as an improvement you can make a delayed property value materialization. For example, text editing in WPF doesn't build a new string each time you type a character. It's made only when a binding triggers or on getting a value from the property changed event args. In case of curiosity what a markup extension receives as a service and which services are available, I recommend making a tiny app with a custom markup extension, drop a breakpoint there and get the type name in case of using it inside a setter and to bind a property on an object. There should be different set of services available. Then go to IL Spy or to WPF repo and look around. |
No idea, but everything that we do from XAML is essentially a public API. Since we are referencing stuff from MSIL, we can't change it, there will be MissingMethodException otherwise. So if there is a way to construct a binding from XAML, it should be considered to be usable from C# too. |
In WPF the main problem with custom bindings is expressions which are private and cannot be used outside for a proper implementation, that's why I suggest observable objects all the way down, it's quite universal. So, your own and any third-party expression is an observable object which is stored by the property system. That will allow having To implement a binding in WPF you have to build your own object inherited from
|
Having it internal and using |
@grokys This is fairly domain-specific, but really benefits from being able to somewhat define custom bindings programmatically outside of XAML. Basically, I have a set of bindings that are convention-driven and transform a simple string into a full compiled binding path. Sometimes the resulting binding paths end up being complex and this setup allows us to insulate that complexity. As an example, consider This substantially simplifies development and allows a lot of flexibility when building domain-specific bindings, and it would be a shame if this feature was closed away. |
That still will cause MissingMethodException if we change anything and the ability to change things is the point of making them internal |
@dmirmilshteyn, do you use reflection, observables and/or notify property changed? I'm curious because I have a pet project which is a Reactive replacement with it's own property system. Therefore, it has custom Avalonia bindings without accessing international code like expression nodes and friends. It works even from XAML after registering a property accessor plugin. My point here is that you can use it at least as an example to solve the migration issues you might have. It doesn't support events yet, but it isn't hard. https://github.com/YohDeadfall/Kinetic There isn't so much documentation, so feel free to open an issue or discussion, or even write privately. |
@dmirmilshteyn I'm currently working on this, and you should still be able to create custom binding extensions using the following pattern (in this case just binding to a predetermined property for simplicity):
Does this work for you? |
@grokys Yeah, that would be perfect! |
Our binding internals need a refactor, for a number of reasons (which I won't get into here), but we probably won't have chance to do this before 11.0, and so it will need to be done during the 11.0 timeframe.
The problem with that is that much of our binding internals are exposed as a public API meaning that we won't be able to refactor it without breaking our API promises. For that reason I think we'll need to make much of our binding internals a private API for 11.0, in particular the following classes:
InstancedBinding
BindingExpression
ExpressionObserver
ExpressionNode
and derived classesIPropertyAccessorPlugin
IDataValidationPlugin
IStreamPlugin
The text was updated successfully, but these errors were encountered: