Crop image with rectangle - windows-8

I have a Image and I want crop it by using a rectangle, code below is the code I put a image and draw a rectangle at middle of the image:
MainPage.Xaml:
<Canvas x:Name="canvas" HorizontalAlignment="Center" VerticalAlignment="Center" Width="340" Height="480" Background="Blue">
<Image x:Name="photo" HorizontalAlignment="Center" VerticalAlignment="Center" ManipulationMode="All">
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
<Path Stroke="Black" StrokeThickness="1">
<Path.Data>
<RectangleGeometry Rect="0,0,340,480"/>
</Path.Data>
</Path>
</Canvas>
I successful display the image and draw a rectangle. The sample image as below:
Now I want click a button to crop the image within the rectangle(not auto clip). The rectangle is auto added when image loaded. So cannot use "Point Pressed" and "Point Released". And also cannot use "rectangle.clip" because it will auto clip the image. How do I solve it? Thanks
Updated:
I able to move the image,How do I bind the data and set the rectangle coordinate to dynamic? Code below is to transform the image. Thanks.
public sealed partial class MainPage: Page
{
private CompositeTransform compositeTranslation;
public MainPage()
{
this.InitializeComponent();
photo.ManipulationDelta += Composite_ManipulationDelta;
compositeTranslation = new CompositeTransform();
photo.RenderTransform = this.compositeTranslation;
}
void Composite_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
// scale the image.
compositeTranslation.CenterX = photo.ActualWidth / 2;
compositeTranslation.CenterY = photo.ActualHeight / 2;
compositeTranslation.ScaleX *= e.Delta.Scale;
compositeTranslation.ScaleY *= e.Delta.Scale;
compositeTranslation.TranslateX += e.Delta.Translation.X;
compositeTranslation.TranslateY += e.Delta.Translation.Y;
}
}

I have not used or XAML as it creates confusion for me. So I created a snippet according to you problem. Try that and let me know the results. I have used the same image as you posted
XAML
<Page.BottomAppBar>
<AppBar IsSticky="True" IsOpen="True">
<Button Content="Crop" Click="btnCrop_Click" />
</AppBar>
</Page.BottomAppBar>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Image x:Name="photo" HorizontalAlignment="Center" VerticalAlignment="Center" ManipulationMode="All" Source="http://i.stack.imgur.com/UIBSp.png" />
<Path x:Name="path" Stroke="Red" StrokeThickness="3">
<Path.Data>
<RectangleGeometry Rect="545,212,440,420"/>
</Path.Data>
</Path>
</Grid>
C#
private void btnCrop_Click(object sender, RoutedEventArgs e)
{
var _rect = new RectangleGeometry();
_rect.Rect = path.Data.Bounds;
photo.Clip = _rect;
}

Related

Displaying a Progress Bar

I have an image control in my main page and the code is as follows:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel HorizontalAlignment="Left" Height="597" VerticalAlignment="Top" Width="440">
<Image x:Name="hinh1" Height="488" Stretch="Fill"/>
<ProgressBar Name="loading" Height="10" IsIndeterminate="True" Visibility="Collapsed"/>
</StackPanel>
</Grid>
and in code behind i have this code :
Uri hinh = new Uri
("http://taigamejar.net/wp-content/uploads/2014/01/Hinh-Anh-Dep-5.jpg", UriKind.Absolute);
hinh1.Source = new BitmapImage(hinh);
While waiting for the image to load, I want to call progress bar run to inform the user that it is loading. Once the the image has loaded, the progress bar should disappear. How can I do this?
If I were you, I would prefer to use , not ProgressBar.
So, I'll give
protected override void OnNavigatedTo(NavigationEventArgs e)
{
loading.IsActive = true;
Uri hinh = new Uri
("http://taigamejar.net/wp-content/uploads/2014/01/Hinh-Anh-Dep-5.jpg", UriKind.Absolute);
hinh1.Source = new BitmapImage(hinh);
hinh1.ImageOpened+=hinh1_ImageOpened; //loadingbar will be disappear when this triggered
}
private void hinh1_ImageOpened(object sender, RoutedEventArgs e)
{
loading.IsActive = false; //this will disable the progressring.
}
And XAML:
<StackPanel HorizontalAlignment="Left" Height="597" VerticalAlignment="Top" Width="400">
<Image x:Name="hinh1" Height="488" Stretch="Fill" ImageOpened="hinh1_ImageOpened"/>
<ProgressRing Name="loading" Height="109" IsActive="True" />
</StackPanel>
If you don't have WP8.1 SDK yet, you can get ProgressRing here: http://www.onurtirpan.com/onur-tirpan/english/windows-phone-english/using-progressring-in-windows-phone/

