Image Gallery Wrap Pannel not wrapping properly - c#

I seem to have a problem with my Images, they are not displaying properly and seems to be some problem with the WrapPanel.
There are a lot of White spaces on the sides and only one Image seems to be shown at the time. The images are loading and everything.
Below is part of my XAML
<ScrollView Grid.Column="0" Grid.Row="1" x:Name="ssView" Orientation="Vertical" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*">
</RowDefinition>
<RowDefinition Height="128">
</RowDefinition>
<RowDefinition Height="Auto">
</RowDefinition>
</Grid.RowDefinitions>
<controls:WrapPanelFixed x:Name="wpImages" Orientation="Horizontal" ItemHeightRequest="{Binding RequestedTileSize}" ItemWidthRequest="{Binding RequestedTileSize}" HeightScaling="1">
<controls:WrapPanelFixed.ItemTemplate>
<DataTemplate>
<RelativeLayout BackgroundColor="White">
<Image
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1.0}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=1.0}"
RelativeLayout.XConstraint="0"
RelativeLayout.YConstraint="0"
Source="{Binding LocalImagePath}" HorizontalOptions="Center" VerticalOptions="Center" Aspect="AspectFit">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="OnImageTapped" NumberOfTapsRequired="1"/>
</Image.GestureRecognizers>
</Image>
</RelativeLayout>
</DataTemplate>
</controls:WrapPanelFixed.ItemTemplate>
</controls:WrapPanelFixed>
</Grid>
</ScrollView>
c# Part of the code
public void Prepare()
{
RefreshImageList(Issue.Id);
}
protected void OnItemHeightChanged(object sender, ItemHeightChangedArg e)
{
int width = e.newHeigth;
e.newWidth = width;
}
protected void OnItemWidthChanged(object sender, ItemWidthChangedArg e)
{
int width = e.newWidth;
e.newHeigth = width;
}
protected void OnSizeChanged(object sender, EventArgs e)
{
wpImages.NeedLayoutOfChildren = true;
wpImages.ForceLayout();
} public void Prepare()
{
RefreshImageList(Issue.Id);
}
protected void OnItemHeightChanged(object sender, ItemHeightChangedArg e)
{
int width = e.newHeigth;
e.newWidth = width;
}
protected void OnItemWidthChanged(object sender, ItemWidthChangedArg e)
{
int width = e.newWidth;
e.newHeigth = width;
}
protected void OnSizeChanged(object sender, EventArgs e)
{
wpImages.NeedLayoutOfChildren = true;
wpImages.ForceLayout();
}
WrapPanel
namespace WrapPanelFixed.Controls
{
public class ItemHeightChangedArg : EventArgs
{
public int newWidth { get; set; }
public int newHeigth { get; private set; }
public ItemHeightChangedArg(int h)
{
newHeigth = h;
}
}
public class ItemWidthChangedArg : EventArgs
{
public int newHeigth { get; set; }
public int newWidth{ get; private set; }
public ItemWidthChangedArg(int h)
{
newWidth = h;
}
}
// Fork of the Wrappanel at https://gist.github.com/NicoVermeir/7ffb34ebd639ed958382
// This panel only allow fixed size items. and it will also strech/shrink item size to makesure it fills the orientation size
public class WrapPanelFixed : Layout<View>
{
private event EventHandler<NotifyCollectionChangedEventArgs> _collectionChanged;
public event EventHandler<ItemHeightChangedArg> ItemHeightChanged;
public event EventHandler<ItemWidthChangedArg> ItemWidthChanged;
public bool NeedLayoutOfChildren { get; set; }
public int ItemHeight { get; private set; }
public int ItemWidth { get; private set; }
public int UnusedWidth { get; private set; }
public int UnusedHeight { get; private set; }
public double HeightScaling { get; set; }
// Minimum number of items per constraint. (width or height)
public int MinimumItems {get; set;}
protected virtual void OnItemHeightChanged(int newHeight, out int newWidth)
{
newWidth = -1;
EventHandler<ItemHeightChangedArg> handler = ItemHeightChanged;
if(handler != null)
{
ItemHeightChangedArg e = new ItemHeightChangedArg(newHeight);
handler(this, e);
newWidth = e.newWidth;
}
}
protected virtual void OnItemWidthChanged(int newHeight, out int newWidth)
{
newWidth = -1;
EventHandler<ItemWidthChangedArg> handler = ItemWidthChanged;
if (handler != null)
{
ItemWidthChangedArg e = new ItemWidthChangedArg(newHeight);
handler(this, e);
newWidth = e.newWidth;
}
}
/// <summary>
/// Backing Storage for the Orientation property
/// </summary>
public static readonly BindableProperty OrientationProperty =
BindableProperty.Create<WrapPanelFixed, StackOrientation>(w => w.Orientation, StackOrientation.Vertical,
propertyChanged: (bindable, oldvalue, newvalue) => ((WrapPanelFixed)bindable).OnSizeChanged());
/// <summary>
/// Orientation (Horizontal or Vertical)
/// </summary>
public StackOrientation Orientation
{
get { return (StackOrientation)GetValue(OrientationProperty); }
set { SetValue(OrientationProperty, value); }
}
/// <summary>
/// Backing Storage for the Spacing property
/// </summary>
public static readonly BindableProperty SpacingProperty =
BindableProperty.Create<WrapPanelFixed, double>(w => w.Spacing, 6,
propertyChanged: (bindable, oldvalue, newvalue) => ((WrapPanelFixed)bindable).OnSizeChanged());
/// <summary>
/// Spacing added between elements (both directions)
/// </summary>
/// <value>The spacing.</value>
public double Spacing
{
get { return (double)GetValue(SpacingProperty); }
set { SetValue(SpacingProperty, value); }
}
public static readonly BindableProperty ItemHeightRequestProperty =
BindableProperty.Create<WrapPanelFixed, int>(w => w.ItemHeightRequest, 100,
propertyChanged: (bindable, oldvalue, newvalue) => ((WrapPanelFixed)bindable).OnSizeChanged());
public int ItemHeightRequest
{
get { return (int)GetValue(ItemHeightRequestProperty); }
set { SetValue(ItemHeightRequestProperty, value); }
}
public static readonly BindableProperty ItemWidthRequestProperty =
BindableProperty.Create<WrapPanelFixed, int>(w => w.ItemWidthRequest, 100,
propertyChanged: (bindable, oldvalue, newvalue) => ((WrapPanelFixed)bindable).OnSizeChanged());
public int ItemWidthRequest
{
get { return (int)GetValue(ItemWidthRequestProperty); }
set { SetValue(ItemWidthRequestProperty, value); }
}
/// <summary>
/// Backing Storage for the Spacing property
/// </summary>
public static readonly BindableProperty ItemTemplateProperty =
BindableProperty.Create<WrapPanelFixed, DataTemplate>(w => w.ItemTemplate, null,
propertyChanged: (bindable, oldvalue, newvalue) => ((WrapPanelFixed)bindable).OnSizeChanged());
/// <summary>
/// Spacing added between elements (both directions)
/// </summary>
/// <value>The spacing.</value>
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
/// <summary>
/// Backing Storage for the Spacing property
/// </summary>
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create<WrapPanelFixed, IEnumerable>(w => w.ItemsSource, null,
propertyChanged: ItemsSource_OnPropertyChanged);
/// <summary>
/// Spacing added between elements (both directions)
/// </summary>
/// <value>The spacing.</value>
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
private static void ItemsSource_OnPropertyChanged(BindableObject bindable, IEnumerable oldvalue, IEnumerable newvalue)
{
WrapPanelFixed wp = bindable as WrapPanelFixed;
if (oldvalue != null)
{
var coll = (INotifyCollectionChanged)oldvalue;
// Unsubscribe from CollectionChanged on the old collection
coll.CollectionChanged -= wp.ItemsSource_OnItemChanged;
}
if (newvalue != null)
{
var coll = (INotifyCollectionChanged)newvalue;
// Subscribe to CollectionChanged on the new collection
coll.CollectionChanged += wp.ItemsSource_OnItemChanged;
}
}
public WrapPanelFixed()
{
MinimumItems = 1;
HeightScaling = 1.0;
_collectionChanged += OnCollectionChanged;
NeedLayoutOfChildren = true;
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
{
if(args.Action == NotifyCollectionChangedAction.Reset)
{
Children.Clear();
NeedLayoutOfChildren = true;
}
else
{
foreach (object item in args.NewItems)
{
var child = ItemTemplate.CreateContent() as View;
if (child == null)
return;
child.BindingContext = item;
Children.Add(child);
}
NeedLayoutOfChildren = true;
}
}
public void OnCollectionRebuild(IList Items)
{
foreach (object item in Items)
{
var child = ItemTemplate.CreateContent() as View;
if (child == null)
return;
child.BindingContext = item;
Children.Add(child);
}
NeedLayoutOfChildren = true;
}
public void ItemsSource_OnItemChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (_collectionChanged != null)
_collectionChanged(sender, e);
}
/// <summary>
/// This is called when the spacing or orientation properties are changed - it forces
/// the control to go back through a layout pass.
/// </summary>
private void OnSizeChanged()
{
ForceLayout();
}
/// <summary>
/// This method is called during the measure pass of a layout cycle to get the desired size of an element.
/// </summary>
/// <param name="widthConstraint">The available width for the element to use.</param>
/// <param name="heightConstraint">The available height for the element to use.</param>
protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
{
if (WidthRequest > 0)
widthConstraint = Math.Min(widthConstraint, WidthRequest);
if (HeightRequest > 0)
heightConstraint = Math.Min(heightConstraint, HeightRequest);
double internalWidth = double.IsPositiveInfinity(widthConstraint) ? double.PositiveInfinity : Math.Max(0, widthConstraint);
double internalHeight = double.IsPositiveInfinity(heightConstraint) ? double.PositiveInfinity : Math.Max(0, heightConstraint);
return Orientation == StackOrientation.Vertical ? DoVerticalMeasure(internalWidth, internalHeight) : DoHorizontalMeasure(internalWidth, internalHeight);
}
public static int CalculateItemSize(double sizeConstraint, int requestItemSize, double itemSpacing, int MinimumItems, out int nItemsPerConstraint)
{
requestItemSize += (int)(itemSpacing / 2);
// Minimum size for MinimumItems
int MinSize = (requestItemSize * MinimumItems) + (int)(itemSpacing * (MinimumItems - 1));
if (MinimumItems > 0 && MinSize > sizeConstraint)
{
// Shrink item size so we requestItemSize is minimum of wanted items
requestItemSize = (int)((sizeConstraint - (itemSpacing * (MinimumItems - 1))) / MinimumItems); // Atleast 2 columns
}
int newItemSize = requestItemSize;
// How many items with the requested size fit in the sizeConstraint
nItemsPerConstraint = (int)(sizeConstraint / (requestItemSize + itemSpacing));
// How much space do we got left
// (There is 1 less spacing then number of item. Only spacing between items)
double spaceLeft = sizeConstraint - ((nItemsPerConstraint * (requestItemSize + itemSpacing)) - itemSpacing);
// If spaceLeft is > then 50% of requestItemSize and less then 1 full item extra, then make items bigger so they fill the sizeContraint
// else make them small so one more item fits.
if (spaceLeft > (requestItemSize * 0.5) && spaceLeft < (requestItemSize + itemSpacing))
{
int extraWidth = (int)(spaceLeft / nItemsPerConstraint);
newItemSize = (int)(requestItemSize + extraWidth);
}
else
{
nItemsPerConstraint++;
newItemSize = (int)((sizeConstraint - (itemSpacing * (nItemsPerConstraint - 1))) / nItemsPerConstraint);
}
return newItemSize;
}
/// <summary>
/// Does the vertical measure.
/// </summary>
/// <returns>The vertical measure.</returns>
/// <param name="widthConstraint">Width constraint.</param>
/// <param name="heightConstraint">Height constraint.</param>
private SizeRequest DoVerticalMeasure(double widthConstraint, double heightConstraint)
{
int nItemsPerCol = 0;
int newItemHeight = CalculateItemSize(heightConstraint, ItemHeightRequest, Spacing, MinimumItems, out nItemsPerCol);
UnusedHeight = (int)(heightConstraint - ((nItemsPerCol * (newItemHeight + Spacing)) - Spacing));
if(ItemHeight != newItemHeight)
{
int newItemWidth;
OnItemHeightChanged(newItemHeight, out newItemWidth);
if (newItemWidth == -1)
newItemWidth = newItemHeight;
ItemHeight = newItemWidth;
ItemWidth = newItemWidth;
NeedLayoutOfChildren = true;
}
// Correct for rounding error
int colCount = (int)((Children.Count / (double)nItemsPerCol) + 0.9);
double height = (ItemWidth * nItemsPerCol) + ((nItemsPerCol - 1) * Spacing);
double width = ((ItemHeight + Spacing) * colCount) - Spacing;
return new SizeRequest(new Size(width, height), new Size(width, height));
}
/// <summary>
/// Does the horizontal measure.
/// </summary>
/// <returns>The horizontal measure.</returns>
/// <param name="widthConstraint">Width constraint.</param>
/// <param name="heightConstraint">Height constraint.</param>
private SizeRequest DoHorizontalMeasure(double widthConstraint, double heightConstraint)
{
int nItemsPerRow = 0;
int newItemWidth = CalculateItemSize(widthConstraint, ItemWidthRequest, Spacing, MinimumItems, out nItemsPerRow);
UnusedWidth = (int)(widthConstraint - ((nItemsPerRow * (newItemWidth + Spacing)) - Spacing));
if(ItemWidth != newItemWidth)
{
int newItemHeight = 0;
OnItemWidthChanged(newItemWidth, out newItemHeight);
if(newItemHeight == -1)
newItemHeight = newItemWidth;
ItemWidth = newItemWidth;
ItemHeight = newItemWidth;
NeedLayoutOfChildren = true;
}
ItemHeight = (int)(ItemHeight * HeightScaling);
// Correct for rounding error
int rowCount = (int)((Children.Count / (double)nItemsPerRow)+0.9); // So if we have 12.1 rows we get 13
double width = (ItemWidth * nItemsPerRow) + ((nItemsPerRow - 1) * Spacing);
double height = ((ItemHeight + Spacing) * rowCount) - Spacing;
return new SizeRequest(new Size(width, height), new Size(width, height));
}
/// <summary>
/// Positions and sizes the children of a Layout.
/// </summary>
/// <param name="x">A value representing the x coordinate of the child region bounding box.</param>
/// <param name="y">A value representing the y coordinate of the child region bounding box.</param>
/// <param name="width">A value representing the width of the child region bounding box.</param>
/// <param name="height">A value representing the height of the child region bounding box.</param>
protected override void LayoutChildren(double x, double y, double width, double height)
{
// Prevent unnessecary layouting.(since all items are fixed in size, we only need to relayout them if itemsource is changed)
if (NeedLayoutOfChildren == false)
return;
if (Orientation == StackOrientation.Vertical)
{
double colWidth = 0;
double yPos = y, xPos = x;
foreach (var child in Children.Where(c => c.IsVisible))
{
//var request = child.GetSizeRequest(width, height);
double childWidth = ItemWidth;
double childHeight = ItemHeight;
colWidth = Math.Max(colWidth, childWidth);
if (yPos + childHeight > height)
{
yPos = y;
xPos += colWidth + Spacing;
colWidth = 0;
}
var region = new Rectangle(xPos, yPos, childWidth, childHeight);
LayoutChildIntoBoundingRegion(child, region);
yPos += region.Height + Spacing;
}
}
else
{
//double rowHeight = 0;
x += UnusedWidth / 2;
double yPos = y, xPos = x;
foreach (var child in Children.Where(c => c.IsVisible))
{
double childWidth = ItemWidth;
double childHeight = ItemHeight;
//rowHeight = Math.Max(rowHeight, childHeight);
if (xPos + childWidth > width)
{
xPos = x;
yPos += childHeight + Spacing;
//rowHeight = 0;
}
var region = new Rectangle(xPos, yPos, childWidth, childHeight);
LayoutChildIntoBoundingRegion(child, region);
xPos += region.Width + Spacing;
}
}
NeedLayoutOfChildren = false;
}
}
}

