Hi
I am getting data to my ultracombo from a webservice.
There are some 50,000 records but we sensibly provide a most recently used subset and dynamically
filter as the user is typing.
If the user does not see the entry they want, we want a mechanism whereby they can reqest more data.
I've tried a few options none of which i cant get working
1. Catch the scroll event and if the scrollbar is at the bottom more data will be requested similar to when you search for images in google and start scrolling down.
this doesnt work because there doesnt seem to be any event to figure this out and SPY++ shows that the WM_VSCROLL event isnt being sent.. Adding a WndProc handler shows the same.
2.Add a fake summary row with a hard coded "Click for more" text and catch the mouse click event.
Again there is no event handler and SPY++ shows no mouse click events are being sent
3. Add a fake row at the end with hard coded "Click for more"
Still no mouse click events so the only (hacky) way I can find is to catch the value changed event and
see if the text is "Click for more" but after that the drop down closes. calling Toggle drop down in that event handler is too early and it closes afterwards.
Also for this solution I would need to merge the multiple columns in this row somehow or do a custom paint over it.
I hope you get what I am tryong to acheive, any nice solution will do.
thanks
Michael
Hi Michael,
Your idea of using a fake summary row (or data row) is not bad. But as you noticed, you cannot catch mouse events on the dropdown portion of the combo - at least not easily.
I found a way to do this using a CreationFilter to insert a custom button UIElement into the dropdown.
So I add a fake summary to the combo:
private void ultraCombo1_InitializeLayout(object sender, InitializeLayoutEventArgs e) { UltraGridLayout layout = e.Layout; UltraGridBand band = layout.Bands[0]; UltraGridOverride ov = layout.Override; band.Summaries.Add("Fake", null); ov.SummaryFooterCaptionVisible = DefaultableBoolean.False; }
And I create a class which inherits from ButtonUIElement and override the OnClick method.
internal class ComboLoadMoreDataButtonUIElement : ButtonUIElement { public ComboLoadMoreDataButtonUIElement(UIElement parent) : base(parent) { } protected override void OnClick() { base.OnClick(); } }
Then I create a CreationFilter class that watches for the SummaryFooterUIElement and replaces the entire contents of this element with my custom button element.
internal class ComboLoadMoreDataCreationFilter : IUIElementCreationFilter { #region IUIElementCreationFilter Members void IUIElementCreationFilter.AfterCreateChildElements(UIElement parent) { // do nothing } bool IUIElementCreationFilter.BeforeCreateChildElements(UIElement parent) { SummaryFooterUIElement summaryFooterUIElement = parent as SummaryFooterUIElement; if (summaryFooterUIElement != null) { ComboLoadMoreDataButtonUIElement comboLoadMoreDataButtonUIElement = null; // See if there is an existing element we can re-use. if (parent.ChildElements.Count > 0) { foreach (UIElement childElement in parent.ChildElements) { if (childElement is ComboLoadMoreDataButtonUIElement) { comboLoadMoreDataButtonUIElement = (ComboLoadMoreDataButtonUIElement)childElement; break; } } } parent.ChildElements.Clear(); if (comboLoadMoreDataButtonUIElement == null) comboLoadMoreDataButtonUIElement = new ComboLoadMoreDataButtonUIElement(parent); comboLoadMoreDataButtonUIElement.Rect = parent.Rect; parent.ChildElements.Add(comboLoadMoreDataButtonUIElement); return true; } return false; } #endregion }
And you just have to attach the CreationFilter to the combo up front. I'd do this in Form_Load.
this.ultraCombo1.CreationFilter = new ComboLoadMoreDataCreationFilter();
Hi Mike
That worked a treat:
Few points though.
I need a mechanism to communicate bewteen this UIElement and the UltraCombo for things like,
At the moment I can do all of the above by tweaking the constructors of the CreationFilter and uielement to pass in the UltraCombo - it just feels a little bit of a hack.
Also the fake button doesnt actually behave like a button, i.e. I don't see it looking pressed when I click on it. I don't need that functionality (in fact i may make mine look like a hyperlink), but is more for completeness for anyone else reading this.
1. In older versions, there was no way to apply an explicit size to the dropdown area of the combo. In the latest version, you can do it using the PreferredDropDownSize property. But I'm not sure if this property is honored unless you also turn on the DropDownResizeHandleStyle.
Another option would be to use the MaxDropDownItems. You cannot set an explicit size with this property, but you could try setting the property to 1 so there's only room for one dropdown item and that might work for what you need.
2. I'm not sure what you mean by "a green rectanlge that doesnt quite fit". If I understand correctly, you want a border around the "Click here for more..." area, right? There is already a white border around it, so what exactly doesn't fit? Are you saying the green border is not replacing the white border that is already there?
Setting combo.Appearance.BackColor doesn't seem like the right thing to do, anyway, since this will affect all of the borders in the entire control, not just the one around the text in the dropdown.
I think you will probably need to use a DrawFilter or derive your own UIElement hand override InitAppearance if you want to control the appearances on such a detailed level.
1. MaxDropDownItem set to 1 still leaves a gray box.
2. I just want the white line in the picture above coloured. Just realised I had a typo (+ intellisense) it was
supposed to be appearance.BorderColor = green,
here is a screen shot of how it looks (when the mouse is over it)
Hope you can see green lines (just one pixel) just inside the white borders. In any case this was a first try, I had thoughts of showing/hiding top/left/right borders.
Looks like DrawFilter is the way, can you give me a pointer as to how to isolate the bottom grid using this method
1. Did you try PreferredDropDownSize, then? If you don't have that property or it does not work, then I don't beleive there is any way to set the size of the dropdown.
2. What UIElement are you using to add the text? If the border is showing up only when the mouse is over it, then it seems to me that you are probably using a ButtonUIElement or some element derived from it and the border you are getting is the border of the button. So your button element must be using a style that pops up the button on a mouse over.
If that's right, then the ButtonUIElement should pick up the style from the control's ButtonStyle or ButtonDisplayStyle property. If not, then you can still change the style by deriving your own class from ButtonUIElement and overriding the ButtonStyle property.
Perhaps there is another button style that shows a single border all the time that you can use.
It's also possible that the white line you are seeing here is not coming from the ButtonUIElement, but from whatever element is above it. But there's no way to tell that just from a screen shot.
Another problem with this now:
We tried making the summary row a nice button by overriding ButtonStyle on the ButtonUIElement
// only show a button if the parent has some summary text:
public
{
get
parentCombo.DisplayLayout.Bands[0].Summaries.Clear();
parentCombo.DisplayLayout.Bands[0].Summaries.Add(
}
The buttons shows just fine but we now get a redraw problem:
As you may remeber we are rebinding a data source from a webservice on each key stroke. When the filtered data gets smaller, the old data is still visible while we are typing.
e.g. here shows there was lots of data, then we hit "o" and the filtered list drops to just 2 items but the old data still shows at the bottom.
All combinations of Invalidate, DoEvents don't help. The also the GUi isnt locked, we can still type and clicking on say the (real) scrollbar causes the old data to dissapear.
If I completely get rid of the above override and don't have a button then there is no problem and the old data dissapears.
This thread is getting kinda long, so I don't remember all of it, but if you are using a CreationFilter here, my guess is that you are not clearing out the ChildElements collection of whatever element is containing those rows.
Normally, the grid will do this for you, but if you are handling BeforeCreatChildElement and you return true, then the grid will not do any of it's own normal processing, so you are responsible for everything, including removing any elements that are no longer needed.