Get selected controls from Pivot.ItemTemplate

I have a XAML:
<phone:Pivot Name="pivot" SelectionChanged="pivot_SelectionChanged">
<phone:Pivot.ItemTemplate>
<DataTemplate>
<ViewportControl Name="viewport">
<Canvas Name="canvas">
<Image Name="image"
RenderTransformOrigin="0,0"
CacheMode="BitmapCache"
Source="{Binding ImageSource}">
<Image.RenderTransform>
<ScaleTransform x:Name="xform"/>
</Image.RenderTransform>
</Image>
</Canvas>
</ViewportControl>
</DataTemplate>
</phone:Pivot.ItemTemplate>
</phone:Pivot>
Can I get current ViewportControl, Canvas, etc for selected item? For example
private void pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//get ViewportControl, Canvas, etc
}
Not necessarily with SelectionChanged, may have other solutions?
Yes, but you have to search for them. You need to use VisualTreeHelper and hunt for children of the desired type.
Or you can have some mapping in the code-behind for all controls and the parent pivot items.

Binding the Images to Image Tag from PhotoChooserTask in ListBox with Same Size in Windows Phone 7

I am working on windows phone 7.
i have to bind the images selected from PhotoChooserTask in a ListBox like Tiles in Windows Phone 7.
I have a design file like this:
<ListBox x:Name="lstImages" Height="530" Margin="0,10,0,0"
ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Style="{StaticResource PickerBoxButton}"
x:Name="btnDashboardItems"
Tag="{Binding Name}"
Padding="0" Margin="-18,0,-12,-45" Height="200"
Width="200">
<Button.Template>
<ControlTemplate>
<StackPanel Height="173" Width="173">
<Image Height="173" Width="173"
Source="{Binding Image}" />
</StackPanel>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel Width="450" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
and i have a class called ImageList like this:
public class ImageList
{
public string Name { get; set; }
public BitmapImage Image { get; set; }
}
and I am binding to the listbox like this:
PhotoChooserTask task = new PhotoChooserTask();
task.Completed += new EventHandler<PhotoResult>(task_Completed);
task.Show();
Here i can select any No of Images So i have taken the ListBox.
Random _Random = new Random();
private void task_Completed(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
System.IO.Stream stream = e.ChosenPhoto;
BitmapImage bmp = new BitmapImage();
bmp.CreateOptions = BitmapCreateOptions.None;
bmp.SetSource(stream);
img.Image = bmp;
img.Name = _Random.Next(int.MaxValue).ToString() + ".jpg";
StateUtilities.ImageList.Add(img);
if (StateUtilities.ImageList != null)
{
if (StateUtilities.ImageList.Count > 0)
{
lstImages.ItemsSource = StateUtilities.ImageList;
}
}
}
}
Here i am able bind the images but images are coming at different sizes but i have given fixed size(Height and Width) to button and Image Tag, still I am getting the images in Different Sizes (Different Height and Width) .
How can i make that images bind at Same Size?
Thanks,
Avinash
I think that the StackPanel will stretch according to the content.
Have you tried setting MaxWidth and MaxHeight too?

Enabling ScrollViewer HorizontalSnapPoints with bindable collection

