Changing the span of CollectionView while rotating phone isn't working - c#

I'm trying to change the span of CollectionView while rotating my iPhone. To make it easy, just show 2 columns in portrait, and 4 columns in landscape.
It works when rotating from portrait to landscape mode, but when rotating back to portrait mode, it always shows 1 column. My code likes,
VideoCollectionView = new CollectionView()
{
ItemsLayout = new GridItemsLayout(2, ItemsLayoutOrientation.Vertical),
};
...
private static double screen_width = 1280.0;
private static double screen_height = 720.0;
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
if ((Math.Abs(screen_width - width) > minimum_double) || (Math.Abs(screen_height - height) > minimum_double))
{
screen_width = width;
screen_height = height;
int split;
if (screen_width > screen_height)
{ // landscape mode
split = 4;
}
else
{ // portrait mode
split = 2;
}
VideoCollectionView.ItemsLayout = new GridItemsLayout(split, ItemsLayoutOrientation.Vertical);
}
}
Is this a bug? Or I should use other ways? Thanks for help.

You could use a Singleton for storing the current orientation.Because it is unwise to set the screen size as s static value . It maybe will cause issue on different size of device .
public class CurrentDevice
{
protected static CurrentDevice Instance;
double width;
double height;
static CurrentDevice()
{
Instance = new CurrentDevice();
}
protected CurrentDevice()
{
}
public static bool IsOrientationPortrait()
{
return Instance.height > Instance.width;
}
public static void SetSize(double width, double height)
{
Instance.width = width;
Instance.height = height;
}
}
And in the method
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
if (CurrentDevice.IsOrientationPortrait() && width > height || !CurrentDevice.IsOrientationPortrait() && width < height)
{
int split;
CurrentDevice.SetSize(width, height);
// Orientation got changed! Do your changes here
if (CurrentDevice.IsOrientationPortrait())
{
// portrait mode
split = 2;
}
else
{
// landscape mode
split = 4;
}
VideoCollectionView.ItemsLayout = new GridItemsLayout(split, ItemsLayoutOrientation.Vertical);
}
}

Related

Toolbar badge count is not working when I tried to set it programmatically from ViewModel

