I try to animate multiple (different sized) images in one Grid control but only the biggest one is animated. The targeted property is "Offset.x".
var container = new Grid();
var compositor = ElementCompositionPreview.GetElementVisual(container).Compositor;
var containerVisual = compositor.CreateContainerVisual();
// ------
// CLOUDS
// ------
var cloudImage1 = CreateCloudImage(60);
var cloudVisual1 = ElementCompositionPreview.GetElementVisual(cloudImage1);
var cloudImage2 = CreateCloudImage(70);
var cloudVisual2 = ElementCompositionPreview.GetElementVisual(cloudImage2);
var cloudImage3 = CreateCloudImage(50);
var cloudVisual3 = ElementCompositionPreview.GetElementVisual(cloudImage3);
container.Children.Add(cloudImage1);
container.Children.Add(cloudImage2);
container.Children.Add(cloudImage3);
containerVisual.Children.InsertAtTop(cloudVisual1);
containerVisual.Children.InsertAtTop(cloudVisual2);
containerVisual.Children.InsertAtTop(cloudVisual3);
// ----------
// ANIMATIONS
// ----------
var offsetAnimation = CreateOffsetAnimation(compositor, 50, 6);
cloudVisual1.StartAnimation("Offset.x", offsetAnimation);
offsetAnimation.InsertKeyFrame(1f, -60);
cloudVisual2.StartAnimation("Offset.x", offsetAnimation); // doesn't work
ElementCompositionPreview.SetElementChildVisual(container, containerVisual);
return container;
Helpers methods:
static ScalarKeyFrameAnimation CreateOffsetAnimation(Compositor compositor, float endKeyFrame, double duration) {
var animation = compositor.CreateScalarKeyFrameAnimation();
animation.InsertKeyFrame(0f, 0);
animation.InsertKeyFrame(1f, endKeyFrame);
animation.IterationBehavior = AnimationIterationBehavior.Forever;
animation.Direction = AnimationDirection.Alternate;
animation.Duration = TimeSpan.FromSeconds(duration);
return animation;
}
static Image CreateCloudImage(double size) {
var cloudBitmapImage = new BitmapImage(new Uri("ms-appx:///Assets/Icons/cloudy.png"));
var cloudImageControl = new Image() {
Source = cloudBitmapImage,
Height = size,
Width = size,
};
return cloudImageControl;
}
Note that if I make the 2nd image the biggest, it becomes the one which is animated.
Any idea on how to solve this ?
Thanks in advance.
Short answer: use a Canvas control to hold images.
Full answer: I found the solution: the culprit was using the Grid control as a container for hosting my images. I think that somehow (maybe due to the center horizontal alignment set on its parent - not visible in the code showed) the Grid container was adding margins to my images which resulted in weird behaviors, as described in the question.
To solve this, I added a Canvas control to hold my images and added this Canvas as a child of the Grid container.
var container = new Grid();
var compositor = ElementCompositionPreview.GetElementVisual(container).Compositor;
var containerVisual = compositor.CreateContainerVisual();
var canvas = new Canvas();
// ------
// CLOUDS
// ------
var cloudImage1 = CreateCloudImage(60);
var cloudVisual1 = ElementCompositionPreview.GetElementVisual(cloudImage1);
var cloudImage2 = CreateCloudImage(70);
var cloudVisual2 = ElementCompositionPreview.GetElementVisual(cloudImage2);
var cloudImage3 = CreateCloudImage(50);
var cloudVisual3 = ElementCompositionPreview.GetElementVisual(cloudImage3);
canvas.Children.Add(cloudImage1);
canvas.Children.Add(cloudImage2);
canvas.Children.Add(cloudImage3);
containerVisual.Children.InsertAtTop(cloudVisual1);
containerVisual.Children.InsertAtTop(cloudVisual2);
containerVisual.Children.InsertAtTop(cloudVisual3);
// ----------
// ANIMATIONS
// ----------
var offsetAnimation = CreateOffsetAnimation(compositor, 50, 6);
cloudVisual1.StartAnimation("Offset.x", offsetAnimation);
offsetAnimation.InsertKeyFrame(1f, -60);
cloudVisual2.StartAnimation("Offset.x", offsetAnimation); // work
offsetAnimation.InsertKeyFrame(1f, 100);
cloudVisual3.StartAnimation("Offset.x", offsetAnimation); // work
ElementCompositionPreview.SetElementChildVisual(canvas, containerVisual);
container.Children.Add(canvas);
return container;
(Replacing the Grid container with a Canvas container should work too).
Related
What I'm trying to do is writing the Xamarin Android code for the attached image (Which is Xamarin iOS)
As we can see in the attached Image, we have a UITableView with floor numbers (1, 2 and 3).
How can I add a ListView in Android using C# (Not XML) to have the same result?
Here's a code snippet of the code I'm using.
But the problem is that my ListView is always under the SearchBox which is not what I want. I want the ListView to be at the bottom of my screen.
private void CreateLayout()
{
// Create a new vertical layout for the app
var layout = new LinearLayout(this) { Orientation = Orientation.Vertical };
// Search Bar
_mySearchBox = new AutoCompleteTextView(this) { Hint = "Search rooms or people..." };
layout.AddView(_mySearchBox);
//Auto Complete Drop Down List View
_searchListView = new ListView(this);
layout.AddView(_searchListView);
// Progress bar
_myProgressBar = new ProgressBar(this) { Indeterminate = true, Visibility = ViewStates.Gone };
layout.AddView(_myProgressBar);
// Floors List View
_floorsTableView = new ListView(this);
_floorsTableView.LayoutParameters = new ViewGroup.LayoutParams(100, 150);
_floorsTableView.TextAlignment = TextAlignment.Center;
var adap = new ArrayAdapter(this, Resource.Layout.SimpleSpinnerItem, new List<string>() { "1", "2", "3" });
_floorsTableView.Adapter = adap;
_floorsTableView.Visibility = ViewStates.Visible;
layout.AddView(_floorsTableView);
// Add a map view to the layout
_myMapView = new MapView(this);
layout.AddView(_myMapView);
// Show the layout in the app
SetContentView(layout);
}
I suggest you switch to a RelativeLayout instead of using a LinearLayout to host your views. LinearLayout inherently wants to position stuff according to its orientation, while RelativeLayout gives you more freedom and power to arrange views.
Also keep in mind that the order you add views to your host container matters. So in your case I would add the ListView last. This way you will ensure that the list draws on top of anything else.
Also you need to fully specify LayoutParams for each view!
var root = new RelativeLayout(this);
_mySearchBox = new AutoCompleteTextView(this) { Hint = "Search rooms or people..." };
_myMapView = new MapView(this)
{
Id = View.GenerateViewId()
};
_floorsTableView = new ListView(this)
{
Id = View.GenerateViewId()
};
var searchBoxParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
searchBoxParams.AddRule(LayoutRules.AlignParentTop);
var mapParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent);
var listParams = new RelativeLayout.LayoutParams(100, 150);
listParams.AddRule(LayoutRules.AlignParentStart);
listParams.AddRule(LayoutRules.AlignParentBottom);
listParams.SetMargins(16, 0, 0, 16);
root.AddView(_myMapView, mapParams);
root.AddView(_mySearchBox, searchBoxParams);
root.AddView(_floorsTableView, listParams);
SetContentView(root, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent));
You will also want to convert the dimensions to px from dp:
private int DpToPx(int dp)
{
return (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, dp, Resources.DisplayMetrics);
}
This way your dimensions will scale according to display density.
You should use RelativeLayout to put an object over another object, then use RelativeLayout.LayoutParams to specify where you want it. So you need:
var layout = new RelativeLayout(this);
And then using LayoutRules.AlignParentBottom and LayoutRules.AlignParentLeft:
// Floors List View
_floorsTableView = new ListView(this);
// Create parameters for the listview
RelativeLayout.LayoutParams parameters = new RelativeLayout.LayoutParams(100, 150);
parameters.AddRule(LayoutRules.AlignParentBottom);
parameters.AddRule(LayoutRules.AlignParentLeft);
_floorsTableView.TextAlignment = TextAlignment.Center;
var adap = new ArrayAdapter(this, Resource.Layout.SimpleSpinnerItem, new List<string>() { "1", "2", "3" });
_floorsTableView.Adapter = adap;
_floorsTableView.Visibility = ViewStates.Visible;
// Add the listview to the layout with parameters specified
layout.AddView(_floorsTableView, parameters);
I didn't test it so you may have to play with width and height layout parameters or such.
Currently i am working on image processing project, where i have one review screen in which i set the image on image container, and on top of the image, all four corners has meta data, which are fixed. Means while i zoom in/out the image, the top content will remain at the fixed position not move. This is my requirement.
Now i have set all content dynamically using the stack panel and all meta data will stay on fixed position except the bottom right position, which will be moved while image is zoomed in/out.
below is the reference screen shot where red mark shows the metadata will moved and hide at right side.
Here is the code for bottom right content
public async Task<ScrollViewer> CreateNewScrollViewer(ImageInfo item)
{
ScrollViewer scrollViewerObj = new ScrollViewer();
byte[] rawData;
try
{
//this will update the values of any older sharpness data to 5
if (item.AnnotationSchemaVersion != null && item.AnnotationSchemaVersion.Equals("1.0", StringComparison.InvariantCulture))
{
item.AdjustmentValue.Sharpness = item.BytePerPixel == 3 ? _samSettingsManager.GetTrueColorSharpnessDefaultValue() : _samSettingsManager.GetSingleColorSharpnessDefaultValue();
var saveSharpness = new Task(() => this.UpdateImageAnalysis(item));
saveSharpness.Start();
}
scrollViewerObj.SetValue(AutomationProperties.AutomationIdProperty, "ReviewImageDetailView_ScrollViewer");
scrollViewerObj.SetValue(AutomationProperties.NameProperty, "ReviewImageDetailView_ScrollViewer");
scrollViewerObj.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
scrollViewerObj.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
scrollViewerObj.Margin = new Thickness(5, 5, 5, 5);
scrollViewerObj.Focusable = true;
scrollViewerObj.SizeChanged += new SizeChangedEventHandler(ScrollViewerSizeChanged);
Point? fixationTarget = null;
Point? foveaXY = null;
Point? onhXY = null;
FixationType fixationMode = FixationType.Internal;
bool performDistortionCorrection = false;
// Provide fixation values only for WF and Non-External(Non-AnteriorSegment) scans, as distortion correction shall only be applied to WF and Non-External(Non-AnteriorSegment) images.
// All composite UWF/Montage/Auto-Montage images will be distortion corrected (Montage algorithm generates distortion corrected image)
if (Convert.ToInt32(item.FOV, CultureInfo.InvariantCulture) == FOVConstants.Widefield &&
item.ExamMode != ExamModes.AnteriorSegment && SAMConstants.SAMExamSourceUID == item.ExamSourceUID)
{
fixationTarget = item.FixationXY;
foveaXY = item.FoveaXY;
onhXY = item.ONHXY;
fixationMode = item.FixationMode;
performDistortionCorrection = true;
}
//bool isOD = item.Laterality == "OD" ? true : false;
string imageCacheFilePath = _imageCacheFilePath;
string imageFileName = System.IO.Path.GetFileName(item.ImagePath);
//creates the image cache folder if it doesn't exist
if (!Directory.Exists(imageCacheFilePath))
Directory.CreateDirectory(imageCacheFilePath);
ImageContainer imageObj = new ImageContainer(_pixelBufferSize);
await Task.Run(() =>
{
imageObj.Initialize(item.ImagePath, item.ImageCompressionType,
item.ImageWidth, item.ImageHeight, item.BytePerPixel, item.ExamSourceUID, item.Laterality, imageCacheFilePath, _pixelBufferSize, fixationTarget,
foveaXY, item.ProjectedXMin, item.ProjectedYMax, item.ProjectedXMax, item.ProjectedYMin, performDistortionCorrection,
onhXY, fixationMode, item.ONHIdentificationMode);
});
imageObj.InitializeZoomValues(((int)ActualHeight - 40) / 4, ((int)ActualWidth - 40) / 4);
PyramidTools.PyramidImageProcessing processImage = new PyramidTools.PyramidImageProcessing();
//Sets up the pyramid
if (!System.IO.File.Exists(imageCacheFilePath + imageFileName + ExtensionConstants.Raw) || (!System.IO.File.Exists(imageCacheFilePath + imageFileName + ExtensionConstants.Text) && SAMConstants.SAMExamSourceUID == imageObj.ExamSourceUID))
{
rawData = imageObj.ImageDataObj.GetData();
if (rawData != null)
{
processImage.CreatePyramidForGivenImage(rawData, item.BytePerPixel, (int)imageObj.ImageZoom.LowestZoomPercentage, imageFileName, imageObj.ImageDataObj.Width, imageObj.ImageDataObj.Height, imageCacheFilePath);
}
}
else if (!processImage.IsPyramidCreated(imageCacheFilePath + imageFileName, (int)imageObj.ImageZoom.LowestZoomPercentage))
{
rawData = File.ReadAllBytes(imageCacheFilePath + imageFileName + ExtensionConstants.Raw);
if (rawData != null)
{
processImage.CreatePyramidForGivenImage(rawData, item.BytePerPixel, (int)imageObj.ImageZoom.LowestZoomPercentage, imageFileName, imageObj.ImageDataObj.Width, imageObj.ImageDataObj.Height, imageCacheFilePath);
}
}
// For image sharpness
imageObj.ImageProcessing = imageProcessing;
imageObj.TrueColorSharpnessRadius = _trueColorSharpnessRadius;
imageObj.TrueColorSharpnessMinAmount = _trueColorSharpnessMinAmount;
imageObj.TrueColorSharpnessMaxAmount = _trueColorSharpnessMaxAmount;
imageObj.TrueColorSharpnessResizeFactor = _trueColorSharpnessResizeFactor;
imageObj.SingleColorSharpnessRadius = _singleColorSharpnessRadius;
imageObj.SingleColorSharpnessMinAmount = _singleColorSharpnessMinAmount;
imageObj.SingleColorSharpnessMaxAmount = _singleColorSharpnessMaxAmount;
imageObj.SingleColorSharpnessResizeFactor = _singleColorSharpnessResizeFactor;
imageObj.TrueColorSharpnessFactor = _trueColorSharpnessFactor;
imageObj.SingleColorSharpnessFactor = _singleColorSharpnessFactor;
imageObj.IsConstituteImage = item.IsConstituteImage;
imageObj.FOV = item.FOV;
imageObj.SelectedChannel = ChannelTypes.TrueColorChannel;
imageObj.TonalOptimizedValues = new Tonal(128, 128, 128);
imageObj.SetValue(AutomationProperties.AutomationIdProperty, "ReviewImageDetailView_ImageContainer");
imageObj.SetValue(AutomationProperties.NameProperty, "ReviewImageDetailView_ImageContainer");
BitmapImage logo = new BitmapImage();
logo.BeginInit();
logo.UriSource = new Uri("pack://application:,,,/SAMProduction.FundusImageDisplay;component/Images/RotateBlue.png");
logo.EndInit();
imageObj.ImageRotationShow = new System.Windows.Controls.Image();
imageObj.ImageRotationShow.Source = logo;
imageObj.ImageRotationShow.SetValue(AutomationProperties.AutomationIdProperty, "ReviewImageDetailView_180DegreeIcon");
imageObj.ImageRotationShow.SetValue(AutomationProperties.NameProperty, "ReviewImageDetailView_180DegreeIcon");
//imageObj.ImageRotationShow.SetResourceReference(Canvas.BackgroundProperty, "180DegreeIcon");
imageObj.ImageRotationShow.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
imageObj.ImageRotationShow.VerticalAlignment = System.Windows.VerticalAlignment.Top;
imageObj.ImageRotationShow.Visibility = System.Windows.Visibility.Collapsed;
imageObj.ImageRotationShow.Width = 30;
imageObj.ImageRotationShow.Height = 30;
imageObj.ImageRotationShow.Margin = new Thickness(0, 10, 0, 0);
imageObj.ImageFrameNoMessage = item.ImageFrameNoMessage;
Style textBlockStyle = this.TryFindResource("TextWhite16") as Style;
#region Top Left Panel Information
StackPanel topLeftPanelInfo = new StackPanel();
topLeftPanelInfo.Width = 160;
topLeftPanelInfo.Name = "TopLeftPanel";
topLeftPanelInfo.Uid = "TopLeftPanel";
topLeftPanelInfo.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
topLeftPanelInfo.VerticalAlignment = System.Windows.VerticalAlignment.Top;
topLeftPanelInfo.Margin = new Thickness(10, 5, 0, 0);
UpdateTopLeftPanel(item, imageObj, topLeftPanelInfo, textBlockStyle);
#endregion
#region Bottom Left Panel Information
StackPanel bottomLeftPanelInfo = new StackPanel();
bottomLeftPanelInfo.Name = "BottomLeftPanel";
bottomLeftPanelInfo.Uid = "BottomLeftPanel";
bottomLeftPanelInfo.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
bottomLeftPanelInfo.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
bottomLeftPanelInfo.Margin = new Thickness(10, 0, 0, 5);
UpdateBottomLeftPanel(item, imageObj, bottomLeftPanelInfo, textBlockStyle);
#endregion
#region Bottom Right Panel Information
StackPanel bottomRightPanelInfo = new StackPanel();
bottomRightPanelInfo.Name = "BottomRightPanel";
bottomRightPanelInfo.Uid = "BottomRightPanel";
bottomRightPanelInfo.SetValue(AutomationProperties.AutomationIdProperty, "ReviewImageDetailView_BottomRightPanelInfo");
bottomRightPanelInfo.SetValue(AutomationProperties.NameProperty, "ReviewImageDetailView_BottomRightPanelInfo");
bottomRightPanelInfo.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
bottomRightPanelInfo.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
bottomRightPanelInfo.Margin = new Thickness(0, 0, 10, 5);
UpdateBottomRightPanel(item, imageObj, bottomRightPanelInfo, textBlockStyle);
#endregion
#region Top Right Panel Information
StackPanel topRightPanelInfo = new StackPanel();
topRightPanelInfo.Name = "TopRightPanel";
topRightPanelInfo.Uid = "TopRightPanel";
topRightPanelInfo.SetValue(AutomationProperties.AutomationIdProperty, "ReviewImageDetailView_TopRightPanelInfo");
topRightPanelInfo.SetValue(AutomationProperties.NameProperty, "ReviewImageDetailView_TopRightPanelInfo");
topRightPanelInfo.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
topRightPanelInfo.VerticalAlignment = System.Windows.VerticalAlignment.Top;
topRightPanelInfo.Margin = new Thickness(0, 5, 10, 0);
UpdateTopRightPanel(item, imageObj, topRightPanelInfo, textBlockStyle);
#endregion
Grid gridObj = new Grid() { ClipToBounds = true };//
gridObj.SetValue(AutomationProperties.AutomationIdProperty, "ReviewImageDetailView_Grid");
gridObj.SetValue(AutomationProperties.NameProperty, "ReviewImageDetailView_Grid");
gridObj.Children.Add(imageObj);
if (topLeftPanelInfo != null)
{
gridObj.Children.Add(topLeftPanelInfo);
}
if (bottomLeftPanelInfo != null)
{
gridObj.Children.Add(bottomLeftPanelInfo);
}
if (topRightPanelInfo != null)
{
gridObj.Children.Add(topRightPanelInfo);
}
if (bottomRightPanelInfo != null)
{
gridObj.Children.Add(bottomRightPanelInfo);
}
gridObj.Children.Add(imageObj.SelectedBorder);
gridObj.Children.Add(imageObj.ImageRotationShow);
gridObj.Children.Add(imageObj.OverlayGrid);
imageObj.OverlayGrid.MouseLeftButtonUp += OverlayGrid_MouseLeftButtonUp;
imageObj.OverlayGrid.MouseMove += OverlayGrid_MouseMove;
imageObj.OverlayGrid.MouseLeftButtonDown += OverlayGrid_MouseLeftButtonDown;
imageObj.OverlayGrid.PreviewMouseRightButtonDown += OverlayGrid_PreviewMouseRightButtonDown;
imageObj.OverlayGrid.PreviewMouseRightButtonUp += OverlayGrid_PreviewMouseRightButtonUp;
scrollViewerObj.Content = gridObj;
// This binding required to align image properly when it is loading.
Binding HeightBinding = new Binding();
RelativeSource relativeheightSource = new RelativeSource();
relativeheightSource.Mode = RelativeSourceMode.FindAncestor;
relativeheightSource.AncestorType = typeof(ScrollViewer);
HeightBinding.RelativeSource = relativeheightSource;
HeightBinding.Path = new PropertyPath("ActualHeight");
HeightBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
HeightBinding.Mode = BindingMode.OneWay;
imageObj.SetBinding(System.Windows.Controls.Image.HeightProperty, HeightBinding);
Binding WidthBinding = new Binding();
RelativeSource relativeWidthSource = new RelativeSource();
relativeWidthSource.Mode = RelativeSourceMode.FindAncestor;
relativeWidthSource.AncestorType = typeof(ScrollViewer);
WidthBinding.RelativeSource = relativeWidthSource;
WidthBinding.Path = new PropertyPath("ActualWidth");
WidthBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
WidthBinding.Mode = BindingMode.OneWay;
imageObj.SetBinding(System.Windows.Controls.Image.WidthProperty, WidthBinding);
imageObj.ImageSourceChanged += this.ImageObj_ImageSourceChanged;
imageObj.ZoomValueChanged += this.ImageObj_ZoomValueChanged;
scrollViewerObj.AllowDrop = true;
scrollViewerObj.Drop += ScrollViewer_Drop;
imageObj.ContainerTonalValueChanged += ImageObj_ContainerTonalValueChanged;
// Previously MouseLeftButtonDown event was used.
// Change set no 141851 has change code of CreateNewScrollViewer(). He set Scrollviewer’s Focable property to true.
// It is required to set focusable true for that change set.
// In ScrollViewer's original code (.net code) it is handling event (e.Handled = true) if it can get focus.
// So side effect of 141851 change set is MouseLeftButtonDown event of scrollviewer do not get call when mouse down on it.
// So it misbehaves.
// So here PreviewMouseLeftButtonDown event used.
scrollViewerObj.PreviewMouseLeftButtonDown += ScrollViewerObj_PreviewMouseLeftButtonDown;
scrollViewerObj.MouseLeftButtonUp += this.ScrollViewerObj_MouseLeftButtonUp;
scrollViewerObj.PreviewMouseWheel += ScrollViewerObj_PreviewMouseWheel;
// No need to handle this event
//imageObj.SizeChanged += this.ImageObj_SizeChanged;
imageObj.MouseMove += this.ImageObj_MouseMove;
imageObj.MouseLeftButtonDown += this.ImageObj_MouseLeftButtonDown;
imageObj.MouseLeftButtonUp += this.ImageObj_MouseLeftButtonUp;
gridObj.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
gridObj.VerticalAlignment = System.Windows.VerticalAlignment.Center;
//It is not necessary to initalize the data
imageObj.ImageID = item.ImageId;
//imageObj.ImagePath = item.ImagePath;
if (imageObj.ExamSourceUID == SAMConstants.SAMExamSourceUID &&
imageObj.ExamMode != ExamModes.AnteriorSegment)
imageObj.OverlayGrid.IsHitTestVisible = IsOverlayGridEnable;
else
imageObj.OverlayGrid.IsHitTestVisible = false;
// imageObj.OverlayGrid.IsHitTestVisible = IsOverlayGridEnable;
//imageObj.ImageSource = imageObj.ImageDataObj;
scrollViewerObj.ContextMenu = CreateContextMenu(scrollViewerObj, imageObj); // set contextmenu
}
catch (Exception ex)
{
_services.Logger.Log(LogLevel.Error, "SAMProduction.FundusImageDisplay", "ImageEditViewerBase", "CreateNewScrollViewer: Error occurred while creating new scrollviewer. : " + ex);
}
finally
{
rawData = null;
}
return scrollViewerObj;
}
Please, let me help out to resolve the moved content on top layer of image, if any one can do. Thanks in Advance.
I find creating views in code very unreadable, so this is how to achieve this in XAML:
<Grid>
<Image .../> // or whatever custom control you use to allow zoom
<StackPanel Name="TopLeft HorizontalAligment="Left" VerticalAligment="Top">
<contente: labels etc ../>
</StackPanel>
...
<StackPanel Name="BottomRight" HorizontalAligment="Right" VerticalAligment="Bottom">
<contente: labels etc ../>
</StackPanel>
</Grid>
The trick is to wrap everything that you want to be in the same place and/or overlay in a Grid. If the StackPanels are after an Image in Grid content, their z-index will be higher and they will be displayed on top of the image.
The Image control by default will be streched to the whole grid, so you should manipulate the zoom with its content, not its size. If that's problematic, just wrap the Image control with another panel, or at best, custom UserControl and work out the size issues there.
Thanks to the Grid, the StackPanels will anchored to the corners, no matter the size and shape of the grid.
Also, you used tag MVVM and your code is almost textbook non-MVVM.
Maybe this will help you rewrite your code.
Hi I am looking to print a StackPanel that contains a listbox which can contain an infinite number of items and therefore needs to print over multiple pages. I found this code online and it works fine.
public static FixedDocument GetFixedDocument(FrameworkElement toPrint, PrintDialog printDialog)
{
if (printDialog == null)
{
printDialog = new PrintDialog();
}
var capabilities = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket);
var pageSize = new Size(printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight);
var visibleSize = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
var fixedDoc = new FixedDocument();
//If the toPrint visual is not displayed on screen we neeed to measure and arrange it
toPrint.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
toPrint.Arrange(new Rect(new Point(0, 0), toPrint.DesiredSize));
//
var size = toPrint.DesiredSize;
//Will assume for simplicity the control fits horizontally on the page
double yOffset = 0;
while (yOffset < size.Height)
{
var vb = new VisualBrush(toPrint)
{
Stretch = Stretch.None,
AlignmentX = AlignmentX.Left,
AlignmentY = AlignmentY.Top,
ViewboxUnits = BrushMappingMode.Absolute,
TileMode = TileMode.None,
Viewbox = new Rect(0, yOffset, visibleSize.Width, visibleSize.Height)
};
var pageContent = new PageContent();
var page = new FixedPage();
((IAddChild)pageContent).AddChild(page);
fixedDoc.Pages.Add(pageContent);
page.Width = pageSize.Width;
page.Height = pageSize.Height;
var canvas = new Canvas();
FixedPage.SetLeft(canvas, capabilities.PageImageableArea.OriginWidth);
FixedPage.SetTop(canvas, capabilities.PageImageableArea.OriginHeight);
canvas.Width = visibleSize.Width;
canvas.Height = visibleSize.Height;
canvas.Background = vb;
page.Children.Add(canvas);
yOffset += visibleSize.Height;
}
return fixedDoc;
}
However this causes certain items of a listbox to be cut off at the bottom of a page and continued on the next page (as shown below). Is it possible to modify this code in any way to determine the size of the page and if the current listboxitem does not fit onto this page that it starts on the next page? Quite new to all this so any help would be greatly appreciated.
I had a similiar task once and came up with this code, which uses a 'dummy' renderer to determine the height of the element up front and then either adds it to the current page or creates a new one. For sure, that's not a very beautiful solution, but it did the job at the time. Maybe you can take sth. away from it.
Size A4Size = new Size(793.92, 1122.24);
Size InfiniteSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
var pages = new List<FrameworkElement>();
int pageNumber = 0;
var printDate = DateTime.Now;
var size = A4Size;
var currentPage = new Report(size, printDate);
currentPage.Render();
var listElements = new Queue<ElementsToPrint>(...);
var dummyRenderer = new Viewbox();
dummyRenderer.Child = currentPage;
dummyRenderer.Measure(InfiniteSize);
dummyRenderer.Arrange(new Rect(dummyRenderer.DesiredSize));
dummyRenderer.UpdateLayout();
var template = (DataTemplate)View.FindResource("ItemTemplate");
dummyRenderer.Child = null;
var availableHeight = currentPage.View.ActualHeight;
while (listElements.Count > 0)
{
var elementToRender = listElements.Dequeue();
dummyRenderer.Child = new ListViewItem()
{
Content = elementToRender,
ContentTemplate = template,
Foreground = Brushes.Black
};
dummyRenderer.Measure(InfiniteSize);
dummyRenderer.Arrange(new Rect(dummyRenderer.DesiredSize));
dummyRenderer.UpdateLayout();
var renderedItem = (ListViewItem)dummyRenderer.Child;
dummyRenderer.Child = null;
var willItFit = availableHeight > renderedItem.ActualHeight;
if (willItFit)
{
currentPage.DataListView.Items.Add(renderedItem);
availableHeight -= renderedItem.ActualHeight;
}
else
{
dummyRenderer.Child = currentPage;
dummyRenderer.Measure(InfiniteSize);
dummyRenderer.Arrange(new Rect(dummyRenderer.DesiredSize));
dummyRenderer.UpdateLayout();
dummyRenderer.Child = null;
pages.Add(currentPage);
// Set up a new Page
pageNumber++;
currentPage = new DiaryReport(size,pageNumber,printDate,anonymous);
dummyRenderer.Child = currentPage;
dummyRenderer.Measure(InfiniteSize);
dummyRenderer.Arrange(new Rect(dummyRenderer.DesiredSize));
dummyRenderer.UpdateLayout();
dummyRenderer.Child = null;
availableHeight = currentPage.DataListView.ActualHeight;
currentPage.DataListView.Items.Add(renderedItem);
availableHeight -= renderedItem.ActualHeight;
}
I'm working on a mini-game where I need to make images go from their initial position to another using a translation transformation.
The problem is: I don't know how to proceed to apply the translation.
So here's the code used to generate my images.
Image myImage1 = new Image();
myImage1.Source = new BitmapImage(new Uri("/Images/image1.png", UriKind.Relative));
myImage1.Name = "image" + index++.ToString();
myImage1.Tap += myImage_Tap;
Canvas.SetLeft(image, 200);
Canvas.SetTop(image, 600);
gameArea.Children.Add(image);
Thanks for your time.
You have two choices to move your image around. The first is using a Canvas like your code shows, but you have to make sure your element is actually within a Canvas. Is your "gameArea" a Canvas? If it's not, your code won't work. The other option is to use Transforms.
var myImage1 = new Image
{
Source = new BitmapImage(new Uri("/Images/image1.png", UriKind.Relative)),
Name = "image" + index++.ToString(),
Tap += myImage_Tap,
RenderTransform = new TranslateTransform
{
X = 200,
Y = 600
}
};
gameArea.Children.Add(image);
Now gameArea can be any type of Panel and it will work.
Note that when using a Canvas, your Top and Left will be from the upper left corner of the Canvas. When using a Transform, your X and Y will be relative to where the element would have originally be drawn.
UPDATE -- Helper class to do simple animations using a Canvas
public sealed class ElementAnimator
{
private readonly UIElement _element;
public ElementAnimator(UIElement element)
{
if (null == element)
{
throw new ArgumentNullException("element", "Element can't be null.");
}
_element = element;
}
public void AnimateToPoint(Point point, int durationInMilliseconds = 300)
{
var duration = new Duration(TimeSpan.FromMilliseconds(durationInMilliseconds));
var easing = new BackEase
{
Amplitude = .3
};
var sb = new Storyboard
{
Duration = duration
};
var animateLeft = new DoubleAnimation
{
From = Canvas.GetLeft(_element),
To = point.X,
Duration = duration,
EasingFunction = easing,
};
var animateTop = new DoubleAnimation
{
From = Canvas.GetTop(_element),
To = point.Y,
Duration = duration,
EasingFunction = easing,
};
Storyboard.SetTargetProperty(animateLeft, "(Canvas.Left)");
Storyboard.SetTarget(animateLeft, _element);
Storyboard.SetTargetProperty(animateTop, "(Canvas.Top)");
Storyboard.SetTarget(animateTop, _element);
sb.Children.Add(animateLeft);
sb.Children.Add(animateTop);
sb.Begin();
}
}
So here's what I did with your code, I took just this part and made it a function:
public void AnimateToPoint(UIElement image, Point point, int durationInMilliseconds = 300)
{
var duration = new Duration(TimeSpan.FromMilliseconds(durationInMilliseconds));
var sb = new Storyboard
{
Duration = duration
};
var animateTop = new DoubleAnimation
{
From = Canvas.GetTop(image),
To = point.Y,
Duration = duration
};
Storyboard.SetTargetProperty(animateTop, new PropertyPath("Canvas.Top")); // You can see that I made some change here because I had an error with what you gave me
Storyboard.SetTarget(animateTop, image);
sb.Children.Add(animateTop);
sb.Begin();
}
And then I made the call with:
Point myPoint = new Point(leftpos, 300); // leftpos is a variable generated randomly
AnimateToPoint(myImage, myPoint);
So now there is still a single error, and it's in the instruction "sb.Begin;".
And it says: Cannot resolve TargetProperty Canvas.Top on specified object.
I reaylly don't know how to proceed.
Thanks for your previous answer!
I have drag'n'drop support in my application. When I start dragging a certain item, I create the dragging visual from code. The code below works, but I want to set the width and height using the style instead of hardcoding it like below. How?
private void OnDragInitialize(object sender, DragInitializeEventArgs args)
{
args.AllowedEffects = DragDropEffects.All;
var shape = new MyShape();
// TODO: How do I let the 'DragShapeStyle' style apply the dimensions?
var shapeSize = new Size(180, 80);
var dropInfo = new DiagramDropInfo(shapeSize, SerializeItems(
new List<IDiagramItem> { shape }));
args.Data = dropInfo;
args.DragVisualOffset = new Point(
args.RelativeStartPoint.X - (shapeSize.Width / 2),
args.RelativeStartPoint.Y - (shapeSize.Height / 2));
var dragShape = new DragShape()
{
DataContext = new ShapeData()
{
Data = new MyData()
}
};
dragShape.SetResourceReference(DragShape.StyleProperty, "DragShapeStyle");
args.DragVisual = new ContentControl() { Content = dragShape };
}
My DragShapeStyle style paints a grid, with its size set using properties of MyData and some other logic. I want to apply this logic to my dragged Visual.