I'm trying to create a similar experience as in the ScrollViewerSample from the Windows 8 SDK samples to be able to snap to the items inside a ScrollViewer when scrolling left and right. The implementation from the sample (which works) is like this:
<ScrollViewer x:Name="scrollViewer" Width="480" Height="270"
HorizontalAlignment="Left" VerticalAlignment="Top"
VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto"
ZoomMode="Disabled" HorizontalSnapPointsType="Mandatory">
<StackPanel Orientation="Horizontal">
<Image Width="480" Height="270" AutomationProperties.Name="Image of a cliff" Source="images/cliff.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of Grapes" Source="images/grapes.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of Mount Rainier" Source="images/Rainier.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of a sunset" Source="images/sunset.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of a valley" Source="images/valley.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</StackPanel>
</ScrollViewer>
The only difference with my desired implementation is that I don't want a StackPanel with items inside, but something I can bind to. I am trying to accomplish this with an ItemsControl, but for some reason the Snap behavior does not kick in:
<ScrollViewer x:Name="scrollViewer" Width="480" Height="270"
HorizontalAlignment="Left" VerticalAlignment="Top"
VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto"
ZoomMode="Disabled" HorizontalSnapPointsType="Mandatory">
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<Image Width="480" Height="270" AutomationProperties.Name="Image of a cliff" Source="images/cliff.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of Grapes" Source="images/grapes.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of Mount Rainier" Source="images/Rainier.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of a sunset" Source="images/sunset.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Image Width="480" Height="270" AutomationProperties.Name="Image of a valley" Source="images/valley.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</ItemsControl>
</ScrollViewer>
Suggestions would be greatly appreciated!
Thanks to Denis, I ended up using the following Style on the ItemsControl and removed the ScrollViewer and inline ItemsPanelTemplate altogether:
<Style x:Key="ItemsControlStyle" TargetType="ItemsControl">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer Style="{StaticResource HorizontalScrollViewerStyle}" HorizontalSnapPointsType="Mandatory">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Getting snap points to work for bound collections can be tricky. For snap points to work immediate child of ScrollViewer should implement IScrollSnapPointsInfo interface. ItemsControl doesn't implement IScrollSnapPointsInfo and consequently you wouldn't see snapping behaviour.
To work around this issue you got couple options:
Create custom class derived from ItemsControl and implement IScrollSnapPointsInfo interface.
Create custom style for items control and set HorizontalSnapPointsType property on ScrollViewer inside the style.
I've implemented former approach and can confirm that it works, but in your case custom style could be a better choice.
Ok, here is the simplest (and standalone) example for horizontal ListView with binded items and correctly working snapping (see comments in following code).
xaml:
<ListView x:Name="YourListView"
ItemsSource="{x:Bind Path=Items}"
Loaded="YourListView_OnLoaded">
<!--Set items panel to horizontal-->
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<!--Some item template-->
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
background code:
private void YourListView_OnLoaded(object sender, RoutedEventArgs e)
{
//get ListView
var yourList = sender as ListView;
//*** yourList style-based changes ***
//see Style here https://msdn.microsoft.com/en-us/library/windows/apps/mt299137.aspx
//** Change orientation of scrollviewer (name in the Style "ScrollViewer") **
//1. get scrollviewer (child element of yourList)
var sv = GetFirstChildDependencyObjectOfType<ScrollViewer>(yourList);
//2. enable ScrollViewer horizontal scrolling
sv.HorizontalScrollMode =ScrollMode.Auto;
sv.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
sv.IsHorizontalRailEnabled = true;
//3. disable ScrollViewer vertical scrolling
sv.VerticalScrollMode = ScrollMode.Disabled;
sv.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
sv.IsVerticalRailEnabled = false;
// //no we have horizontally scrolling ListView
//** Enable snapping **
sv.HorizontalSnapPointsType = SnapPointsType.MandatorySingle; //or you can use SnapPointsType.Mandatory
sv.HorizontalSnapPointsAlignment = SnapPointsAlignment.Near; //example works only for Near case, for other there should be some changes
// //no we have horizontally scrolling ListView with snapping and "scroll last item into view" bug (about bug see here http://stackoverflow.com/questions/11084493/snapping-scrollviewer-in-windows-8-metro-in-wide-screens-not-snapping-to-the-las)
//** fix "scroll last item into view" bug **
//1. Get items presenter (child element of yourList)
var ip = GetFirstChildDependencyObjectOfType<ItemsPresenter>(yourList);
// or var ip = GetFirstChildDependencyObjectOfType<ItemsPresenter>(sv); //also will work here
//2. Subscribe to its SizeChanged event
ip.SizeChanged += ip_SizeChanged;
//3. see the continuation in: private void ip_SizeChanged(object sender, SizeChangedEventArgs e)
}
public static T GetFirstChildDependencyObjectOfType<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj is T) return depObj as T;
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = GetFirstChildDependencyObjectOfType<T>(child);
if (result != null) return result;
}
return null;
}
private void ip_SizeChanged(object sender, SizeChangedEventArgs e)
{
//3.0 if rev size is same as new - do nothing
//here should be one more condition added by && but it is a little bit complicated and rare, so it is omitted.
//The condition is: yourList.Items.Last() must be equal to (yourList.Items.Last() used on previous call of ip_SizeChanged)
if (e.PreviousSize.Equals(e.NewSize)) return;
//3.1 get sender as our ItemsPresenter
var ip = sender as ItemsPresenter;
//3.2 get the ItemsPresenter parent to get "viewable" width of ItemsPresenter that is ActualWidth of the Scrollviewer (it is scrollviewer actually, but we need just its ActualWidth so - as FrameworkElement is used)
var sv = ip.Parent as FrameworkElement;
//3.3 get parent ListView to be able to get elements Containers
var yourList = GetParent<ListView>(ip);
//3.4 get last item ActualWidth
var lastItem = yourList.Items.Last();
var lastItemContainerObject = yourList.ContainerFromItem(lastItem);
var lastItemContainer = lastItemContainerObject as FrameworkElement;
if (lastItemContainer == null)
{
//NO lastItemContainer YET, wait for next call
return;
}
var lastItemWidth = lastItemContainer.ActualWidth;
//3.5 get margin fix value
var rightMarginFixValue = sv.ActualWidth - lastItemWidth;
//3.6. fix "scroll last item into view" bug
ip.Margin = new Thickness(ip.Margin.Left,
ip.Margin.Top,
ip.Margin.Right + rightMarginFixValue, //APPLY FIX
ip.Margin.Bottom);
}
public static T GetParent<T>(DependencyObject reference) where T : class
{
var depObj = VisualTreeHelper.GetParent(reference);
if (depObj == null) return (T)null;
while (true)
{
var depClass = depObj as T;
if (depClass != null) return depClass;
depObj = VisualTreeHelper.GetParent(depObj);
if (depObj == null) return (T)null;
}
}
About this example.
Most of checks and errors handling is omitted.
If you override ListView Style/Template, VisualTree search parts must be changed accordingly
I'd rather create inherited from ListView control with this logic, than use provided example as-is in real code.
Same code works for Vertical case (or both) with small changes.
Mentioned snapping bug - ScrollViewer bug of handling SnapPointsType.MandatorySingle and SnapPointsType.Mandatory cases. It appears for items with not-fixed sizes
.