Try this:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="PhotoTemplate">
<Grid Width="50"
Height="50"
Margin="0">
<Image HorizontalAlignment="Center"
Stretch="UniformToFill">
<Image.Source>
<BitmapImage DecodePixelHeight="200"
UriSource="{Binding LocalImagePath}" />
</Image.Source>
</Image>
</Grid>
</DataTemplate>
<Style TargetType="ListViewItem">
<Setter Property="Margin" Value="0" />
<Setter Property="Padding" Value="0" />
</Style>
</Page.Resources>
<Grid Padding="48">
<ListView Name="WrapPanelContainer"
Margin="2"
IsItemClickEnabled="True"
ItemTemplate="{StaticResource PhotoTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controls:WrapPanel Background="LightGray"
VerticalSpacing="5"
HorizontalSpacing="5"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ListView>
</Grid>
</Page>

Related

Animating textbox text bound to a double property on property value change

I'd like to animate the transition from the old to the new value as seen in many software, i.e. when the value of the bound property changes, I'd like to increase or decrease the text of the text box by a specific offset until it reaches the new value. As an example:
Initial value: 26.0%
New value: 43.5%
Animation:
26.5% -> 30.0% -> 30.5% ....... -> 43.4
Is it possible to do this with the standard equipment of .Net or do you need a custom control?
Thanks in advance for any help.
I'm afraid I don't know if .NET has a custom control. But you can do it very easily with special supervision.
Step One : Create a timer
Step Two : Run timer1 object in form load event [timerName.Start();]
Step Three : Create a global variable to control the second. The local variable
Step Four : Check textbox contents by performing a second check on the tick event of the Timer object
private void Form1_Load(object sender, EventArgs e)
{
timer1.Start();
}
private int elapsed;
private void timer1_Tick(object sender, EventArgs e)
{
elapsed = elapsed + 1;
if (elapsed == 15)
{
textBox1.Text = "%" + "next value 1";
}
if (elapsed == 30)
{
textBox1.Text = "%" + "next value 2";
}
if (elapsed == 45)
{
textBox1.Text = "%" + "next value 3";
}
}
I hope I could help. If I can't help you, please write it down. Good coding!
An example of an auxiliary proxy for a discrete animation of a Double number:
using System;
using System.Windows;
namespace Proxy
{
public partial class DeltaNumberAnimator : Freezable
{
protected override Freezable CreateInstanceCore()
{
throw new NotImplementedException();
}
}
}
using System;
using System.Windows;
namespace Proxy
{
public partial class DeltaNumberAnimator
{
/// <summary>Source of number</summary>
public double Source
{
get => (double)GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
}
/// <summary><see cref="DependencyProperty"/> for property <see cref="Source"/>.</summary>
public static readonly DependencyProperty SourceProperty =
DependencyProperty.Register(nameof(Source), typeof(double), typeof(DeltaNumberAnimator), new PropertyMetadata(0d, (d, e) => ((DeltaNumberAnimator)d).SourceChanged(e)));
/// <summary>Number with animated change</summary>
public double Number
{
get => (double)GetValue(NumberProperty);
private set => SetValue(NumberPropertyKey, value);
}
private static readonly DependencyPropertyKey NumberPropertyKey =
DependencyProperty.RegisterReadOnly(nameof(Number), typeof(double), typeof(DeltaNumberAnimator), new PropertyMetadata(0d, NumberChanged));
/// <summary><see cref="DependencyProperty"/> for property <see cref="Number"/>.</summary>
public static readonly DependencyProperty NumberProperty = NumberPropertyKey.DependencyProperty;
/// <summary>Sets the delta value for a discrete change in the <see cref="Number"/> property.</summary>
public double Delta
{
get => (double)GetValue(DeltaProperty);
set => SetValue(DeltaProperty, value);
}
/// <summary><see cref="DependencyProperty"/> for property <see cref="Delta"/>.</summary>
public static readonly DependencyProperty DeltaProperty =
DependencyProperty.Register(nameof(Delta), typeof(double), typeof(DeltaNumberAnimator), new PropertyMetadata(0.01, DeltaChanged, CoerceDelta));
/// <summary>Number increment interval. </summary>
public TimeSpan Interval
{
get => (TimeSpan)GetValue(IntervalProperty);
set => SetValue(IntervalProperty, value);
}
/// <summary><see cref="DependencyProperty"/> for property <see cref="Interval"/>.</summary>
public static readonly DependencyProperty IntervalProperty =
DependencyProperty.Register(nameof(Interval), typeof(TimeSpan), typeof(DeltaNumberAnimator), new PropertyMetadata(TimeSpan.Zero, IntervalChanged));
/// <summary>Animation in progress.</summary>
public bool IsAnimation
{
get => (bool)GetValue(IsAnimationProperty);
private set => SetValue(IsAnimationPropertyKey, value);
}
public static readonly DependencyPropertyKey IsAnimationPropertyKey =
DependencyProperty.RegisterReadOnly(nameof(IsAnimation), typeof(bool), typeof(DeltaNumberAnimator), new PropertyMetadata(false));
/// <summary><see cref="DependencyProperty"/> for property <see cref="IsAnimation"/>.</summary>
public static readonly DependencyProperty IsAnimationProperty = IsAnimationPropertyKey.DependencyProperty;
}
}
using System;
using System.Windows;
using System.Windows.Threading;
namespace Proxy
{
public partial class DeltaNumberAnimator
{
private readonly DispatcherTimer timer = new DispatcherTimer();
private double source;
private double delta;
private double number;
public DeltaNumberAnimator()
{
timer.Tick += OnTick;
}
private void OnTick(object sender, EventArgs e)
{
if (NextStep())
{
timer.Stop();
IsAnimation = false;
}
}
private static void IntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((DeltaNumberAnimator)d).timer.Interval = (TimeSpan)e.NewValue;
}
private void SourceChanged(DependencyPropertyChangedEventArgs e)
{
source = (double)e.NewValue;
if (source == number)
{
timer.Stop();
IsAnimation = false;
return;
}
if (timer.Interval == TimeSpan.Zero ||
delta == 0d)
{
Number = source;
timer.Stop();
IsAnimation = false;
return;
}
if (!NextStep())
{
timer.Start();
IsAnimation = true;
}
}
// Changing Number by Delta towards Source.
// Returns true if the Source value is reached.
private bool NextStep()
{
if (number < source)
{
double next = number + delta;
if (next >= source)
{
Number = source;
return true;
}
else
{
Number = next;
return false;
}
}
else
{
double next = number - delta;
if (next <= source)
{
Number = source;
return true;
}
else
{
Number = next;
return false;
}
}
}
private static object CoerceDelta(DependencyObject d, object baseValue)
{
double num = (double)baseValue;
if (num < double.Epsilon && num > -double.Epsilon)
return 0d;
if (num > 0)
return baseValue;
return -num;
}
private static void DeltaChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((DeltaNumberAnimator)d).delta = (double)e.NewValue;
}
private static void NumberChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((DeltaNumberAnimator)d).number = (double)e.NewValue;
}
}
}
Usage example:
namespace DeltaNumber
{
public class ViewModel
{
public double NumberProperty { get; set; }
}
}
<Window x:Class="DeltaNumber.DeltaNumberTestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DeltaNumber" xmlns:proxy="clr-namespace:Proxy;assembly=Common"
mc:Ignorable="d"
Title="DeltaNumberTestWindow" Height="450" Width="800">
<FrameworkElement.DataContext>
<local:ViewModel/>
</FrameworkElement.DataContext>
<UniformGrid Columns="1">
<FrameworkElement.Resources>
<proxy:DeltaNumberAnimator x:Key="deltaAnimator"
Source="{Binding NumberProperty}"
Delta="1"
Interval="0:0:1"/>
</FrameworkElement.Resources>
<TextBlock Text="{Binding Number, Source={StaticResource deltaAnimator}}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding IsAnimation, Source={StaticResource deltaAnimator}}"
Value="True">
<Setter Property="Background" Value="LightGreen"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBox Text="{Binding NumberProperty}"/>
<TextBox Text="Any text. Used only to lose focus in an binded TextBox."/>
</UniformGrid>
</Window>

