Silverlight DataGrid with vertical Scrollbar problem - datagrid

I have a Datagrid filled with a table. Now the vertical scrollbar shows up because the table doesn't fit. That's fine so far. Now in the last column I have defined a Button in the xaml file. All these buttons have the same callback, but I can distinguish from the selectedIndex of the table what this callback should do. Because clicking the button automatically also selects the line in the DataGrid where this button lives. That's fine so far. Now in my app, for some rows I want to disable the Button, because it has no meaning for that specific row. So what I did is take a subscription on event Load of each Button and let the callback set the MaxWidth = 0, if the button has no meaning. This works fine too, but only initially. As soon as I start dragging the scrollbar, at random places in the Button column buttons show up, or wrong buttons get MaxWidth = 0. I have the strong feeling that cells that scrolled out at the top are being reused at the bottom, but I don't get an event, or at least I don't know which event I should subscribe on. I don't know how to identify the scrollbar. Has anyone a suggestion to tackle this problem?

I finally found a solution to this problem myself, and I will post it for the record.
The event you should subscribe on is LoadingRow (generated by the DataGrid).
In the callback
void TableLoadingRow(object sender, DataGridRowEventArgs e)
you can identify an element in a cell by using VisualTreeHelper for instance as follows:
private void ButtonSetMaxWidth(DependencyObject reference, int maxWidth)
{
if (reference != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(reference); i++)
{
var child = VisualTreeHelper.GetChild(reference, i);
if (child.GetType() == typeof(Button))
{
Button b = (Button)child;
if (b.Name == "TheNameOfTheButtonInTheXAML")
{
b.MaxWidth = maxWidth;
return;
}
}
ButtonSetMaxWidth(child, maxWidth);
}
}
return;
}

Related

How to detect SizeChanged event after using .HeightRequest

I noticed that after using the .HeightRequest property on a View in Xamarin.Forms that a method I have assigned to the SizeChanged event is no longer called.
The content within the View that had called .HeightRequest is a Label that contains text which can be zoomed in. When zooming in, the text now exceeds the "bounds" of the View's height, and the height is no longer adjusting as it once was.
public ExpandableEntryView(...)
{
InitializeComponent();
// my beautiful code
SizeChanged += ExpandableEntryView_SizeChanged;
UpdateUI();
}
private void ExpandableEntryView_SizeChanged(object sender, EventArgs e)
{
// this is never called once .HeightRequest is assigned a value
}
private void SomeFunction() {
sectionsStackLayout.HeightRequest = 0; // this causes SizeChanged to no longer work
}
I essentially need this View to minimize its height to 0, and then return to its original height when I tell it to. I am also using IsVisible, but the Height property is required for an animation I am trying to do.
Thank you in advance.
Nevermind, I was able to figure it out. The reason why the SizeChanged event is no longer called is because the view is no longer responsible for keeping track of its size after assigning a value to HeightRequest. So, if you would like for your View to return to being able to determine its own size once again, (i.e. if a child element in that View happens to change size/scale) you need to assign the HeightRequest to -1. This will then reenable the SizeChanged event.
Hope this helps somebody!

How to get children of grid row if Grid.Row is known

I am working on xamarin.forms application and I have question that I could not solve.
1) I have multiple Grids one after another that contain button, label and image. Now, on button click I want to change image or rotate it to down. But somehow, I am not able to do it.
My first try was to get parent of button and find image using FindByName method. But FindByName returns null, but I can see grid in parent while debugging.
My second try was to get row of button and find all the controls that are in that row. Because my image is in the same row as button.
My structure is something like this
My grid works fine but only rotation issue is there.
pubic void OnButtonClicked(object sender, EventArgs e)
{
var SenderButton = (Button)sender;
var row = Grid.GetRow(SenderButton); // Here i get row = 0 but dont know how to find other controls on same row.
Image upimage = SenderButton.Parent.FindByName<Image>("imageExpand"); // imageExpand is my image name in grid.
upimage.Source = "upimage.png";
}
Here upimage is null.
Thank you very much.
I'm only replying to your first question
you got it right, you can get the value of the attached bindable property Grid.Row using public static int GetRow(BindableObject bindable). Now it's quite easy to filter the grid's Children.
var button = (Button)sender;
var row = Grid.GetRow(button);
var grid = button.Parent as Grid;
//assuming the image is in column 1
var image = grid.Children.Where(c => Grid.GetRow(c) == row && Grid.GetColumn(c)==1);

Flex multiple selection drop down list with scrolling