I have made dependency services on both side and Interface in shared library on Xamarin platform
when i use it in xaml.cs hard coded it works but when i use it in ViewModel using messaging center to set count of notification in Toolbar of application it doesn't works
Does anyone have any kind of idea whats happening or should i do ?
this code works from Xaml.cs page
DependencyService.Get<IToolbarItemBadgeService>().SetBadge(this, ToolbarItems[0], "2", Color.Red, Color.White);
And Below Code doesn't works
From ViewModel
" MessagingCenter.Send(new MessagingCenterModel { }, "NotificationCount", NotificationListCount);
At Xaml.cs Page
MessagingCenter.Subscribe<MessagingCenterModel, string>(this, "NotificationCount", (sender, args) =>
{
DependencyService.Get<IToolbarItemBadgeService>().SetBadge(this, ToolbarItems[0], args, Color.Red, Color.White);
});
InterFaceCode
public interface IToolbarItemBadgeService
{
void SetBadge(Page page, ToolbarItem item, string value, Color backgroundColor, Color textColor);
}
Dependency service
public class ToolbarItemBadgeService : IToolbarItemBadgeService
{
public void SetBadge(Page page, ToolbarItem item, string value, Color backgroundColor, Color textColor)
{
Device.BeginInvokeOnMainThread(() =>
{
var toolbar = CrossCurrentActivity.Current.Activity.FindViewById(Resource.Id.toolbar) as Android.Support.V7.Widget.Toolbar;
if (toolbar != null)
{
if (!string.IsNullOrEmpty(value))
{
var idx = page.ToolbarItems.IndexOf(item);
if (toolbar.Menu.Size() > idx)
{
var menuItem = toolbar.Menu.GetItem(idx);
BadgeDrawable.SetBadgeText(CrossCurrentActivity.Current.Activity, menuItem, value, backgroundColor.ToAndroid(), textColor.ToAndroid());
}
}
}
});
}
}
BadgeDrawable Class
public class BadgeDrawable : Drawable
{
private const string BadgeValueOverflow = "*";
private Paint _badgeBackground;
private Paint _badgeText;
private Rect _textRect = new Rect();
private string _badgeValue = "";
private bool _shouldDraw = true;
Context _context;
public override int Opacity => (int)Format.Unknown;
public BadgeDrawable(Context context, Color backgroundColor, Color textColor)
{
_context = context;
float textSize = context.Resources.GetDimension(Resource.Dimension.textsize_badge_count);
_badgeBackground = new Paint();
_badgeBackground.Color = backgroundColor;
_badgeBackground.AntiAlias = true;
_badgeBackground.SetStyle(Paint.Style.Fill);
_badgeText = new Paint();
_badgeText.Color = textColor;
_badgeText.SetTypeface(Typeface.Default);
_badgeText.TextSize = textSize;
_badgeText.AntiAlias = true;
_badgeText.TextAlign = Paint.Align.Center;
}
public override void Draw(Canvas canvas)
{
if (!_shouldDraw)
{
return;
}
Rect bounds = Bounds;
float width = bounds.Right - bounds.Left;
float height = bounds.Bottom - bounds.Top;
float oneDp = 1 * _context.Resources.DisplayMetrics.Density;
// Position the badge in the top-right quadrant of the icon.
float radius = ((Java.Lang.Math.Max(width, height) / 2)) / 2;
float centerX = (width - radius - 1) + oneDp * 2;
float centerY = radius - 2 * oneDp;
canvas.DrawCircle(centerX, centerY, (int)(radius + oneDp * 5), _badgeBackground);
// Draw badge count message inside the circle.
_badgeText.GetTextBounds(_badgeValue, 0, _badgeValue.Length, _textRect);
float textHeight = _textRect.Bottom - _textRect.Top;
float textY = centerY + (textHeight / 2f);
canvas.DrawText(_badgeValue.Length > 2 ? BadgeValueOverflow : _badgeValue,
centerX, textY, _badgeText);
}
// Sets the text to display. Badge displays a '*' if more than 2 characters
private void SetBadgeText(string text)
{
_badgeValue = text;
// Only draw a badge if the value isn't a zero
_shouldDraw = !text.Equals("0");
InvalidateSelf();
}
public override void SetAlpha(int alpha)
{
// do nothing
}
public override void SetColorFilter(ColorFilter cf)
{
// do nothing
}
public static void SetBadgeCount(Context context, IMenuItem item, int count, Color backgroundColor, Color textColor)
{
SetBadgeText(context, item, $"{count}", backgroundColor, textColor);
}
public static void SetBadgeText(Context context, IMenuItem item, string text, Color backgroundColor, Color textColor)
{
if (item.Icon == null)
{
return;
}
BadgeDrawable badge = null;
Drawable icon = item.Icon;
if (item.Icon is LayerDrawable)
{
LayerDrawable lDrawable = item.Icon as LayerDrawable;
if (string.IsNullOrEmpty(text) || text == "0")
{
icon = lDrawable.GetDrawable(0);
lDrawable.Dispose();
}
else
{
for (var i = 0; i < lDrawable.NumberOfLayers; i++)
{
if (lDrawable.GetDrawable(i) is BadgeDrawable)
{
badge = lDrawable.GetDrawable(i) as BadgeDrawable;
break;
}
}
if (badge == null)
{
badge = new BadgeDrawable(context, backgroundColor, textColor);
icon = new LayerDrawable(new Drawable[] { item.Icon, badge });
}
}
}
else
{
badge = new BadgeDrawable(context, backgroundColor, textColor);
icon = new LayerDrawable(new Drawable[] { item.Icon, badge });
}
badge?.SetBadgeText(text);
item.SetIcon(icon);
icon.Dispose();
}
}
Firstly , make sure that we had Subscribe the message before we send it . Otherwise the codes in Subscribe will never been called .
In addition , the code in Dependency Service could only set the badge of ToolbarItem in the navigation bar (on tabbed bar it will never work).
If you want to set the badge of tabbed page icon , you could use the plugin Plugin.Badge .

Xamarin.Forms - change size of control in code behind