Xamarin Slider OnDraw is called only once

I am inheriting from Xamarin..Android.SliderRenderer to create a circular slider. I created a View class and assembled them already:
[assembly: ExportRendererAttribute(typeof(CircleSliderView), typeof(CircleSliderViewRenderer))]
public class CircleSliderViewRenderer : SliderRenderer
I carefully avoid the SetWillNotDraw trap in constructor:
this.SetWillNotDraw(false);
Finally, override the OnDraw method to draw something else than the original one:
protected override void OnDraw(Canvas canvas)
{
...
DrawTrack(canvas, view.MaximumTrackColor.ToAndroid(), maxSweep);
DrawTrack(canvas, view.MinimumTrackColor.ToAndroid(), minSweep);
// no call to super.OnDraw()
}
As a result, I have an arc drawn:
However, I have 2 issues here:
Old slider drawing is still there.
My OnDraw is called once and never again (even after value change).
Apparently, there is another method than OnDraw that is being called continually (susceptibly when the value changes). But the API docs do not help at all on finding this method. Does anyone know which methods I should override to solve above issues?
Thank you in advance.
You could custom a circle slider which Inherited the View,then use ViewRenderer instead of SliderRenderer.
Custom CircularSlider in Android Project:
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Android.Content;
using Android.Graphics;
using Android.Util;
using Android.Views;
using Java.Lang;
using Math = Java.Lang.Math;
namespace EntryCa.Droid
{
public class CircularSlider : View, INotifyPropertyChanged
{
int _arcRadius;
float _progressSweep;
RectF _arcRect = new RectF();
Paint _arcPaint;
Paint _progressPaint;
int _translateX;
int _translateY;
int _thumbXPos;
int _thumbYPos;
float _touchInsideIgnoreRadius;
float _touchOutsideIgnoreRadius;
int _touchCorrection = 40;
/// <summary>
/// This indicates how many points a touch event can go inside or outside the circle before the slider stops updating.
/// This may never exceed half of the controls size (this can create unwanted behaviour).
/// The value must be greater or equal to 0.
/// </summary>
public int TouchCorrection
{
get
{
return _touchCorrection;
}
set
{
if (_touchCorrection < 0)
throw new ArgumentOutOfRangeException(nameof(TouchCorrection), "The value must be at least 0");
_touchCorrection = value;
OnPropertyChanged();
}
}
int _sweepAngle = 180;
/// <summary>
/// This indicates how many degrees the circle is used.
/// The value must be between 0 and 360
/// </summary>
public int SweepAngle
{
get { return _sweepAngle; }
set
{
if (value < 0 || value > 360)
throw new ArgumentOutOfRangeException(nameof(SweepAngle), "The value must be between 0 and 360");
_sweepAngle = value;
if (Width > 0 && Height > 0)
{
CalculateArcRect(Width, Height);
UpdateProgress();
}
Invalidate();
OnPropertyChanged();
}
}
int _startAngle = 180;
/// <summary>
/// This indicates at how many degrees in the circle the indicator will start.
/// The value must be between 0 and 360.
/// </summary>
public int StartAngle
{
get { return _startAngle; }
set
{
if (value < 0 || value > 360)
throw new ArgumentOutOfRangeException(nameof(StartAngle), "The value must be between 0 and 360");
_startAngle = value;
if (Width > 0 && Height > 0)
{
CalculateArcRect(Width, Height);
UpdateProgress();
}
Invalidate();
OnPropertyChanged();
}
}
/// <summary>
/// The color of the uncompleted progress indicator.
/// </summary>
public Color Color
{
get
{
return _arcPaint.Color;
}
set
{
_arcPaint.Color = value;
Invalidate();
OnPropertyChanged();
}
}
/// <summary>
/// The color of the completed progress indicator.
/// </summary>
public Color ProgressColor
{
get
{
return _progressPaint.Color;
}
set
{
_progressPaint.Color = value;
Invalidate();
OnPropertyChanged();
}
}
Bitmap _thumb;
/// <summary>
/// The thumb image to indicate the current progress.
/// The bitmap must have the same width and height.
/// </summary>
public Bitmap Thumb
{
get
{
return _thumb;
}
set
{
if (value != null && value.Width != value.Height)
throw new ArgumentException("The image must be a square (same width and height)", nameof(Thumb));
_thumb = value;
if (Width > 0 && Height > 0)
{
CalculateArcRect(Width, Height);
UpdateProgress();
}
OnPropertyChanged();
}
}
/// <summary>
/// The line width in pixels of the circle.
/// </summary>
public int LineWidth
{
get
{
return (int)_arcPaint.StrokeWidth;
}
set
{
_arcPaint.StrokeWidth = value;
_progressPaint.StrokeWidth = value;
if (Width > 0 && Height > 0)
{
CalculateArcRect(Width, Height);
UpdateThumbPosition();
}
Invalidate();
OnPropertyChanged();
}
}
/// <summary>
/// This indicates if the circle line has rounded corners at the end of the line.
/// </summary>
public bool RoundEdges
{
get
{
return _arcPaint.StrokeCap == Paint.Cap.Round;
}
set
{
_arcPaint.StrokeCap = value ? Paint.Cap.Round : Paint.Cap.Square;
_progressPaint.StrokeCap = value ? Paint.Cap.Round : Paint.Cap.Square;
Invalidate();
OnPropertyChanged();
}
}
int _maximum;
/// <summary>
/// The maximum value of the progress.
/// </summary>
public int Maximum
{
get
{
return _maximum;
}
set
{
if (value < 0)
throw new IllegalStateException("Maximum can not be less than 0");
if (value < Progress)
throw new IllegalStateException("Maximum can not be less than Progress value" + Progress);
if (value != _maximum)
{
_maximum = value;
UpdateProgress();
OnPropertyChanged();
}
}
}
int _progress;
/// <summary>
/// The current progress.
/// </summary>
public int Progress
{
get
{
return _progress;
}
set
{
if (value < 0)
throw new IllegalStateException("Progress can not be less than 0");
if (value > Maximum)
throw new IllegalStateException("Progress can not be more than Maximum value " + Maximum);
if (value != _progress)
{
_progress = value;
UpdateProgress();
ProgressChanged?.Invoke(this, value);
OnPropertyChanged();
}
}
}
bool _clockwise = true;
/// <summary>
/// This indicates if the slider should work clockwise or counter clockwise.
/// </summary>
public bool Clockwise
{
get
{
return _clockwise;
}
set
{
_clockwise = value;
Invalidate();
OnPropertyChanged();
}
}
/// <summary>
/// This indicates if the user can interact with the control or not
/// </summary>
public override bool Enabled
{
get
{
return base.Enabled;
}
set
{
base.Enabled = value;
OnPropertyChanged();
}
}
/// <summary>
/// Triggered when one of the custom properties is changed.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Triggered when the progress value has changed.
/// </summary>
public event EventHandler<int> ProgressChanged;
public CircularSlider(Context context)
: base(context)
{
Init();
}
public CircularSlider(Context context, IAttributeSet attrs)
: base(context, attrs)
{
Init();
}
public CircularSlider(Context context, IAttributeSet attrs, int defStyle)
: base(context, attrs, defStyle)
{
Init();
}
void Init()
{
_arcPaint = new Paint
{
AntiAlias = true,
StrokeCap = Paint.Cap.Round
};
_arcPaint.SetStyle(Paint.Style.Stroke);
_progressPaint = new Paint
{
AntiAlias = true,
StrokeCap = Paint.Cap.Round
};
_progressPaint.SetStyle(Paint.Style.Stroke);
LineWidth = (int)(4 * Context.Resources.DisplayMetrics.Density);
UpdateProgress();
}
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
var width = GetDefaultSize(SuggestedMinimumWidth, widthMeasureSpec);
var height = GetDefaultSize(SuggestedMinimumHeight, heightMeasureSpec);
CalculateArcRect(width, height);
UpdateThumbPosition();
// Don't use the exact radius but include TouchCorrection or else this makes interaction too tricky
if (Thumb != null)
{
_touchInsideIgnoreRadius = _arcRadius - (Math.Min(Thumb.Width, Thumb.Height) + TouchCorrection);
_touchOutsideIgnoreRadius = _arcRadius + (Math.Min(Thumb.Width, Thumb.Height) + TouchCorrection);
}
else
{
_touchInsideIgnoreRadius = _arcRadius - TouchCorrection;
_touchOutsideIgnoreRadius = _arcRadius + TouchCorrection;
}
}
protected override void OnDraw(Canvas canvas)
{
base.OnDraw(canvas);
if (!Clockwise)
canvas.Scale(-1, 1, _arcRect.CenterX(), _arcRect.CenterY());
canvas.DrawArc(_arcRect, StartAngle, SweepAngle, false, _arcPaint);
canvas.DrawArc(_arcRect, StartAngle, _progressSweep, false, _progressPaint);
if (Thumb != null)
{
var left = (_translateX - _thumbXPos) - (Thumb.Width / 2);
var top = (_translateY - _thumbYPos) - (Thumb.Height / 2);
canvas.DrawBitmap(Thumb, left, top, null);
}
}
void CalculateArcRect(int width, int height)
{
_translateX = (int)(width * 0.5f);
_translateY = (int)(height * 0.5f);
var min = Math.Min(width, height);
if (Thumb != null)
{
var arcDiameter = min - (LineWidth + Thumb.Width);
_arcRadius = arcDiameter / 2;
var top = height / 2 - (arcDiameter / 2);
var left = width / 2 - (arcDiameter / 2);
_arcRect.Set(left, top, left + arcDiameter, top + arcDiameter);
}
else
{
var arcDiameter = min - LineWidth;
_arcRadius = arcDiameter / 2;
var top = height / 2 - (arcDiameter / 2);
var left = width / 2 - (arcDiameter / 2);
_arcRect.Set(left, top, left + arcDiameter, top + arcDiameter);
}
}
public override bool OnTouchEvent(MotionEvent e)
{
if (Enabled)
{
Parent?.RequestDisallowInterceptTouchEvent(true);
switch (e.Action)
{
case MotionEventActions.Down:
case MotionEventActions.Move:
UpdateOnTouch(e);
break;
case MotionEventActions.Up:
case MotionEventActions.Cancel:
Pressed = false;
Parent?.RequestDisallowInterceptTouchEvent(true);
break;
}
return true;
}
return false;
}
void UpdateOnTouch(MotionEvent e)
{
if (IgnoreTouch(e.GetX(), e.GetY()))
return;
Pressed = true;
var touchAngle = GetTouchDegrees(e.GetX(), e.GetY());
var progress = GetProgressForAngle(touchAngle);
if (progress >= 0)
{
Progress = progress;
}
}
bool IgnoreTouch(float xPos, float yPos)
{
var x = xPos - _translateX;
var y = yPos - _translateY;
return PointIsInsideCircle(_touchInsideIgnoreRadius, x, y) || !PointIsInsideCircle(_touchOutsideIgnoreRadius, x, y);
}
bool PointIsInsideCircle(double circleRadius, double x, double y)
{
return (Math.Pow(x, 2) + Math.Pow(y, 2)) < (Math.Pow(circleRadius, 2));
}
double GetTouchDegrees(float xPos, float yPos)
{
float x = xPos - _translateX;
float y = yPos - _translateY;
if (!Clockwise)
x = -x;
// Convert to arc Angle
var angle = Math.ToDegrees(Math.Atan2(y, x) + (Math.Pi / 2));
angle -= 90;
if (angle < 0)
{
angle = 360 + angle;
}
angle -= StartAngle;
return angle;
}
int GetProgressForAngle(double angle)
{
var valuePerDegree = (float)Maximum / SweepAngle;
var progress = (int)Math.Round(valuePerDegree * angle);
if (progress < 0 || progress > Maximum)
return -1;
return progress;
}
void UpdateProgress()
{
_progressSweep = (float)Progress / Maximum * SweepAngle;
UpdateThumbPosition();
Invalidate();
}
void UpdateThumbPosition()
{
var thumbAngle = StartAngle + _progressSweep + 180;
_thumbXPos = (int)(_arcRadius * Math.Cos(Math.ToRadians(thumbAngle)));
_thumbYPos = (int)(_arcRadius * Math.Sin(Math.ToRadians(thumbAngle)));
}
/// <summary>
/// Sets the thumb resource identifier.
/// This will automatically be converted to a bitmap and set to the Thumb property.
/// </summary>
public void SetThumbResourceId(int resId)
{
Thumb = BitmapFactory.DecodeResource(Resources, resId);
}
public void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
the in your CircleSliderViewRenderer :
class CircleSliderViewRenderer: ViewRenderer
{
Context mContext;
CircularSlider _slider;
public CircleSliderViewRenderer(Context context) : base(context)
{
mContext = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e)
{
base.OnElementChanged(e);
_slider = new CircularSlider(mContext);
_slider.Color = Android.Graphics.Color.Red;
_slider.ProgressColor = Android.Graphics.Color.Yellow;
_slider.Maximum = 50;
_slider.Progress = 20;
_slider.ProgressChanged += _slider_ProgressChanged;
SetNativeControl(_slider);
}
private void _slider_ProgressChanged(object sender, int e)
{
//when the progress change,you could do something here
}
}
the effect like this:

How to add data to the list when "pull to refresh" without clearing old data

I have a PulltoRefreshListView control:
public class PullToRefreshListView : ListView
{
private const string ScrollViewerControl = "ScrollViewer";
private const string ContainerGrid = "ContainerGrid";
private const string PullToRefreshIndicator = "PullToRefreshIndicator";
private const string RefreshButton = "RefreshButton";
private const string VisualStateNormal = "Normal";
private const string VisualStateReadyToRefresh = "ReadyToRefresh";
private DispatcherTimer compressionTimer;
private ScrollViewer scrollViewer;
private DispatcherTimer timer;
private Grid containerGrid;
private Border pullToRefreshIndicator;
private bool isCompressionTimerRunning;
private bool isReadyToRefresh;
private bool isCompressedEnough;
public event EventHandler RefreshContent;
public static readonly DependencyProperty PullTextProperty = DependencyProperty.Register("PullText", typeof(string), typeof(PullToRefreshListView), new PropertyMetadata("Pull to refresh"));
public static readonly DependencyProperty RefreshTextProperty = DependencyProperty.Register("RefreshText", typeof(string), typeof(PullToRefreshListView), new PropertyMetadata("Release to refresh"));
public static readonly DependencyProperty RefreshHeaderHeightProperty = DependencyProperty.Register("RefreshHeaderHeight", typeof(double), typeof(PullToRefreshListView), new PropertyMetadata(40D));
public static readonly DependencyProperty RefreshCommandProperty = DependencyProperty.Register("RefreshCommand", typeof(ICommand), typeof(PullToRefreshListView), new PropertyMetadata(null));
public static readonly DependencyProperty ArrowColorProperty = DependencyProperty.Register("ArrowColor", typeof(Brush), typeof(PullToRefreshListView), new PropertyMetadata(new SolidColorBrush(Colors.Red)));
private double offsetTreshhold = 40;
public PullToRefreshListView()
{
this.DefaultStyleKey = typeof(PullToRefreshListView);
Loaded += PullToRefreshScrollViewer_Loaded;
this.SizeChanged += PullToRefreshListView_SizeChanged;
}
private void PullToRefreshListView_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (ItemsPanelRoot != null)
ItemsPanelRoot.Width = e.NewSize.Width;
}
public ICommand RefreshCommand
{
get { return (ICommand)GetValue(RefreshCommandProperty); }
set { SetValue(RefreshCommandProperty, value); }
}
public double RefreshHeaderHeight
{
get { return (double)GetValue(RefreshHeaderHeightProperty); }
set { SetValue(RefreshHeaderHeightProperty, value); }
}
public string RefreshText
{
get { return (string)GetValue(RefreshTextProperty); }
set { SetValue(RefreshTextProperty, value); }
}
public string PullText
{
get { return (string)GetValue(PullTextProperty); }
set { SetValue(PullTextProperty, value); }
}
public Brush ArrowColor
{
get { return (Brush)GetValue(ArrowColorProperty); }
set { SetValue(ArrowColorProperty, value); }
}
protected override void OnApplyTemplate()
{
try
{
base.OnApplyTemplate();
scrollViewer = (ScrollViewer)GetTemplateChild(ScrollViewerControl);
scrollViewer.ViewChanging += ScrollViewer_ViewChanging;
scrollViewer.Margin = new Thickness(0, 0, 0, -RefreshHeaderHeight);
var transform = new CompositeTransform();
transform.TranslateY = -RefreshHeaderHeight;
scrollViewer.RenderTransform = transform;
containerGrid = (Grid)GetTemplateChild(ContainerGrid);
pullToRefreshIndicator = (Border)GetTemplateChild(PullToRefreshIndicator);
SizeChanged += OnSizeChanged;
}
catch (Exception wd)
{
var dwd = wd.Message;
}
}
/// <summary>
/// Initiate timers to detect if we're scrolling into negative space
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PullToRefreshScrollViewer_Loaded(object sender, RoutedEventArgs e)
{
// Show Refresh Button on non-touch device.
if (new Windows.Devices.Input.TouchCapabilities().TouchPresent == 0)
{
var refreshButton = (Button)GetTemplateChild(RefreshButton);
refreshButton.Visibility = Visibility.Visible;
refreshButton.Click += RefreshButton_Click;
}
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(100);
timer.Tick += Timer_Tick;
compressionTimer = new DispatcherTimer();
compressionTimer.Interval = TimeSpan.FromSeconds(.5);
compressionTimer.Tick += CompressionTimer_Tick;
timer.Start();
}
/// <summary>
/// Clip the bounds of the control to avoid showing the pull to refresh text
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
Clip = new RectangleGeometry()
{
Rect = new Rect(0, 0, e.NewSize.Width, e.NewSize.Height)
};
}
/// <summary>
/// Detect if we've scrolled all the way to the top. Stop timers when we're not completely in the top
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ScrollViewer_ViewChanging(object sender, ScrollViewerViewChangingEventArgs e)
{
if (e.NextView.VerticalOffset == 0)
{
timer.Start();
}
else
{
if (timer != null)
{
timer.Stop();
}
if (compressionTimer != null)
{
compressionTimer.Stop();
}
isCompressionTimerRunning = false;
isCompressedEnough = false;
isReadyToRefresh = false;
VisualStateManager.GoToState(this, VisualStateNormal, true);
}
}
/// <summary>
/// Detect if I've scrolled far enough and been there for enough time to refresh
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CompressionTimer_Tick(object sender, object e)
{
if (isCompressedEnough)
{
VisualStateManager.GoToState(this, VisualStateReadyToRefresh, true);
isReadyToRefresh = true;
}
else
{
isCompressedEnough = false;
compressionTimer.Stop();
}
}
/// <summary>
/// Invoke timer if we've scrolled far enough up into negative space. If we get back to offset 0 the refresh command and event is invoked.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Timer_Tick(object sender, object e)
{
if (containerGrid != null)
{
Rect elementBounds = pullToRefreshIndicator.TransformToVisual(containerGrid).TransformBounds(new Rect(0.0, 0.0, pullToRefreshIndicator.Height, RefreshHeaderHeight));
var compressionOffset = elementBounds.Bottom;
if (compressionOffset > offsetTreshhold)
{
if (isCompressionTimerRunning == false)
{
isCompressionTimerRunning = true;
compressionTimer.Start();
}
isCompressedEnough = true;
}
else if (compressionOffset == 0 && isReadyToRefresh == true)
{
InvokeRefresh();
}
else
{
isCompressedEnough = false;
isCompressionTimerRunning = false;
}
}
}
private void RefreshButton_Click(object sender, object e)
{
InvokeRefresh();
}
/// <summary>
/// Set correct visual state and invoke refresh event and command
/// </summary>
private void InvokeRefresh()
{
isReadyToRefresh = false;
VisualStateManager.GoToState(this, VisualStateNormal, true);
if (RefreshContent != null)
{
RefreshContent(this, EventArgs.Empty);
}
if (RefreshCommand != null && RefreshCommand.CanExecute(null) == true)
{
RefreshCommand.Execute(null);
}
}
}
and i use it in xaml:
<controls:PullToRefreshListView ItemsSource="{Binding TrackListItems}"
RefreshCommand="{Binding RefreshCommand}">
</controls:PullToRefreshListView>
and code behind:
refreshCommand = new RelayCommandN(RefreshItems);
public void RefreshItems()
{
TrackListItems.Clear();
//code: added my data in List: TrackListItems
}
In this way I always have new data, but the sheet is cleaned completely. How to do to the old data remain, and only add new data to the top of the list after "Pull To Refresh"?
What is the right strategy? I can find the data are marked as new. How to add them to the top of the list? And that there is no glitches? And do not clear the all list?
You can use List.Insert(0, newItem) to add items to the top of the list. If you want to add multiple items, you'll call have to use it multiple times. Note that calling Insert with 0 adds the items to the top of the list, which works if your items are in reverse order. If you want to add them in order, you can do something like this:
public void Refresh(ObservableCollection<Item> myList, List<Item> newItems)
{
for(int i = 0; i < newItems.Count; i++)
{
myList.Insert(i, newItem=newItems[i]);
}
}

