I have added 10 images in a stackpanel horizontally which is inside a scrollviewer. When user swipe the page the scrollviewer stops at certain position, if the scroll stops at &th image i want to get the name of the image. How to get that?
for (int i = 0; i <= 59; i++)
{
Uri uri = new Uri("http://d1mu9ule1cy7bp.cloudfront.net/2012/media/catalogues/47/pages/p_" + i + "/thump.jpg");
ImageSource img1 = new BitmapImage(uri);
Image rect = new Image { RenderTransform = new TranslateTransform() };
rect.Source = img1;
stack.Children.Add(rect);
}
XAML:
<ScrollViewer HorizontalContentAlignment="Left" HorizontalAlignment="Left" Name="scroll" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Visible">
<StackPanel Name="stack" Width="Auto" Orientation="Horizontal" HorizontalAlignment="Left" >
</StackPanel>
</ScrollViewer>
Assuming that your images are all the same size, you could calculate this by looking at the HorizontalOffset of the ScrollViewer.
Related
I'm receiving a live video from a DJI drone in a SwapChainPanel and I'm using template matching from OpenCV to find an image inside the frames of the video.
I want to draw a rectangle when the subgimage is detected, but there are white spaces in both sides of the frames and I don't know how to get the size of those or align the image to the left and top.
Here is the XAML:
<SwapChainPanel x:Name="swapChainPanel" Grid.Column="8" Grid.ColumnSpan="4" Grid.Row="2" Grid.RowSpan="11">
<Canvas>
<Rectangle x:Name="rectFiducial" Visibility="Collapsed" Stroke="Red"></Rectangle>
<Rectangle Stroke="Blue" Width="400" Height="400"></Rectangle>
</Canvas>
</SwapChainPanel>
Here is the code when I try to draw the rectangle with the results of the Template Matching:
SoftwareBitmap inputBitmap = SoftwareBitmap.CreateCopyFromBuffer(CryptographicBuffer.CreateFromByteArray(imageData),
BitmapPixelFormat.Rgba8,
imageWidth,
imageHeight);
if (inputBitmap.BitmapPixelFormat != BitmapPixelFormat.Bgra8
|| inputBitmap.BitmapAlphaMode != BitmapAlphaMode.Premultiplied)
{
inputBitmap = SoftwareBitmap.Convert(inputBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
}
int x = 0, y = 0, matchMethod = 0;
double matchResult = 0;
Stopwatch testWatch = new Stopwatch();
testWatch.Start();
await txtMatchMethod.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
int.TryParse(txtMatchMethod.Text, out matchMethod);
});
OpenCV.TemplateMatching(inputBitmap, template, matchMethod, out x, out y, out matchResult);
testWatch.Stop();
await txtMatchTime.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
txtMatchTime.Text = testWatch.ElapsedMilliseconds.ToString();
txtMatchResult.Text = matchResult.ToString();
double swapX = x * swapChainPanel.ActualWidth / imageWidth;
double swapY = y * swapChainPanel.ActualHeight / imageHeight;
double swapWidth = template.PixelWidth * swapChainPanel.ActualWidth / imageWidth;
double swapHeight = template.PixelHeight * swapChainPanel.ActualHeight / imageHeight;
rectFiducial.SetValue(Canvas.LeftProperty, swapX);
rectFiducial.SetValue(Canvas.TopProperty, swapY);
rectFiducial.Width = swapWidth;
rectFiducial.Height = swapHeight;
rectFiducial.Visibility = Visibility.Visible;
});
}
There is an event where I can get the bytes of the image and I tried to display it in an Image inside a Canvas, but the image didn't stretch to fit the canvas size.
Edit
I realized that I'm calculating the position based on the width and height of the SwapChainPanel, but I have to calculate it with the width and height of the image inside.
So I would need to get the data of the resized image that is inside the SwapChainPanel and the padding of the left side.
Well, I couldn't find a solution for the SwapChainPanel, but I found a solution with the image and the canvas.
I was trying to make something like this:
<Canvas x:Name="canvas" Grid.Column="8" Grid.ColumnSpan="4" Grid.Row="4" Grid.RowSpan="11">
<Image x:Name="imgDrone" HorizontalAlignment="Left"/>
<Rectangle x:Name="rectFiducial" Visibility="Collapsed" Stroke="Red"></Rectangle>
<Rectangle Stroke="Blue" Width="400" Height="400"></Rectangle>
</Canvas>
But I couldn't stretch the image, it was displayed with it's real size.
So instead of declaring the image inside the Canvas I just took it out and set it's column and row with the same values of the canvas.
Like this:
<Image x:Name="imgDrone" HorizontalAlignment="Left" Grid.Column="8" Grid.ColumnSpan="2" Grid.Row="2" Grid.RowSpan="11"/>
<Canvas x:Name="canvas" Grid.Column="8" Grid.ColumnSpan="4" Grid.Row="4" Grid.RowSpan="11">
<Rectangle x:Name="rectFiducial" Visibility="Collapsed" Stroke="Red"></Rectangle>
<Rectangle Stroke="Blue" Width="400" Height="400"></Rectangle>
</Canvas>
I am building an application like a noteBook in Landscape.
I have two canvas next to each other and I'm changing the Background inside them.
Every time I write on the two canvas and move to another 2 backgrounds, I need to save what I wrote on the two canvas and reload it once I move to these backgrounds once again, and clear them. And do the same for all the backgrounds.
<Grid x:Name="RenderedGrid" Width="1140" Height="770">
<ScrollViewer x:Name="DScrollViewer" MaxZoomFactor="2.0" MinZoomFactor="1.0" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" ZoomMode="Disabled">
<StackPanel Orientation="Horizontal">
<Canvas x:Name="inkCanvas0" HorizontalAlignment="Left" Width="570">
<Canvas.Background>
<ImageBrush x:Name="DImage0" ImageSource="{Binding}"/>
</Canvas.Background>
</Canvas>
<Canvas x:Name="inkCanvas1" HorizontalAlignment="Right" Width="570">
<Canvas.Background>
<ImageBrush x:Name="DImage1" ImageSource="{Binding}"/>
</Canvas.Background>
</Canvas>
</StackPanel>
</ScrollViewer>
</Grid>
I need to bind the Canvas in a way to this class instead of inkCanvas0 & inkCanvas1:
public class MyCanvas
{
public Canvas inkCanvas { get; set; }
}
List<MyCanvas> CanvasList = new List<MyCanvas>();
This is how I am creating Empty Canvas and storing them in CanvasList:
for (int i = 0; i < 24; i++)
{
Canvas canvas = new Canvas();
canvas.Name = "inkCanvas" + i;
MyCanvas mc = new MyCanvas();
mc.inkCanvas = canvas;
CanvasList.Add(mc);
}
I need to Bind these Canvas to the its corresponding page (inkCanvas0 to page0)
but I'm getting an exception in Xaml when I try to bind the Name of the Canvas.
<Canvas x:Name="{Binding}" HorizontalAlignment="Left" Width="570">
Exception: Catastrophic failure The name already exists in the tree.
How can I solve this? Is my logic of creating and loading the Canvas correct?
I'm having trouble getting the selectionBox not to center. In the image below, I tried to draw a box around the word Final Bill (accented ms paint box) by clicking and dragging but the resulting selectionBox (dashed line in red) that outputs always starts in the center. The rectangle values that are calculated and saved in the mouseUp event are all correct, suggesting perhaps a XAML display issue?
I am very knew to WPF/XAML and front end stuff in general.
EDIT: By placing just the selectionBox in a <Canvas> tag I was able to get it almost working. It no longer centers but the start point appears to be twice as far from the left and top borders as the mouse is when clicked.
XAML
<DockPanel Width="Auto" Margin="225,65,5,5">
<Border x:Name="img_Border" ClipToBounds="True" Height="Auto" Width="Auto" Margin="0,0,0,0" VerticalAlignment="Top">
<Grid>
<ScrollViewer>
<Image x:Name="img_Box" ClipToBounds="True" MouseMove="img_Box_MouseMove" MouseWheel="img_Box_MouseWheel">
</Image>
</ScrollViewer>
<Rectangle x:Name="selectionBox" Visibility="Collapsed" Stroke="Red" StrokeThickness="3" StrokeDashArray="3,1">
</Rectangle>
</Grid>
</Border>
</DockPanel>
I can get the selectionBox to work correctly if I use <Canvas> tags. but that causes the image to not fit inside the <DockPanel>.
c#
public MainWindow()
{
InitializeComponent();
img_Box.MouseLeftButtonDown += img_Box_MouseLeftButtonDown;
img_Box.MouseLeftButtonUp += img_Box_MouseLeftButtonUp;
img_Box.MouseMove += img_Box_MouseMove;
Point mouseDownPos;
}
private void img_Box_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
img_Box.CaptureMouse();
var tt = (TranslateTransform)((TransformGroup)img_Box.RenderTransform).Children.First(tr => tr is TranslateTransform);
double BoxX = (e.GetPosition(img_Box).X / img_Box.ActualWidth) * 1;
double BoxY = (e.GetPosition(img_Box).Y / img_Box.ActualHeight) * 1;
double xValue = Math.Round((BoxX * img_Box.Source.Width), 0);
double yValue = Math.Round((BoxY * img_Box.Source.Height), 0);
StartDrag = new System.Windows.Point(xValue, yValue);
mouseDownPos.X = (int)xValue;
mouseDownPos.Y = (int)yValue;
Canvas.SetLeft(selectionBox, xValue);
Canvas.SetTop(selectionBox, yValue);
selectionBox.Width = 0;
selectionBox.Height = 0;
selectionBox.Visibility = Visibility.Visible;
}
private void img_Box_MouseMove(object sender, MouseEventArgs e)
{
double x = e.GetPosition(img_Box).X;
double y = e.GetPosition(img_Box).Y;
double BoxX = (x / img_Box.ActualWidth) * 1;
double BoxY = (y / img_Box.ActualHeight) * 1;
double xValue = Math.Round((BoxX * img_Box.Source.Width), 0);
double yValue = Math.Round((BoxY * img_Box.Source.Height), 0);
if (mouseDownPos.X < xValue)
{
Canvas.SetLeft(selectionBox, mouseDownPos.X);
selectionBox.Width = xValue - mouseDownPos.X;
}
else
{
Canvas.SetLeft(selectionBox, xValue);
selectionBox.Width = mouseDownPos.X - xValue;
}
if (mouseDownPos.Y < yValue)
{
Canvas.SetTop(selectionBox, mouseDownPos.Y);
selectionBox.Height = yValue - mouseDownPos.Y;
}
else
{
Canvas.SetTop(selectionBox, yValue);
selectionBox.Height = mouseDownPos.Y - yValue;
}
}
Not sure if I fully understand what exactly you are trying to accomplish here but if you just need a border around that text and not to allow the user to move it around with the mouse, set the image to be the background of the Grid and then partition the Grid so that one of the grid cells is directly above that text you want to place the border around. Place the border within that cell and If all the bill images are exactly the same size and have the text in exactly the same location it will always be directly over that text as long as you do not allow users to resize the image... If you want the scrolling just put the entire grid within the ScrollViewer control.
Something like this:
<Grid>
<Grid.Background>
<VisualBrush TileMode="None" >
<VisualBrush.Visual>
<Image Source="{Binding ImageSource}"/>
</VisualBrush.Visual>
</VisualBrush>
</Grid.Background>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/> //Distance from the left edge of the image to the right edge of the border around the "Final Bill" text.
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="150"/> //Distance from the top of the image to the top of the desired location of the border around the "Final Bill" text.
<RowDefinition Height="50"/> //Desired height of the border around the "Final Bill" text.
</Grid.RowDefinitions>
<Border Grid.Column="0" Grid.Row="1" BorderThickness="1"/>
</Grid>
(Edit) i have an image in tabItem1. when i resize window(dragging by corner or maximize button) the image also resize and occupy whole grid. i added width and height on image and the resisng stopped default to actual image width & height in pixels.
Do i have to apply width and height to prevent resising of control whom i don't want to resize on window scale? or is there any property for controls to prevent resizing.
Basically, i'll have some pics which i don't want to be resided, and there will be some text which i want to be resided.
XAML:
<Window x:Class="Engine.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Width="600" Height="600">
<Grid>
<TabControl Grid.RowSpan="2">
<TabItem Header="TabItem1">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Grid x:Name="TGrid1" Background="#FFE5E5E5"/>
</ScrollViewer>
</TabItem>
<TabItem Header="TabItem2">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Grid x:Name="TGrid2" Background="#FFE5E5E5">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
</Grid>
</ScrollViewer>
</TabItem>
</TabControl>
</Grid>
</Window>
Code:
public MainWindow()
{
InitializeComponent();
var bitmapFrame = BitmapFrame.Create(new Uri(#"" + AppDomain.CurrentDomain.BaseDirectory + "Chrysanthemum.jpg"), BitmapCreateOptions.DelayCreation, BitmapCacheOption.None);
var dragDropImage = new Image
{
Source = bitmapFrame, //new BitmapImage(new Uri(#"" + AppDomain.CurrentDomain.BaseDirectory + "Chrysanthemum.jpg")),
Name = "dragDropImage",
Width = bitmapFrame.PixelWidth,
Height = bitmapFrame.PixelHeight
};
TGrid1.Children.Add(dragDropImage);
var rect = new Rectangle
{
Stroke = new SolidColorBrush(Colors.Red),
Fill = new SolidColorBrush(Colors.Black),
Width = 474,
Height = 405
};
Grid.SetRow(rect, 0);
TGrid2.Children.Add(rect);
}
If you set the properties VerticalAlignment (for example to Top) and HorizontalAlignment (for example to Left) of your components image and rect, these controls will be sized according to the content need, instead of the available space in the container.
Is that what you want ?
EDIT : For your image, you should set its property Stretch="None".
See here.
EDIT 2 :
var dragDropImage = new Image
{
Source = bitmapFrame, //new BitmapImage(new Uri(#"" + AppDomain.CurrentDomain.BaseDirectory + "Chrysanthemum.jpg")),
Name = "dragDropImage",
VerticalAlignment = System.Windows.VerticalAlignment.Top,
HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
Stretch = System.Windows.Media.Stretch.None
};
I am having a problem while making a Whack a Mole type game, I am trying to create the images where the mole will appear dynamically, yet there is only a blank white screen where the stack panel is. It is fair to say that I am a noob.
This is my loop where I am trying to create these images:
Image[] ImageArray = new Image[50];
InitializeComponent();
//string ImageName = "Image";
for (int i = 0; i <= 8; i++)
{
Image Image = new Image();
ImageArray[i] = Image;
Image.Name = "Image" + i.ToString();
StackPanel1.Children.Add(ImageArray[i]);
}
//Random Number Generator
Random rnd = new Random();
int num = rnd.Next(1, 9);
//If Random Number is "1" Then Image will display
if (num == 1)
{
ImageSource MoleImage = new BitmapImage(new Uri(ImgNameMole));
ImageArray[1].Source = MoleImage;
}
This is the StackPanel XAML:
<Window x:Name="Window1" x:Class="WhackaMole.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="468.843" Width="666.045" OpacityMask="#FFF70D0D" Icon="mole2.png" Cursor="" >
<Grid OpacityMask="#FF5D1313">
<Image Margin="422,191,-185,-69" Source="mole2.png" Stretch="Fill" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
<TextBlock HorizontalAlignment="Left" Margin="35,31,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="52" Width="595" FontSize="50" FontFamily="SimHei"><Run Language="en-ca" Text="Can You Catch the Mole?"/></TextBlock>
<Button x:Name="NewGameBttn" Content="New Game" HorizontalAlignment="Left" Margin="77,0,0,16" VerticalAlignment="Bottom" Width="139" Height="50" FontSize="25" Click="NewGameBttn_Click"/>
<Button x:Name="CloseBttn" Content="Close" HorizontalAlignment="Left" Margin="245,365,0,0" VerticalAlignment="Top" Width="76" Height="50" FontSize="29" Click="CloseBttn_Click"/>
<StackPanel x:Name="StackPanel1" HorizontalAlignment="Left" Height="231" Margin="35,112,0,0" VerticalAlignment="Top" Width="525"/>
</Grid>
</Window>
As far as I can tell you're creating a new object of type Image but that Image really doesn't have anything to display. You need to set the Source of your Image. Here's an example stolen from MSDN.
Image myImage = new Image();
myImage.Source = new BitmapImage(new Uri("myPicture.jpg", UriKind.RelativeOrAbsolute));
LayoutRoot.Children.Add(myImage);
As townsean pointed out, you should probably create a Style for your Image where you can set common properties such as Height, Width etc.
My guess is that since you are adding the items to a StackPanel, the StackPanel is choosing the default mins for height and width on the image (which is probably 0), and that is why you are not seeing anything.
Try setting a value for the Height and Width of the image and see if anything shows.
Also, as Tejas pointed out you are not setting the image source.
EDIT: Set the Image width like this:
Image myImage = new Image();
myImage.Width = 25;
myImage.Height = 25;
Do something like this in your for-loop where you first create the images.