I'm working in flex and I made a custom drop down where there are check boxes to allow the user to select multiple options. I used this template.
However this does not have scrolling because if you allow scrolling for some reason the checkboxes start to mess up. For instance if you have options 1 to 8 and only 1 to 5 are shown. You select option 1 and then scroll down to select option 7. When you scroll up the checkboxes start to switch around like option 3 all of a sudden is showing selected. Keep scrolling up and down and the checkbox selection just changes on it's own. I think this is a rendering issue and the actual selection data isn't changed at all (it knows only option 1 and option 7 were selected). Any ideas on how to fix this?
public function onOpen(event:DropDownEvent):void
{//load the checkboxes and set the mouse tracker
activateAllCheckBoxes();
this.scroller.verticalScrollBar.addEventListener(Event.CHANGE, list_verticalScrollBar_change);
callLater(observeMouse);
}
private function list_verticalScrollBar_change(evt:Event):void
{
//currentlySelectedCheckBoxes = selectedCheckboxes;
UpdateCheckBoxesWhenScrolling();
selectedIndex = -1;
}
protected function UpdateCheckBoxesWhenScrolling():void
{
for (var c:int = 0; c < dataGroup.numElements; c++) {
var obj:DropDownCheckBox = dataGroup.getElementAt(c) as DropDownCheckBox;
if(obj!=null)
{
var judgDebtorFromCheckBox:JudgDebtor = (obj.data) as JudgDebtor;
if(FindInCurrentList(judgDebtorFromCheckBox.JudgmentDebtorId)>0)
{
obj.checkbox.selected = true;
}
else
{
obj.checkbox.selected = false;
}
}
}
}
private function FindInCurrentList(ID:int):int
{
for(var i:int=0;i<currentlySelectedCheckBoxes.length;i++)
{
var JD:JudgDebtor = currentlySelectedCheckBoxes.getItemAt(i) as JudgDebtor;
if(JD.JudgmentDebtorId == ID)
return 1;
}
return -1;
}
So above code I register a scroll event listener on the drop down. It will update the drop down entries which has a check box and it uses an array collection called: currentlySelectedCheckBoxes. I debug the UpdateCheckBoxesWhenScrolling function and it's working fine, in other words it will check off the ones selected but for some reason it still is showing the wrong results for instance 11 entries in the list and only the second one is selected I scroll down and I can't see the the second entry but all of a sudden the last entry is showing that it's checked off.
This happens because the drop down list reuses the renderers when you scroll. For example if you have checked 1st item and scroll, the renderer for that is reused to display the item that becomes visible when you scroll. So the last item shows as checked. To avoid messing up the selection, you will have to do the following in the renderer that you are using
override public function set data(value:Object):void
{
super.data = value;
//inspect the property which indicates whether to select the checkbox or not
//and set the value of selected property accordingly
}
Hope this helps

Telerik RadGrid maintain scroll position after row selection

I have a RadGrid that has a WebUserControl for each row of the grid to allow the user to edit that row. When I click the edit button to expand the row (this opens up a .ascx control within the grid for that row), it always scrolls to the top of the page. The user then has to scroll down to find the row they selected with the row expanded to begin editing that row.
I found in another post that adding RadGrid1.ClientSettings.AllowKeyboardNavigation = true; prior to data binding the grid helps to maintain scroll position. This kind of works and you only have to scroll down one click of the mouse wheel to find the row to edit; not good enough.
I also have set MaintainScrollPositionOnPostback=“true" on the aspx page.
I also have set on the RadGrid itself under client settings SaveScrollPosition=“true".
What I'd like to see is the page not move at all when the user clicks on edit for the given row. I would like to maintain the scroll position on the page.
Can this be accomplished? If so, how?
I finally figured out why my grid always scrolled to the top. It was my fault. I wanted the user to see any message from the WebUserControl when control pass back to the parent page. The RadGrid1.ClientSettings.Scrolling.ScrollTop = 0; was the issue.
I had the following code listed:
private void DisplayMessage()
{
// Display any messages from RadGrid2 that occurred in WebUserControl
if (!string.IsNullOrEmpty(Convert.ToString(Session["LabelUpdated"])))
{
lblUpdated.Text = Convert.ToString(Session["LabelUpdated"]);
Session["LabelUpdated"] = null;
}
RadGrid1.ClientSettings.Scrolling.ScrollTop = "0";
lblUpdated.Focus();
}
I've since changed it to what is below:
private void DisplayMessage()
{
// Display any messages from RadGrid2 that occurren in WebUserControl
if (!string.IsNullOrEmpty(Convert.ToString(Session["LabelUpdated"])))
{
lblUpdated.Text = Convert.ToString(Session["LabelUpdated"]);
Session["LabelUpdated"] = null;
RadGrid1.ClientSettings.Scrolling.ScrollTop = "0";
lblUpdated.Focus();
}
}
After the change the grid will only scroll to the top when a message is present from the WebUserControl.

