Does anyone know what is the easiest way to get from an EditorButton object to the associated EditorButtonUIElement?
I don't think you can get the UIElement from a single button instance. The button object may be represented by more than one UIElement. If the button is in a grid cell, for example, it will show up with a different UIElement in each cell.
If you are just using the editor control, where there is only a single instance, then you could get the element from the control using control.UIElement.GetDescendant and passing in the button as context.
But this seems like a really odd thing to do. You cannot modify the UIElement in this way... so why are you trying to get it? What are you trying to do?
A little background...we use the IDataErrorInfo pattern to relay business object error information to our users. One of our major UI elements used throughout our application is a custom editor that inherits from EditorWithText.
The custom editor has an internal error state that we need to pass along to the user. For consistency sake, our UI designers would like to simulate the IDataErrorInfo behavior (error icon within the editors UI space)...complete with a tool tip message giving details about the error.
Since the error is fully contained within the editor, I cannot take advantage of the normal IDataErrorInfo implementation our application uses.
In an attempt to satisfy the UI requirement, I want to use a flat borderless EditorButton to display the error icon within the editor. My issue is that I need a way to connect the tool tip text that provides the detail of the error to the EditorButtonUIElement that is displaying the error icon.
I would like to design this in a way that can be used for other places that we need tool tips...so instead of inventing my own complicated plumbing that generalizes this behavior across lots of different types of UIElements, I was hoping to leverage the ToolTipItem property of the EditorButtonUIElement.
If I could set the ToolTipItem property when the EditorButton was created, it would be really easy to get the tool tip displayed when the mouse enters the element.
I realize that Cell and MergedCell are the only grid objects that natively take advantage of the ToolTipItem to display the tool tip (working in 8.2), but I would like to put code in MouseEnterElement could use the UIElement directly to display the tool tip. In the future, if the grid started to use the ToolTipItem more generally across different types of UIElement objects, I would be prepared to take advantage of it...and would only need to add exclusions to my custom tool tip display code in MouseEnterElement.
Thoughts?
Here's what I ended up doing.
I made my own class that inherited from EditorButton that took the tool tip text as a parameter of the constructor. In that class I overrode the CreateUIElement method...let MyBase.CreateUIElement create the UIElement for me, then I set the ToolTipItem property to a custom helper class that imlements IToolTipItem.
In my editor I added code to conditionally add the button based on the editors internal error state.
I was then able to remove all the code I had added to MouseEnterElement and MouseLeaveElement and the grid "automagically" took care of the rest.
Thanks for the clues...they did help me understand what was going on and got started me down the right path.
Okay, I think there might be a way to do what you want without a CreationFilter. But I don't think it can be done with an EditorButton. Remember that the editor services an entire column. So there's no way it can validate data in a general sense. It can only do so when it has some kind of context for the row whose data is to be examined.
What I would do is derive an editor from one of the existing editor classes, like EditorWithText. You are already doing this, I think.
When you create this editor, you will need to supply it with a DefaultOwner (a class that derives from DefaultEditorOwner). Your derived DefaultEditorOwner can override the GetExtendedInfo method. This method passes you a context (this will either be the grid cell or maybe the row) and allows you to pass back an object to the editor which contains any information you want. So you could pass in an image or some object that describes the error information, if any, for the given cell.
You might be able to use this information on the editor class to add or remove buttons, but I suspect that will not work.
What you probably have to do is override GetEmbeddbleElement and GetEmbeddableElementType on your editor and then return a custom UIElement for your editor which handles displaying the text and the image. This is very similar to use a CreationFilter, but it will be outside the existing CreationFilter logic and be part of the editor, so you don't have to hook anything else up on the grid-side of the application.
Your UIElement can derive from EditorWithTextUIElement, which is the normal element that EditorWithText uses and then you can override CreateEditorElements to call into the GetExtendedInfo on the owner, determine what images you need to display and insert some image elements into the element.
None of this is trivial, of course. You are delving pretty deeply into the embeddable editor infrastructure. But I'm pretty sure it's doable.
I'm pretty sure you don't. :-)
We use IDataErrorInfo to handle errors from our business objects...the grid's built in implementation handles those errors just fine. Our users love it so much they want all the errors...even those coming from the UI itself to display the same way.
In this case, the error I need to display is being raised by the custom editor itself. It is the editor's internal error state I am trying to display...not a data error...so there really is no way for me to inject the error down several layers to get it to display through IDataErrorInfo in the normal way.
It is also NOT the cell image that I need to change. I want to encapsulate this behavior within my custom editor...so I need an image within the custom editor's space. The EditorWithText object does not expose an image collection (or even a single image for that matter)...so I am stuck using a button so that I can take advantage of its image.
We use this editor at the cell level...so when it displays an image it only appears in the cell containing the editor in question.
We would also prefer not to have a CreationFilter dependency. We are already using a CreationFilter for other things that cannot be implemented any other way...and do not want to increase its already considerable complexity.
Ultimately, we also want to keep as much of this behavior as possible encapsulated within the custom editor itself (I have enough angst about needing custom code within the MouseEnterElement event to handle the tool tip). We use this control EVERYWHERE within our applications and we want to make as a few ripples as possible.
I'm not sure I follow the approach you are trying to take here.
If I understand you correctly, you want to show an image in a cell that has errors (as determined by the IDataErrorInfo implementation on the data source). I'm a little fuzzy on why you need a custom editor for this, since the grid already has this support built-in, and it actually works with EditorWithText. So your derived EditorWithText should already be handling this and you should not have to do anything.
But let's assume that you have to use your own editor, for whatever reason. So rather than apply an image to the cell, you want to use an EditorButton? That doesn't make a lot of sense to me, because the button will end up displaying in every cell of the column, not just the ones with errors. Do you have error information to display in every cell?
It seems to me that if you want to display an image in some cells of the grid, then there are better ways to do it than to use a button. What I would do is assign a completely blank, transparent an image to the column in the grid. This will have the effect of reserving space in every cell of the column for a possible image and create an Image UIElement for each cell.
Then all you have to do is use a CreationFilter to set the image on this element and use the ToolTipInfo to set a tooltip on it, as needed.