I'm trying to create an expendable list with text as well as an ImageView. This is how I'm currently doing this: There's one parent xaml and two children xaml (a ChildText.xaml and a ChildImage.xaml). I want one of the parent items to contain an image. I used following code in my adapter:
public override View GetChildView (int groupPosition, int childPosition, bool isLastChild, View convertView, ViewGroup parent) {
var item = _dictGroup [_lstGroupID [groupPosition]] [childPosition];
if(item.Contains("ichart")) {
if (convertView == null)
convertView = _activity.LayoutInflater.Inflate (Resource.Layout.ListControl_ImageChild, null);
var imageView = convertView.FindViewById<ImageView>(Resource.Id.image);
var imageBitmap = GetImageBitmapFromUrl (item);
imageView.SetImageBitmap (imageBitmap); //X
} else {
string[] data = item.Split ('_');
if (convertView == null)
convertView = _activity.LayoutInflater.Inflate (Resource.Layout.ListControl_Child, null);
var titleBox = convertView.FindViewById<TextView> (Resource.Id.titleSmall);
var textBox = convertView.FindViewById<TextView> (Resource.Id.txtSmall);
titleBox.SetText (data[0], TextView.BufferType.Normal);
textBox.SetText (data[1], TextView.BufferType.Normal);
}
return convertView;
}
So if the string contains ichart, it should create an ImageView. This works, but when I try to click open another tab (containing text), I get a nullpointer exception on the line with the X saying imageView is null. Why is it entering that if?
Can anyone tell me what I'm doing wrong?
Thanks in advance
First of all we have to make an array of images & parent names we want to put in expandable list view. Then call these arrays by using array adapter class.
you have to put the first variable manually in .xml file after that array adapter set all images & textview as per array you made.
Related
I have a menu structure as seen in picture below:
I want to add images to all submenu-items under the controllerToolStripMenuItem, ie openToolStripMenuItem, openInNewWindowToolStripMenuItem... ImageList contains my images to use and menuStrip1 gets a reference to the list of images :
menuStrip1.ImageList = ImageList;
Test code:
private void LoadSubMenuIcons()
{
menuStrip1.ImageList = ImageList;
//Just for test:
controllerToolStripMenuItem.ImageIndex = 2;
ToolStrip firstLevelParent = controllerToolStripMenuItem.GetCurrentParent();
//firstLevelParent.ImageList is of type MenuStrip
//firstLevelParent.ImageList equals ImageList set above
foreach (ToolStripItem subMenuItem in controllerToolStripMenuItem.DropDownItems)
{
if (subMenuItem is ToolStripMenuItem)
{
subMenuItem.ImageIndex = 2;
ToolStrip secondLevelParent = subMenuItem.GetCurrentParent();
//secondLevelParent is of type ToolStripDropDownMenu
//secondLevelParent.ImageList is null
}
}
}
In the example code above I try to add the image with index 2 to all submenu-items. This doesn't work! It might have to do with the fact that their parent is of type ToolStripDropDownMenu and its ImageList-property is null? The middle level item, controllerToolStripMenuItem, on the other hand shows the image correctly. Its parent is menuStrip1 which has a valid refrence to my imagelist. How do I solve the problem with the submenu-items?
I call an API and get from there an id, a name and an URL for images...
I display them in a flipview and I used to convert them, saved them in a folder, convert them back and show them...
So I thought it would be much easier if I show them directly from their URL.
Now, when the user clicks (taps) on the image, it has to go to another page to show the detail of that image (and it was working fine, when saving the pic, since I named them by the id (id.png))
is there anyway I can name the ImageSource to be this id, or give it like a property (Title or Name)?
var pics = from special in GlobalVariables.Special
where special.special == "1"
select new { id = special.id, name = special.name, image = special.banner_image, featured = special.special };
foreach (var item in pics)
{
await savePicToDisk(item.image, item.name, item.id, item.featured);
}
So, then, instead of save them:
List<ImageSource> listOfImages = new List<ImageSource>();
string url = "http://52.8.2.140" + picAddress;
ImageSource urlOfPic = new BitmapImage(new Uri(url, UriKind.Absolute));
listOfImages.Add(urlOfPic);
Then, where I have to show them, I just bind it to the flipview:
flipView1.DataContext = Classes.Special.listOfImages;
The Item_Click event's arguments have a property ClickedItem (in some cases you may also need OriginalSource), which you can use to point to your item in a collection. If item's class has a property responsible for Name/Id/other you can freely pass that when navigating, other solution may be passing an index of selected item in the collection. Sample code;
private void ItemClick(object sender, ItemClickEventArgs e)
{
var item = e.ClickedItem as ItemClass;
if (item != null)
Frame.Navigate(typeof(DetailPage), item.ID);
// if your item contains a Name/Id/other you can pass that when navigating
// you can also pass index of your item in collection if you need
}
I have a Pivot with several PivotItems, one of which contains a canvas that places its items in dynamic locations (depending on the data). I get the data, and I can place the items in their place before the user can choose this item (this isn't the first pivot). However, only when I select the PivotItem, the canvas renders itself, so you can see it flicker before it's shown as it should.
Is there a way to force the canvas to render before it's shown, so everything's prepared by the time the user sees it?
My code looks something like this:
In the page.xaml.cs:
private async void GameCenterView_OnDataContextChanged(object sender, EventArgs e)
{
// Load data...
// Handle other pivots
// This is the problem pivot
if (ViewModel.CurrentGame.SportTypeId == 1)
{
_hasLineups = ViewModel.CurrentGame.HasLineups.GetValueOrDefault();
HasFieldPositions = ViewModel.CurrentGame.HasFieldPositions.GetValueOrDefault();
// I only add the pivot when I need it, otherwise, it won't be shown
if (_hasLineups)
{
if (MainPivot.Items != null) MainPivot.Items.Add(LineupPivotItem);
}
if (HasFieldPositions)
{
// Here I place all the items in their proper place on the canvas
ArrangeLineup(ViewModel.TeamOneLineup, TeamOneCanvas);
ArrangeLineup(ViewModel.TeamTwoLineup, TeamTwoCanvas);
}
}
// Handle other pivots
}
private void ArrangeLineup(ObservableCollection<PlayerInLineupViewModel> teamLineup, RationalCanvas canvas)
{
if (teamLineup == null)
return;
foreach (var player in teamLineup)
{
var control = new ContentControl
{
Content = player,
ContentTemplate = LinupPlayerInFieldDataTemplate
};
control.SetValue(RationalCanvas.RationalTopProperty, player.Player.FieldPositionLine);
control.SetValue(RationalCanvas.RationalLeftProperty, player.Player.FieldPositionSide);
canvas.Children.Add(control);
}
}
The canvas isn't the stock canvas. I created a new canvas that displays items according to their relative position (I get the positions in a scale of 0-99).
The logic happens in the OverrideArrange method:
protected override Size ArrangeOverride(Size finalSize)
{
if (finalSize.Height == 0 || finalSize.Width == 0)
{
return base.ArrangeOverride(finalSize);
}
var yRatio = finalSize.Height/100.0;
var xRatio = finalSize.Width/100.0;
foreach (var child in Children)
{
var top = (double) child.GetValue(TopProperty);
var left = (double) child.GetValue(LeftProperty);
if (top > 0 || left > 0)
continue;
var rationalTop = (int) child.GetValue(RationalTopProperty);
var rationalLeft = (int) child.GetValue(RationalLeftProperty);
if (InvertY)
rationalTop = 100 - rationalTop;
if (InvertX)
rationalLeft = 100 - rationalLeft;
child.SetValue(TopProperty, rationalTop*yRatio);
child.SetValue(LeftProperty, rationalLeft*xRatio);
}
return base.ArrangeOverride(finalSize);
}
Thanks.
There are several tricks you could try. For example:
In your ArrangeOverride you can short-circuit the logic if the size hasn't changed since last time you executed (and the data is the same)
Make sure you're listening to the events on Pivot that tell you to get ready for presentation - PivotItemLoading for example
You can have the control not actually be part of the Pivot, but instead be in the parent container (eg a Grid) and have it with Opacity of zero. Then set it to 100 when the target PivotItem comes into view.
In my application I have a ListView with "sections". For each item, I added a letter, but they are visible only for the first word beginning with that letter. It works fine, but if I scroll down in my ListView, the order changes, that means the letter is going to next item.
Example:
A
--
- Alligator
- Ant
- Antelope
- Ape
But when I scroll down, the following happens:
- Aligator
A
--
- Ant
- Antelope
- Ape
Function that adds the letter I have implemented in GetView()
How can I solve this problem?
I read that ListView is refreshing while scrolling, how can I disable refreshing? Or is there the other way to solve this?
protected string old_char = "";
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = sw_items [position];
View view;
convertView = null;
view = (convertView ??
this.context.LayoutInflater.Inflate (Resource.Layout.ItemLayout,
parent,
false)) as LinearLayout;
var txtTitle = view.FindViewById<TextView> (Resource.Id.txtTitle);
txtTitle.SetText (sw_items [position].name, TextView.BufferType.Normal);
var alfabet = view.FindViewById<TextView> (Resource.Id.alfabet);
var linAlfabet = view.FindViewById<LinearLayout> (Resource.Id.Lin_Alfabet);
if (convertView == null) {
string cnv_char = item.name [0].ToString ().ToUpper ();
alfabet.Text = cnv_char;
if (cnv_char != old_char) {
alfabet.Visibility = ViewStates.Visible;
linAlfabet.Visibility = ViewStates.Visible;
} else {
alfabet.Visibility = ViewStates.Gone;
linAlfabet.Visibility = ViewStates.Gone;
}
//saving previous char
old_char = cnv_char;
}
return view;
}
}
What am I doing wrong?
Revised
First, the basic scheme for getView() implementations is as follows.
if (convertView == null) {
// the system does not want me to recycle a view object, so create a new one
LayoutInflater inflater = (LayyoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.your_layout_file, parent, false);
}
// here, set up the convertView object, no matter whether it was recycled or not
...
return convertView;
Given the code snippet you posted, all you probably have to do is: 1. remove the convertVire = null; statement which Yatin suggested and 2. remove the surrounding if (convertView == null) { including closing } around the string cnv_char... old_char = cnv_char block. Make sure to set everything properly for convertView, because it is not guaranteed to be a fresh object.
Second, your code is relying on getView() being called in a particular order, which is not the case. Currently, you're relying on old_char being set to the starting letter of the last item (in the order in which they appear in the list). This is not guiaranteed.
I suggest you use the position argument to access the previous entry of the list (except for the first, of course) and check for a difference, showing the starting letter of the current item if there is no predecessor or if it starts with a different letter.
ListView reuses views in stack to replace the view which is scrolled up to place it again at the bottom
try adding the following statement in the code before as :-
convertView=null;
before it checks for
if(convertView==null);
I am trying to get the text value of a "cell" inside of a GridView that is set as the view of a ListView. I do not want to get the SelectedItem of the ListView as that just returns my entire View Model (but not which property the cell refers to).
I am able to get the text value by responding to direct mouse events (up down or whatever) and if the value is a textblock, obviously I can use the text. This works great and as of right now this is my only solution, although its currently limited.
I would like to take it a step further and be able to click anywhere with in the cell area, navigate around to find the appropriate textblock and then use that value. I have tried a half million ways to do this but what seems logical doesn't seem to quite work out like it should.
Setup:
I have a dynamic GridView that creates its own columns and bindings based on data models that I pass to it. I am using a programmatic cell template (shown below) to have individual control over the cells, particularly so I can add a "border" to it making it actually separate out each cell. I have named the objects so I can access them easier when I'm navigating around the VisualTree.
Here is the Template Code. (Note that the content presenter originally was a textblock itself, but this was changed for later flexibility)
private DataTemplate GetCellTemplate(string bindingName)
{
StringBuilder builder = new StringBuilder();
builder.Append("<DataTemplate ");
builder.Append("xmlns='http://schemas.microsoft.com/winfx/");
builder.Append("2006/xaml/presentation' ");
builder.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' ");
builder.Append("xmlns:local = 'clr-namespace:XXXXXXXX");
builder.Append(";assembly=XXXXXXXXX'>");
builder.Append("<Border Name=\"border\" BorderThickness=\"1,0,0,0\" BorderBrush=\"Gray\" Margin=\"-6,-3,-6,-3\">");
builder.Append("<Grid Margin=\"6,3,6,3\">");
builder.Append("<ContentPresenter Name=\"content\" HorizontalAlignment=\"Stretch\" Content=\"{Binding ");
builder.Append(string.Format("{0}", bindingName));
builder.Append("}\"/>");
builder.Append("</Grid>");
builder.Append("</Border>");
builder.Append("</DataTemplate>");
DataTemplate cellTemplate= (DataTemplate)XamlReader.Parse(builder.ToString());
return cellTemplate;
}
What I have Tried:
The logical approach for me was to react to a Mouse event. From the object that had the mouse event I would do either
A. Look at its children to find a textblock, or
B. Get its parent then look for child with a textblock.
My assumption is that if I click in white space I'm clicking in a container that has my textblock. So far the two things that come up are a Border and a Rectangle (if I don't click the text itself). A. Returns absolutely nothing except for the recangle and the border. When I do B i can find textblocks but they are every single text block in the entire row.
So what I try to do from that is get all textblocks, then go backwards till I find which one has a IsMouseOver property as true. It turns out none of these objects EVER have a IsMouseOver except the content presenter for the entire row. So this seems to indicate to me is that the whitespace in the cells does not actually contain the textblock.
What I find is that when I click on the Border and start looking at children, I eventually get to a container that has a rectangle (the rectangle I click) and a grid row view presenter. The presenter shows all of the objects inside the row (hence why i would get all textblocks when i do this recursive scan).
Here is some of the code used to do this to get an idea of what i'm doing. I have written about 10 different versions of this same recursive code generally attempting to find who has the Mouse over it and is related to a textbox.
private void OnPreviewMouseUp(object sender, MouseButtonEventArgs e)
{
object original = e.OriginalSource;
if (original is TextBlock)
{
this.valueTextBlock.Text = ((TextBlock)original).Text;
}
else if (original is FrameworkElement)
{
var result = GetAllNestedChildren<Border>(VisualTreeHelper.GetParent((DependencyObject)original)).Where(x => x.Name == "border").Where(x => HasAChildWithMouse(x)).ToList();
}
else
{
this.valueTextBlock.Text = string.Empty;
}
}
private bool HasAChildWithMouse(UIElement element)
{
if (element.IsMouseOver || element.IsMouseDirectlyOver)
return true;
var childCount = VisualTreeHelper.GetChildrenCount(element);
for (int i = 0; i < childCount; ++i)
{
var child = VisualTreeHelper.GetChild(element, i);
if (child is UIElement)
if (HasAChildWithMouse((UIElement)child))
return true;
}
return false;
}
private IEnumerable<T> GetAllNestedChildren<T>(DependencyObject obj) where T : UIElement
{
if (obj is T)
yield return obj as T;
var childCount = VisualTreeHelper.GetChildrenCount(obj);
for (int i = 0; i < childCount; ++i)
{
var child = VisualTreeHelper.GetChild(obj, i);
foreach (var nested in GetAllNestedChildren<T>(child))
yield return nested;
}
}
private T GetObjectByTypeParentHasMouse<T>(DependencyObject obj) where T : UIElement
{
if (obj is T)
{
if ((VisualTreeHelper.GetParent(obj) as UIElement).IsMouseOver )
{
return obj as T;
}
}
var childCount = VisualTreeHelper.GetChildrenCount(obj);
for (int i = 0; i < childCount; ++i)
{
var child = VisualTreeHelper.GetChild(obj, i);
var correctType = GetObjectByTypeParentHasMouse<T>(child);
if (correctType != null)
return correctType;
}
return null;
}
private T GetContainedType<T>(DependencyObject obj, bool checkForMouseOver) where T : UIElement
{
if (obj is T && ((T)obj).IsMouseOver)
return obj as T;
var childCount = VisualTreeHelper.GetChildrenCount(obj);
for (int i = 0; i < childCount; ++i)
{
var child = VisualTreeHelper.GetChild(obj, i);
var correctType = GetContainedType<T>(child, checkForMouseOver);
if (correctType != null)
return correctType;
}
return null;
}
The other approach I took was to start with the TextBlock itself, find its containing parent and find out how i can navigate to the answer. I find the templateparent is the ContentPresenter (named ="content") I find the grid, and then the border. The parent of the border is a content presenter whos content is the data view model for the entire row. The parent of this contentpresenter is the grid column's presenter. This is the same one that i was navigating up to in the other one.
It would appear that the first approach objects while are contain the cell do not actually contain the textblock or the entire cell templated items. It would appear to me there is no way to go from the Border or Rectangle that is clicked, back to the actual text field.
"Long story short" is there ANY way to make this connection?
(Btw I am not willing to give up this ListView/GridView because its payoffs far outweigh this negative and I'd gladly give up on this idea to keep the rest).
I think you sjould be able to either
1) Add some kind of (toggle)button to the root of your data template, and either bind to Command and handle it on your viewmodel or bind to IsChecked/IsPressed and handle changes via data triggers or w/e on the view side.
2) Add EventTrigger to your datatemplate at some point, and handle PreviewNouseUp/Down events there via simple animations.