Bind a Path Stroke color to Foreground

Using the TabControl element for Silverlight in Blend I created the following markup:
<controls:TabControl>
<controls:TabItem Header="TabItem" Style="{StaticResource TabItemStyle1}" />
<controls:TabItem Style="{StaticResource TabItemStyle1}">
<controls:TabItem.Header>
<StackPanel Orientation="Horizontal">
<Path Data="M0,14L0,6 5,0 10,6 10,14 0,6 10,6 0,14 10,14"
StrokeLineJoin="Round" Margin="0 0 6 0"
Stroke="Black"/>
<TextBlock Text="TabItem"/>
</StackPanel>
</controls:TabItem.Header>
</controls:TabItem>
</controls:TabControl>
TabItemStyle1 is a copy of the default style of a TabItem.
I altered TabItemStyle1 by adding a color animation in the MouseOver storyboard so that unselected tab items become red when the mouse hovers them:
<ColorAnimation BeginTime="0" Duration="00:00:00.001"
Storyboard.TargetName="HeaderTopUnselected"
Storyboard.TargetProperty="(UIElement.Foreground).(SolidColorBrush.Color)"
To="Red" />
Now when I hover the second tab, the text becomes red but the Path remains black:
How should I define the Path Stroke color to make it follow the same rule?
The following should work:
<controls:TabControl>
<controls:TabItem Header="TabItem" Style="{StaticResource TabItemStyle1}" />
<controls:TabItem Style="{StaticResource TabItemStyle1}">
<controls:TabItem.Header>
<StackPanel Orientation="Horizontal">
<Path Data="M0,14L0,6 5,0 10,6 10,14 0,6 10,6 0,14 10,14"
StrokeLineJoin="Round" Margin="0 0 6 0"
Stroke="{Binding ElementName=textBlock, Path=Foreground}"/>
<TextBlock x:Name="textBlock" Text="TabItem"/>
</StackPanel>
</controls:TabItem.Header>
</controls:TabItem>
</controls:TabControl>
it's not a perfect solution but you could use this
<sdk:TabControl>
<sdk:TabItem Header="item1"></sdk:TabItem>
<sdk:TabItem Foreground="Red" x:Name="someNameForTheTab">
<sdk:TabItem.Header>
<StackPanel Orientation="Horizontal">
<!--Just set stroke binding to the foreground of the tabItem-->
<Path Stroke="{Binding Foreground, ElementName=someNameForTheTab}" Data="M0,14L0,6 5,0 10,6 10,14 0,6 10,6 0,14 10,14"
StrokeLineJoin="Round" Margin="0 0 6 0"/>
<TextBlock Text="item2"/>
</StackPanel>
</sdk:TabItem.Header>
</sdk:TabItem>
</sdk:TabControl>
Try binding to the TemplatedParent like this:
<Path
Data="M0,14L0,6 5,0 10,6 10,14 0,6 10,6 0,14 10,14"
StrokeLineJoin="Round"
Margin="0 0 6 0"
Stroke="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}"/>
I haven't tested this, but give it a whirl and let me know. If it doesn't work, try this:
<Path Data="M0,14L0,6 5,0 10,6 10,14 0,6 10,6 0,14 10,14" StrokeLineJoin="Round" Margin="0 0 6 0">
<Path.Stroke>
<SolidColorBrush Color="{Binding Foreground.Color, RelativeSource={RelativeSource TemplatedParent}}" />
</Path.Stroke>
</Path>
I have a feeling that the Color property needs to be the source of binding, not the actual brush.
I made it work by binding the header content brushes to {TemplateBinding TextElement.Foreground}.
In other cases I used standard property binding with converters, for example if I had to adapt element's brushes to item state.
// animazione periferica
public static void LineAnimation(Line _line,String _colore)
{
Storyboard result = new Storyboard();
Duration duration = new Duration(TimeSpan.FromSeconds(2));
ColorAnimation animation = new ColorAnimation();
animation.RepeatBehavior = RepeatBehavior.Forever;
animation.Duration = duration;
switch (_colore.ToUpper())
{
case "RED":
animation.From = Colors.Red;
break;
case "ORANGE":
animation.From = Colors.Orange;
break;
case "YELLOW":
animation.From = Colors.Yellow;
break;
case "GRAY":
animation.From = Colors.DarkGray;
break;
default:
animation.From = Colors.Green;
break;
}
animation.To = Colors.Gray;
Storyboard.SetTarget(animation, _line);
Storyboard.SetTargetProperty(animation, new PropertyPath("(Line.Stroke).(SolidColorBrush.Color)"));
result.Children.Add(animation);
result.Begin();
}
}
//**********************************************
public partial class MainPage : UserControl
{
public Line _line;
public MainPage()
{
InitializeComponent();
Canvas.MouseLeftButtonDown += Canvas_MouseLeftButtonDown;
Canvas.MouseLeftButtonUp += Canvas_MouseLeftButtonUp;
}
void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
_line.X2 = e.GetPosition(this.Canvas).X;
_line.Y2 = e.GetPosition(this.Canvas).Y;
_line.Loaded += _line_Loaded;
Canvas.Children.Add(_line);
}
void _line_Loaded(object sender, RoutedEventArgs e)
{
Cls_Barriere.LineAnimation(sender as Line, "RED");
}
void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_line = new Line();
_line.Stroke = new SolidColorBrush(Colors.White);
_line.StrokeThickness = 5;
_line.StrokeStartLineCap = PenLineCap.Round;
_line.StrokeEndLineCap = PenLineCap.Round;
_line.StrokeDashCap = PenLineCap.Round;
_line.X1 = e.GetPosition(this.Canvas).X;
_line.Y1= e.GetPosition(this.Canvas).Y;
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
}
}