How to re-size image without effecting the quality of original image in C#? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
How to create a multiple image thumbnails of a image in C#.
Condition is:
1. Image quality should not effect.
2. Thumbnails size should be not same.
If you are using asp.net mvc then you could try the build-in WebImage class. More info can be found here: http://msdn.microsoft.com/en-us/library/system.web.helpers.webimage(v=vs.111).aspx
For more professional use, where you want to control everything, you could use: http://imageresizing.net/ this suite is very advanced with lots of features on image resizing.
There are also plenty of options available for writing your own code, an example can be found here: http://www.codeproject.com/Articles/191424/Resizing-an-Image-On-The-Fly-using-NET
My suggestion would be: "Don't try to invent the wheel again", there are a lot of good solutions out there.
Hope this can help you out.
using System.ComponentModel;
using System.Web.UI;
/// <summary>
/// An abstract ImageFilter class.
/// </summary>
public abstract class ImageFilter
{
/// <summary>
/// Processes the image with current filter.
/// </summary>
/// <param name="image">The image to process.</param>
/// <returns>Returns a Image after applying current filter.</returns>
public abstract System.Drawing.Image Process(System.Drawing.Image image);
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString()
{
return "Image Filter";
}
}
public class ResizeFilter : ImageFilter
{
private int x = -1;
private int y = -1;
private int height;
private int width;
private InterpolationMode interpolationMode = InterpolationMode.Bicubic;
private ResizeMode resizeMode = ResizeMode.Fit;
[DefaultValue(-1)]
[Category("Behavior")]
public int X
{
get
{
return this.x;
}
set
{
if (value < 0)
{
value = -1;
}
x = value;
}
}
[DefaultValue(-1)]
[Category("Behavior")]
public int Y
{
get
{
return this.y;
}
set
{
if (value < -1)
{
value = -1;
}
y = value;
}
}
/// <summary>
/// Gets or sets a value indicating whether disable transparency.
/// </summary>
/// <value>
/// <see langword="true"/> if disable transparency; otherwise, <see langword="false"/>.
/// </value>
/// <author>Anwar</author>
/// <datetime>3/4/2011 5:37 PM</datetime>
[DefaultValue(false), Category("Behavior")]
public bool DisableTransparency { get; set; }
/// <summary>
/// Gets or sets the maximum height of the resulting image.
/// </summary>
/// <value>The height of the resulting image.</value>
[DefaultValue(0)]
[Category("Behavior")]
public int Height
{
get
{
return this.height;
}
set
{
CheckValue(value);
this.height = value;
}
}
/// <summary>
/// Gets or sets the interpolation mode used for resizing images. The default is HighQualityBicubic.
/// </summary>
/// <value>The interpolation mode.</value>
[DefaultValue(InterpolationMode.HighQualityBicubic)]
[Category("Behavior")]
public InterpolationMode InterpolationMode
{
get { return this.interpolationMode; }
set { this.interpolationMode = value; }
}
/// <summary>
/// Gets or sets the resize mode. The default value is Fit.
/// </summary>
/// <value>The image resize mode.</value>
[DefaultValue(ResizeMode.Fit)]
[Category("Behavior")]
public ResizeMode ResizeMode
{
get { return this.resizeMode; }
set { this.resizeMode = value; }
}
/// <summary>
/// Gets or sets the maximum width of the resulting image.
/// </summary>
/// <value>The width of the image..</value>
[DefaultValue(0)]
[Category("Behavior")]
public int Width
{
get
{
return this.width;
}
set
{
CheckValue(value);
this.width = value;
}
}
/// <summary>
/// Processes the image with current filter.
/// </summary>
/// <param name="image">The image to process.</param>
/// <returns>Returns a Image after applying current filter.</returns>
public override Image Process(Image image)
{
int scaledHeight = (int)(image.Height * (this.Width / (float)image.Width));
int scaledWidth = (int)(image.Width * (this.Height / (float)image.Height));
switch (this.ResizeMode)
{
case ResizeMode.Fit:
return this.FitImage(image, scaledHeight, scaledWidth);
case ResizeMode.Crop:
return this.CropImage(image, scaledHeight, scaledWidth);
default:
Debug.Fail("Should not reach this");
break;
}
return null;
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString()
{
return "Resize Filter";
}
private static void CheckValue(int value)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException("value");
}
}
private Image CropImage(Image img, int scaledHeight, int scaledWidth)
{
int resizeWidth;
int resizeHeight;
if (this.Width != 0 && this.Height != 0)
{
resizeWidth = this.Width;
resizeHeight = this.Height;
}
else if (this.Height == 0)
{
resizeWidth = this.Width;
resizeHeight = scaledHeight;
}
else if (this.Width == 0)
{
resizeWidth = scaledWidth;
resizeHeight = this.Height;
}
else
{
if (this.Width / (float)img.Width > this.Height / (float)img.Height)
{
resizeWidth = this.Width;
resizeHeight = scaledHeight;
}
else
{
resizeWidth = scaledWidth;
resizeHeight = this.Height;
}
}
Bitmap newImage = new Bitmap(this.Width, this.Height);
using (Graphics graphics = Graphics.FromImage(newImage))
{
this.SetupGraphics(graphics);
if (this.DisableTransparency)
{
graphics.FillRectangle(new SolidBrush(Color.White), 0, 0, resizeWidth, resizeHeight);
}
int srcX = this.X;
int srcY = this.Y;
if (srcX == -1)
{
srcX = (this.Width - resizeWidth) / 2;
}
if (srcY == -1)
{
srcY = (this.Height - resizeHeight) / 2;
}
graphics.DrawImage(img, new Rectangle(0, 0, resizeWidth, resizeHeight), srcX, srcY, resizeWidth, resizeHeight, GraphicsUnit.Pixel);
}
return newImage;
}
private Image FitImage(Image img, int scaledHeight, int scaledWidth)
{
int resizeWidth;
int resizeHeight;
if (this.Width != 0 && this.Height != 0)
{
resizeWidth = this.Width;
resizeHeight = this.Height;
}
else if (this.Height == 0)
{
resizeWidth = this.Width;
resizeHeight = scaledHeight;
}
else if (this.Width == 0)
{
resizeWidth = scaledWidth;
resizeHeight = this.Height;
}
else
{
if (this.Width / (float)img.Width < this.Height / (float)img.Height)
{
resizeWidth = this.Width;
resizeHeight = scaledHeight;
}
else
{
resizeWidth = scaledWidth;
resizeHeight = this.Height;
}
}
Bitmap newimage = new Bitmap(resizeWidth, resizeHeight);
using (Graphics gra = Graphics.FromImage(newimage))
{
if (DisableTransparency)
{
gra.FillRectangle(new SolidBrush(Color.White), 0, 0, resizeWidth, resizeHeight);
}
this.SetupGraphics(gra);
gra.DrawImage(img, 0, 0, resizeWidth, resizeHeight);
}
return newimage;
}
private void SetupGraphics(Graphics graphics)
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighSpeed;
graphics.InterpolationMode = this.InterpolationMode;
}
}
////Seprate this enum in your different class ResizeMode.cs
/// <summary>
/// Image Resize Modes.
/// </summary>
public enum ResizeMode
{
/// <summary>
/// Fit mode maintains the aspect ratio of the original image while ensuring that the dimensions of the result
/// do not exceed the maximum values for the resize transformation.
/// </summary>
Fit,
/// <summary>
/// Crop resizes the image and removes parts of it to ensure that the dimensions of the result are exactly
/// as specified by the transformation.
/// </summary>
Crop
}
///Your Controller Code
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult ImportImage()
{
var postedFile = Request.Files["FileUpload1"];
if (postedFile != null && postedFile.ContentLength > 0 )
{
MemoryStream ms=new MemoryStream();
postedFile.InputStream.CopyTo(ms);
Image image=new Bitmap(ms);
Guid newImageName=Guid.NewGuid();
string newNameToImage = newImageName.ToString() + Path.GetExtension(postedFile.FileName);
ResizeFilter resizeFilter=new ResizeFilter {Height = 0, Width = 75};
using (Image thumbnailImage = resizeFilter.Process(image))
{
var imagePath = Path.Combine(Server.MapPath("~/Content/Images"), newNameToImage);
thumbnailImage.Save(imagePath);
}
resizeFilter.Width = 350;
resizeFilter.Height = 0;
newImageName = Guid.NewGuid();
newNameToImage = newImageName.ToString() + Path.GetExtension(postedFile.FileName);
using (Image middleImage = resizeFilter.Process(image))
{
var imagePath = Path.Combine(Server.MapPath("~/Content/Images"), newNameToImage);
middleImage.Save(imagePath);
}
}
return RedirectToAction("Index");
}
}
///View Coding
#{
ViewBag.Title = "Index";
}
#using (Html.BeginForm("ImportImage", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="FileUpload1" id="FileUpload1" />
<input type="submit" id="submit" />
}