I would like to change size of a control in Xamarin.Forms with some event in code behind of a control.
Especially, I would like to change size of a StackLayout when Orientation of device changes.
For now, I have done it like this (but it does not work):
private void SettingsPage_OnSizeChanged(object sender, EventArgs e)
{
var isPortrait = UIHelpers.IsPortrait(this);
if (isPortrait)
RemoteServerSL.WidthRequest = RemoteServerSL.ParentView.Width;
else
{
RemoteServerSL.WidthRequest = RemoteServerSL.ParentView.Width/2;
}
this.UpdateChildrenLayout();
this.ForceLayout();
RemoteServerSL.ForceLayout();
}
The purpose is to change Width of my StackLayout to parentWidth if I'm in landscape mode.
How can I handle that?
BTW.I'm working on Android for now.
You should use OnSizeAllocated method override to detect orientation change;
double previousWidth;
double previousHeight;
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
if (previousWidth != width || previousHeight != height)
{
previousWidth = width;
previousHeight = height;
if (width > height)
{
// landscape mode
}
else
{
// portrait mode
}
}
}

Problems with custom canvas

I tried to write my own custom Canvas and wanted to draw a little labyrinth which consist of little rectangles. My Problem is, that I just get 4 little points on my screen and not 4 Rectangles (when trying it with a 2 X 2 field).
Here is some Code:
public class LabyrinthCanvas : System.Windows.Controls.Canvas
{
public static readonly int RectRadius = 60;
public ObservableCollection<ObservableCollection<Rect>> Rectangles;
public LabyrinthCanvas()
{
Rectangles = new ObservableCollection<ObservableCollection<Rect>>();
}
public void AddRectangles(int Height, int Width)
{
for (int iHeight = 0; iHeight < Height; iHeight++)
{
ObservableCollection<Rect> newRects = new ObservableCollection<Rect>();
newRects.CollectionChanged += RectanglesChanged;
Rectangles.Add(newRects);
for (int iWidth = 0; iWidth < Width; iWidth++)
{
Rect rect = new Rect(iHeight * RectRadius, iWidth * RectRadius);
Rectangles[iHeight].Add(rect);
}
}
}
public void RectanglesChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
foreach (object rect in e.NewItems)
{
if (rect is Rect)
{
this.Children.Add(((Rect)rect).innerRectangle);
System.Windows.Controls.Canvas.SetTop(((Rect)rect).innerRectangle, ((Rect)rect).YPos);
System.Windows.Controls.Canvas.SetLeft(((Rect)rect).innerRectangle, ((Rect)rect).XPos);
}
}
}
else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
{
foreach (Rect rect in e.OldItems)
{
this.Children.Remove(rect.innerRectangle);
}
}
}
}
public class Rect : INotifyPropertyChanged
{
public Rect(int YPos, int XPos)
{
innerRectangle.Stroke = System.Windows.Media.Brushes.Black;
innerRectangle.Fill = System.Windows.Media.Brushes.Blue;
this.YPos = YPos;
this.XPos = XPos;
}
public System.Windows.Shapes.Rectangle innerRectangle = new System.Windows.Shapes.Rectangle();
public int YPos;
public int XPos;
}
I think the important thing is that:
this.Children.Add(((Rect)rect).innerRectangle);
System.Windows.Controls.Canvas.SetTop(((Rect)rect).innerRectangle, ((Rect)rect).YPos);
System.Windows.Controls.Canvas.SetLeft(((Rect)rect).innerRectangle, ((Rect)rect).XPos);
Im using a own Class "Rect" because i need some extra properties which i removed from the shown code and I cant inherit from Rectangle.
I'm not entirely sure what you want your end result to look like, so I probably won't be able to suggest the exact solution you're after.
That said, the reason you're obtaining small points on your screen, rather than rectangles, is because the canvas is rendering the innerRectangle of your Rect object, at the specified coordinates, but you're never initialising setting the dimensions of that innerRectangle.
The dots you're seeing are those width/heightless rectangles, which are having the Black stroke rendered (the dot).
You can see what's going on if you try something along these lines:
public System.Windows.Shapes.Rectangle innerRectangle = new System.Windows.Shapes.Rectangle() { Width = 10, Height = 10 };

How can I use a single bitmap for many icons in an imagelist? (without splitting it to multiple files)