Strange listbox behavior. New item won't show unless another item is added or page reloaded by exiting and returning

Here is what a portion of my screen looks like:
The user can pick a choice from the drop-down list and click the add button. Here is the code for the add button:
protected void btnModuleAdd_Click(object sender, EventArgs e)
{
var selectedModule = ddlModsList.SelectedItem.ToString();
var graphicName = this.GraphicName;
var xr = new GraphicModuleXRef();
xr.GraphicName = graphicName;
xr.Module = selectedModule;
// Take drop down list selection and add it to GraphicModuleXRef table.
var context = new XRefDataContext();
context.GraphicModuleXRefs.InsertOnSubmit(xr);
context.SubmitChanges();
}
Basically, it's taking the user's choice and writing it out to a table. This part works fine.
In my Page_Load, I check whether IsPostback and, if it is, I run the code below:
private void LoadOtherModulesUsed()
{
if (this.GraphicName != null)
{
lbModules.Items.Clear();
var context = new XRefDataContext();
var q = context.GraphicModuleXRefs
.Where(a => a.GraphicName.Contains(this.GraphicName));
foreach (GraphicModuleXRef gr in q)
{
lbModules.Items.Add(new ListItem(gr.Module.ToString()));
}
}
}
This code reads from a table, finds all records that match the criteria, and adds them to the listbox.
So, what I'm expecting to happen is for the page to reload and the listbox to be repopulated, including the new entry just added to the table. But, that isn't happening. The screen refreshes like it has reloaded, but the entry doesn't appear in the listbox. However, it IS there, it just can't be seen. If the user adds another entry, by clicking the Add button, the list 'rolls up' one row and the previous entry can be seen. But, not the new one. If the user exits from the screen and re-enters, all the entries in the listbox can be seen. It's almost like the listbox is too short to display all records, but I've tried different heights, with no difference.
I'm wondering if anyone can point me in the right direction?
Put simply, when adding a new item to the listbox, it isn't immediately visible unless another item is added, thereby 'rolling' the list up. Even scrolling the list with the scrollbar doesn't show the new entry until another entry is added. And, if you scroll the list up, you can see the prior entry. So strange!
EDIT: Trying to describe this more simply:
User adds item to listbox by pressing Add button.
New item does not appear in listbox.
User adds another item to listbox by press Add button.
Prior item now shows in listbox if user scrolls listbox up.
The newest item just added, however, does not appear unless step 3 is repeated.
Also, exiting the page and then coming back in loads every item in the list and all is visible.
This is a timing issue. Whats happening is Page_Load runs first in this case and THEN the Click event handler so effectively the control has been bound before the new entry is added. Thats why you're always one refresh behind. Id refactor your code like this so everything runs in the correct order! To understand the timing of event execution I strongly recommend reading this article on MSDN its AWESOME and will really help you get the best from ASP.NET.
Additionally reading this article on MSDN (Also awesome) especially the section on ViewState will explain how the DropDown retains its details even when, in the modified code, you're onlly filling it when the page is NOT a postback and when the click event is fired.
Hope this helps!
public void Page_Load(object sender, EventArgs e)
{
if (IsPostBack) return;
LoadOtherModulesUsed();
}
private void LoadOtherModulesUsed()
{
if (this.GraphicName != null)
{
lbModules.Items.Clear();
var context = new XRefDataContext();
var q = context.GraphicModuleXRefs
.Where(a => a.GraphicName.Contains(this.GraphicName));
foreach (GraphicModuleXRef gr in q)
{
lbModules.Items.Add(new ListItem(gr.Module.ToString()));
}
}
}
protected void btnModuleAdd_Click(object sender, EventArgs e)
{
var selectedModule = ddlModsList.SelectedItem.ToString();
var graphicName = this.GraphicName;
var xr = new GraphicModuleXRef();
xr.GraphicName = graphicName;
xr.Module = selectedModule;
// Take drop down list selection and add it to GraphicModuleXRef table.
var context = new XRefDataContext();
context.GraphicModuleXRefs.InsertOnSubmit(xr);
context.SubmitChanges();
LoadOtherModulesUsed();
}

Resources