Round shaped buttons

How do I make a button in a round shape rather than the conventional rectangle.
I am using winforms(2.0)
First make a class. Give it name: "RoundButton".
Then write the code directly as this:
using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Linq;
using System.Text;
namespace WindowsFormsApplication1
{
public class RoundButton : Button
{
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
GraphicsPath grPath = new GraphicsPath();
grPath.AddEllipse(0, 0, ClientSize.Width, ClientSize.Height);
this.Region = new System.Drawing.Region(grPath);
base.OnPaint(e);
}
}
}
Then, build your application and close this.
Now go to the toolbox and you will see a control named RoundButton.
Then drag and drop this on your Windows form and test it.
GraphicsPath p = new GraphicsPath();
p.AddEllipse(1, 1, button1.Width - 4, button1.Height - 4);
button1.Region = new Region(p);
Code project has many articles about these kinds of things, especially the article RoundButton Windows Control - Ever Decreasing Circles might be of interest since it shows you have to do different kinds of round buttons.
This or this could help if you need to implement your own Button class based on the default Windows Forms button. You can also search online for more examples.
What about 'GDI'?
Implementation Example:
#region <Round Corners> : (Properties)
// [Use Round Corners]
private bool useRoundCorners = false;
[Category("Control Corners"), DisplayName("Round Corners")]
[Description("Set Round Corners.")]
[Browsable(true)]
public bool UseRoundBorders
{
get { return useRoundCorners; }
set { if (useRoundCorners != value) { useRoundCorners = value; Invalidate(); } }
}
// [Ellipse Radius]
private int ellipseRadius = 20;
[Category("Control Corners"), DisplayName("Radius")]
[Description("Set Corner (Ellipse) Radius")]
[Browsable(true)]
public int EllipseRadius
{
get { return ellipseRadius.FixedValue(0, 90); }
set { if (ellipseRadius != value.FixedValue(0, 90)) { ellipseRadius = value; Invalidate(); } }
}
#endregion
#region <Round Corners> : (Draw)
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
private static extern IntPtr CreateRoundRectRgn
(
int nLeftRect, // x-coordinate of upper-left corner
int nTopRect, // y-coordinate of upper-left corner
int nRightRect, // x-coordinate of lower-right corner-
int nBottomRect, // y-coordinate of lower-right corner
int nWidthEllipse, // width of ellipse
int nHeightEllipse // height of ellipse
);
/// <summary> Draw Corners (Round or Square). </summary>
/// <param name="e"></param>
private void DrawCorners()
{
if (useRoundCorners) { this.Region = Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, ellipseRadius, ellipseRadius)); }
else { this.Region = Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 0, 0)); }
}
#endregion
/// <summary> Redraw (Update) the Control. </summary>
/// <param name="e"></param>
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
DrawCorners();
}
Extension to Limit Round Corner Radius (*Range: 0-90)
Author: Salvador
// Extension to Set Min. & Max. Values to Properties
public static class Extensions
{
public static int FixedValue(this int value, int min, int max)
{
if (value >= min && value <= max) { return value; }
else if (value > max) { return max; }
else if (value < min) { return min; }
else { return 1; }
}
}
This is what you want
public class RoundButton : Control
{
private readonly Label lbl;
public RoundButton() : base()
{
lbl = new Label
{
Text = Text,
ForeColor = ForeColor,
BackColor = BackColor,
Font = Font
};
CenterInParent();
}
private void CenterInParent()
{
lbl.Left = (Width - lbl.Width) / 2;
lbl.Top = (Height - lbl.Height) / 2;
}
protected override void OnPaint(PaintEventArgs e)
{
GraphicsPath grPath = new GraphicsPath();
grPath.AddEllipse(0, 0, ClientSize.Width, ClientSize.Height);
Region = new Region(grPath);
base.OnPaint(e);
}
protected override void OnMove(EventArgs e)
{
CenterInParent();
base.OnMove(e);
}
protected override void OnTextChanged(EventArgs e)
{
lbl.Text = Text;
base.OnTextChanged(e);
}
protected override void OnForeColorChanged(EventArgs e)
{
lbl.ForeColor = ForeColor;
base.OnForeColorChanged(e);
}
protected override void OnBackColorChanged(EventArgs e)
{
lbl.BackColor = BackColor;
base.OnBackColorChanged(e);
}
protected override void OnFontChanged(EventArgs e)
{
lbl.Font = Font;
base.OnFontChanged(e);
}
}
Pros:
No cuts
Round
Cons:
Wrong designer loader for round button
public class OptionsMenu : Button
{
public OptionsMenu(int NoOfOptions, Point Location, ControlCollection controls,
Size ButtonSize, int DistanceBetweenOptions)
{
Button[] buttons = new Button[NoOfOptions];
for (int i = 0; i < NoOfOptions; i++)
{
buttons[i] = new Button()
{
Size = ButtonSize,
};
GraphicsPath p = new GraphicsPath();
p.AddEllipse(1, 1, buttons[i].Width - 4, buttons[i].Height - 4);
buttons[i].Region = new Region(p);
buttons[i].Location = new Point(Location.X, Location.Y + DistanceBetweenOptions * i);
controls.Add(buttons[i]);
}
}
}
You can call it like this:
OptionsMenu menu = new OptionsMenu(4, new Point(50, 50), Controls, new Size(20, 20), 40);
Controls.AddRange(new Control[]
{
menu
});

Categories