I have a bitmap that contains 24x24 icons. I would like to use it in an image list for a toolstrip. Is it possible to use the bitmap and select the right portion of it based on the ImageIndex of a ToolStripButton? I would like to avoid splitting it into multiple files.
You could inherit ToolStripButton and provide a new source for the image. Here is a fairly simplistic approach; you might need to expand upon the idea for your exact needs.
public class ToolStripImageButton: ToolStripButton
{
public ToolStripImageButton()
: base()
{
}
private Image iconMap;
private Int32 iconMapIndex;
[RefreshProperties(System.ComponentModel.RefreshProperties.Repaint)]
public Image IconMap
{
get { return this.iconMap; }
set
{
this.iconMap = value;
this.RecalculateImage();
}
}
[RefreshProperties(System.ComponentModel.RefreshProperties.Repaint)]
public Int32 IconMapIndex
{
get { return this.iconMapIndex; }
set
{
this.iconMapIndex = value;
this.RecalculateImage();
}
}
protected void RecalculateImage()
{
if (base.Image != null)
{
base.Image.Dispose();
base.Image = null;
}
if (this.iconMap != null)
{
// assumes each icon is 16x16, you could add more properties for flexibility
Int32 x = this.iconMap.Width / 16;
Int32 y = this.iconMap.Width / 16;
Int32 iconCount = x * y;
if (this.iconMapIndex < 0 || this.iconMapIndex >= iconCount) return;
Int32 offsetX = (this.iconMapIndex % x) * 16;
Int32 offsetY = (this.iconMapIndex / x) * 16;
Bitmap bitmap = new Bitmap(16, 16);
using (Graphics g = Graphics.FromImage(bitmap))
g.DrawImage(
this.iconMap,
new Rectangle(0,0,bitmap.Width,bitmap.Height),
new Rectangle(offsetX, offsetY, bitmap.Width, bitmap.Height),
GraphicsUnit.Pixel);
base.Image = bitmap;
}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override Image Image
{
get
{
return base.Image;
}
set
{
// ignore
}
}

how to find pixel coordinates in an image in C#?

I want to develop a noise reduction project, so
how to find pixel coordinates in an image .
you can try this
Bitmap bmp = new Bitmap("filename");
//to get the pixel color
Color c= bmp.GetPixel(50,50);
//to set the color of the pixel
bmp.SetPixel(50, 50, Color.Green);
The below code will give you all pixel coordinates in image
namespace WindowsFormsApplication4
{
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
public partial class Form1 : Form
{
private const string FILE_NAME = #"C:\Temp\Capture.png";
private const double BW_THRESHOLD = 0.5;
private readonly Color colorBlack =
Color.FromArgb(255, 0, 0, 0);
private readonly Color colorWhite =
Color.FromArgb(255, 255, 255, 255);
private readonly Bitmap originalImage;
private readonly Bitmap convertedImage;
private readonly List<Vertex> vertices = new List<Vertex>();
public Form1()
{
InitializeComponent();
pictureBox1.ImageLocation = FILE_NAME;
this.originalImage = new Bitmap(FILE_NAME);
this.convertedImage = this.Img2BW(this.originalImage, BW_THRESHOLD);
foreach (Vertex vert in this.vertices)
{
listBox1.Items.Add(vert.ToString());
}
}
private Bitmap Img2BW(Bitmap imgSrc, double threshold)
{
int width = imgSrc.Width;
int height = imgSrc.Height;
Color pixel;
Bitmap imgOut = new Bitmap(imgSrc);
for (int row = 0; row < height - 1; row++)
{
for (int col = 0; col < width - 1; col++)
{
pixel = imgSrc.GetPixel(col, row);
if (pixel.GetBrightness() < threshold)
{
this.vertices.Add(new Vertex(col, row));
imgOut.SetPixel(col, row, this.colorBlack);
}
else
{
imgOut.SetPixel(col, row, this.colorWhite);
}
}
}
return imgOut;
}
}
public class Vertex
{
public Vertex(int i, int j)
{
this.X = i;
this.Y = j;
}
public int X { get; set; }
public int Y { get; set; }
public string ToString()
{
return string.Format("({0}/{1})", this.X, this.Y);
}
}
}
A pixel is merely a colour located at a position in a cartesian coordinate system, to easily read and write these colours in an image, you can use the Bitmap class, using the GetPixel and SetPixel methods.

Categories

Resources