How do I print WebView content C# UWP Win 10 - c#

I've searched how to print a simple WebView as :
<WebView x:Name="MyWebView" Source="http://www.stackoverflow.com" />
I tried many things as :
How do I print WebView content in a Windows Store App?
This solution is sadly not updated for Windows 10 UWP apps, but, I converted it so the obsoletes functions would work that leads me to another problem.
To print, I used some classes from the sample (Windows-universal-samples/Samples/Printing/cs/) because I need the preview.
I put the example given in the above mentioned question as :
<RichTextBlock
x:Name="TextContent"
Grid.Row="1"
Grid.ColumnSpan="2"
Width="595"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Foreground="Black"
IsTextSelectionEnabled="True"
OverflowContentTarget="{Binding ElementName=FirstLinkedContainer}">
<Paragraph>
<InlineUIContainer> [The question XAML]
The overflow is not managed, and so the WebView is seen like this :
Note: I'm new to XAML language and the logic behind this.
I would like an update on how to do this and if this is possible ?
EDIT:
Here's the code behind of my PageToPrint.xaml.cs :
using System;
using System.Collections.Generic;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace TestPrint
{
/// <summary>
/// Page content to send to the printer
/// </summary>
public sealed partial class PageToPrint : Page
{
public RichTextBlock TextContentBlock { get; set; }
public PageToPrint()
{
this.InitializeComponent();
TextContentBlock = TextContent;
MyWebView.LoadCompleted += MyWebView_LoadCompletedAsync;
}
async void MyWebView_LoadCompletedAsync(object sender, NavigationEventArgs e)
{
MyWebViewRectangle.Fill = await GetWebViewBrushAsync(MyWebView);
MyPrintPages.ItemsSource = await GetWebPagesAsync(MyWebView, new Windows.Foundation.Size(100d, 150d));
MyWebView.Visibility = Windows.UI.Xaml.Visibility.Visible;
}
async System.Threading.Tasks.Task<WebViewBrush> GetWebViewBrushAsync(WebView webView)
{
// resize width to content
var _OriginalWidth = webView.Width;
var _WidthString = await webView.InvokeScriptAsync("eval",
new[] { "document.body.scrollWidth.toString()" });
int _ContentWidth;
if (!int.TryParse(_WidthString, out _ContentWidth))
throw new Exception(string.Format("failure/width:{0}", _WidthString));
webView.Width = _ContentWidth;
// resize height to content
var _OriginalHeight = webView.Height;
var _HeightString = await webView.InvokeScriptAsync("eval",
new[] { "document.body.scrollHeight.toString()" });
int _ContentHeight;
if (!int.TryParse(_HeightString, out _ContentHeight))
throw new Exception(string.Format("failure/height:{0}", _HeightString));
webView.Height = _ContentHeight;
// create brush
var _OriginalVisibilty = webView.Visibility;
webView.Visibility = Windows.UI.Xaml.Visibility.Visible;
var _Brush = new WebViewBrush
{
SourceName = webView.Name,
Stretch = Stretch.Uniform
};
_Brush.Redraw();
// reset, return
webView.Width = _OriginalWidth;
webView.Height = _OriginalHeight;
webView.Visibility = _OriginalVisibilty;
return _Brush;
}
async System.Threading.Tasks.Task<IEnumerable<FrameworkElement>> GetWebPagesAsync(WebView webView, Windows.Foundation.Size page)
{
// ask the content its width
var _WidthString = await webView.InvokeScriptAsync("eval",
new[] { "document.body.scrollWidth.toString()" });
int _ContentWidth;
if (!int.TryParse(_WidthString, out _ContentWidth))
throw new Exception(string.Format("failure/width:{0}", _WidthString));
webView.Width = _ContentWidth;
// ask the content its height
var _HeightString = await webView.InvokeScriptAsync("eval",
new[] { "document.body.scrollHeight.toString()" });
int _ContentHeight;
if (!int.TryParse(_HeightString, out _ContentHeight))
throw new Exception(string.Format("failure/height:{0}", _HeightString));
webView.Height = _ContentHeight;
// how many pages will there be?
var _Scale = page.Width / _ContentWidth;
var _ScaledHeight = (_ContentHeight * _Scale);
var _PageCount = (double)_ScaledHeight / page.Height;
_PageCount = _PageCount + ((_PageCount > (int)_PageCount) ? 1 : 0);
// create the pages
var _Pages = new List<Windows.UI.Xaml.Shapes.Rectangle>();
for (int i = 0; i < (int)_PageCount; i++)
{
var _TranslateY = -page.Height * i;
var _Page = new Windows.UI.Xaml.Shapes.Rectangle
{
Height = page.Height,
Width = page.Width,
Margin = new Thickness(5),
Tag = new TranslateTransform { Y = _TranslateY },
};
_Page.Loaded += async (s, e) =>
{
var _Rectangle = s as Windows.UI.Xaml.Shapes.Rectangle;
var _Brush = await GetWebViewBrushAsync(webView);
_Brush.Stretch = Stretch.UniformToFill;
_Brush.AlignmentY = AlignmentY.Top;
_Brush.Transform = _Rectangle.Tag as TranslateTransform;
_Rectangle.Fill = _Brush;
};
_Pages.Add(_Page);
}
return _Pages;
}
}
}

For your requment, I simplified the PrintHelper of official sample and created a simple sample to print WebView via use WebViewBrush.
<Page.BottomAppBar>
<CommandBar>
<AppBarButton
x:Name="appbar_Printer"
Click="appbar_Printer_Click"
Label="printer" />
</CommandBar>
</Page.BottomAppBar>
<Grid x:Name="PrintArea" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="995" />
<ColumnDefinition Width="300" />
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<WebView Grid.Column="0" x:Name="MyWebView" Source="http://www.stackoverflow.com" HorizontalAlignment="Right" />
<Rectangle Grid.Column="1" x:Name="MyWebViewRectangle" Fill="Red" />
<Button Grid.Column="2" Content="Print" HorizontalAlignment="Center"/>
</Grid>
When the WebView load completed, you could add the MyWebViewRectangle that fill with WebViewBrush to printDoc.
private async void appbar_Printer_Click(object sender, RoutedEventArgs e)
{
if (printDoc != null)
{
printDoc.GetPreviewPage -= OnGetPreviewPage;
printDoc.Paginate -= PrintDic_Paginate;
printDoc.AddPages -= PrintDic_AddPages;
}
this.printDoc = new PrintDocument();
printDoc.GetPreviewPage += OnGetPreviewPage;
printDoc.Paginate += PrintDic_Paginate;
printDoc.AddPages += PrintDic_AddPages;
bool showPrint = await PrintManager.ShowPrintUIAsync();
}
private void PrintDic_AddPages(object sender, AddPagesEventArgs e)
{
Rectangle page = (Rectangle)this.FindName("MyWebViewRectangle");
printDoc.AddPage(page);
printDoc.AddPagesComplete();
}
private void PrintDic_Paginate(object sender, PaginateEventArgs e)
{
PrintTaskOptions opt = task.Options;
PrintTaskOptionDetails printDetailedOptions = PrintTaskOptionDetails.GetFromPrintTaskOptions(e.PrintTaskOptions);
printDoc.SetPreviewPageCount(1, PreviewPageCountType.Final);
}
I have uploaded the code sample to github that you could refer to.

Related

TabControl overlays Minimize, Maximize and Close button of window

If I create for example 12 Tabs at start of my app the tabpages are overlapping the Close, Minimize and Maximize buttons,
I have used the official sample from Microsoft:
https://github.com/microsoft/WinUI-Gallery/blob/master/XamlControlsGallery/TabViewPages/TabViewWindowingSamplePage.xaml.cs
I only changed the number of tabs created at start to 12 like this:
// Main Window -- add some default items
for (int i = 0; i < 12; i++)
{
Tabs.TabItems.Add(CreateNewTVI($"Item {i}", $"Page {i}"));
}
And then this happens:
And I really don't know why this happens
Edit:
The Xaml Code:
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<muxc:TabView x:Name="Tabs"
VerticalAlignment="Stretch"
<muxc:TabView.TabStripHeader>
<Grid x:Name="ShellTitlebarInset" Background="Transparent" />
</muxc:TabView.TabStripHeader>
<muxc:TabView.TabStripFooter>
<Grid x:Name="CustomDragRegion" Background="Transparent" HorizontalAlignment="Right" Width="188"/>
</muxc:TabView.TabStripFooter>
</muxc:TabView>
</Grid>
The MainPage.xaml.cs
public MainPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
Tabs.SelectedIndex = 0;
// Extend into the titlebar
var coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
coreTitleBar.ExtendViewIntoTitleBar = true;
coreTitleBar.LayoutMetricsChanged += CoreTitleBar_LayoutMetricsChanged;
var titleBar = ApplicationView.GetForCurrentView().TitleBar;
titleBar.ButtonBackgroundColor = Windows.UI.Colors.Transparent;
titleBar.ButtonInactiveBackgroundColor = Windows.UI.Colors.Transparent;
Window.Current.SetTitleBar(CustomDragRegion);
// Main Window - add some tabs
for (int i = 0; i < 24; i++)
{
Tabs.TabItems.Add(CreateNewTVI($"Item {i}", $"Page {i}"));
}
}
private void CoreTitleBar_LayoutMetricsChanged(CoreApplicationViewTitleBar sender, object args)
{
// To ensure that the tabs in the titlebar are not occluded by shell
// content, we must ensure that we account for left and right overlays.
// In LTR layouts, the right inset includes the caption buttons and the
// drag region, which is flipped in RTL.
// The SystemOverlayLeftInset and SystemOverlayRightInset values are
// in terms of physical left and right. Therefore, we need to flip
// then when our flow direction is RTL.
if (FlowDirection == FlowDirection.LeftToRight)
{
CustomDragRegion.MinWidth = sender.SystemOverlayRightInset;
ShellTitlebarInset.MinWidth = sender.SystemOverlayLeftInset;
}
else
{
CustomDragRegion.MinWidth = sender.SystemOverlayLeftInset;
ShellTitlebarInset.MinWidth = sender.SystemOverlayRightInset;
}
// Ensure that the height of the custom regions are the same as the titlebar.
CustomDragRegion.Height = ShellTitlebarInset.Height = sender.Height;
}
private TabViewItem CreateNewTVI(string header, string dataContext)
{
var newTab = new TabViewItem()
{
IconSource = new Microsoft.UI.Xaml.Controls.SymbolIconSource()
{
Symbol = Symbol.Placeholder
},
Header = header,
Content = new TextBlock()
{
Text = "This is a text:\n" + dataContext, HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center,
FontSize = 25,
}
};
return newTab;
}
To fix this, you have to first add a Loaded event to your CustomDragRegion. Now you can remove the code from the OnNavigateTo function and paste it into the Loaded function. That's it.
private void CustomDragRegion_Loaded(object sender, RoutedEventArgs e)
{
Tabs.SelectedIndex = 0;
// Extend into the titlebar
var coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
coreTitleBar.ExtendViewIntoTitleBar = true;
coreTitleBar.LayoutMetricsChanged += CoreTitleBar_LayoutMetricsChanged;
var titleBar = ApplicationView.GetForCurrentView().TitleBar;
titleBar.ButtonBackgroundColor = Windows.UI.Colors.Transparent;
titleBar.ButtonInactiveBackgroundColor = Windows.UI.Colors.Transparent;
Window.Current.SetTitleBar(CustomDragRegion);
// Main Window - add some tabs
for (int i = 0; i < 24; i++)
{
Tabs.TabItems.Add(CreateNewTVI($"Item {i}", $"Page {i}"));
}
}

How can I capture the canvas area from the Image in the ScrollViewer

I use the scrollviewer to zoom in or out of the picture, and it has been successful. Now I hope to draw an area on the picture and capture the area to an image. But the image I get is blank except the border. Here is my code.
XAML:
<Window x:Class="Capture.MainWindow"
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:Capture"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Slider Grid.Column="0" Orientation="Vertical"
HorizontalAlignment="Left" Minimum="1" x:Name="slider"/>
<ScrollViewer Name="scrollViewer" Grid.Column="1"
VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Visible" Margin="0,0,0,40">
<Grid Name="grid" Width="400" Height="400" >
<Grid.LayoutTransform>
<TransformGroup x:Name="TfGroup">
<ScaleTransform x:Name="scaleTransform"/>
</TransformGroup>
</Grid.LayoutTransform>
<Viewbox Grid.Column="0" Grid.Row="0">
<Image x:Name="img" Source="C:\Users\citic\Desktop\微信截图_20200728104010.png" />
</Viewbox>
<Canvas x:Name="canvas" MouseDown="Canvas_MouseDown" MouseMove="Canvas_MouseMove" MouseUp="Canvas_MouseUp" Background="Transparent"/>
</Grid>
</ScrollViewer>
<Button Grid.Column="1" Content="Capture" Margin="338,381,337.333,9.667" Click="Button_Click"/>
</Grid>
</Window>
public partial class MainWindow : Window
{
Point? lastCenterPositionOnTarget;
Point? lastMousePositionOnTarget;
Point? lastDragPoint;
private System.Windows.Point startPoint;
private System.Windows.Shapes.Rectangle rect;
private int w1;
private int h1;
public MainWindow()
{
InitializeComponent();
scrollViewer.ScrollChanged += OnScrollViewerScrollChanged;
scrollViewer.PreviewMouseLeftButtonUp += OnMouseLeftButtonUp;
scrollViewer.PreviewMouseWheel += OnPreviewMouseWheel;
slider.ValueChanged += OnSliderValueChanged;
}
void OnScrollViewerScrollChanged(object sender, ScrollChangedEventArgs e)
{
if (e.ExtentHeightChange != 0 || e.ExtentWidthChange != 0)
{
Point? targetBefore = null;
Point? targetNow = null;
if (!lastMousePositionOnTarget.HasValue)
{
if (lastCenterPositionOnTarget.HasValue)
{
var centerOfViewport = new Point(scrollViewer.ViewportWidth / 2,
scrollViewer.ViewportHeight / 2);
Point centerOfTargetNow =
scrollViewer.TranslatePoint(centerOfViewport, grid);
targetBefore = lastCenterPositionOnTarget;
targetNow = centerOfTargetNow;
}
}
else
{
targetBefore = lastMousePositionOnTarget;
targetNow = Mouse.GetPosition(grid);
lastMousePositionOnTarget = null;
}
if (targetBefore.HasValue)
{
double dXInTargetPixels = targetNow.Value.X - targetBefore.Value.X;
double dYInTargetPixels = targetNow.Value.Y - targetBefore.Value.Y;
double multiplicatorX = e.ExtentWidth / grid.Width;
double multiplicatorY = e.ExtentHeight / grid.Height;
double newOffsetX = scrollViewer.HorizontalOffset -
dXInTargetPixels * multiplicatorX;
double newOffsetY = scrollViewer.VerticalOffset -
dYInTargetPixels * multiplicatorY;
if (double.IsNaN(newOffsetX) || double.IsNaN(newOffsetY))
{
return;
}
scrollViewer.ScrollToHorizontalOffset(newOffsetX);
scrollViewer.ScrollToVerticalOffset(newOffsetY);
}
}
}
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
scrollViewer.Cursor = Cursors.Arrow;
scrollViewer.ReleaseMouseCapture();
lastDragPoint = null;
}
private void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
lastMousePositionOnTarget = Mouse.GetPosition(grid);
System.Windows.Point centerPoint = e.GetPosition(img);
var val = e.Delta * 0.01; //描述鼠标滑轮滚动
if (scaleTransform.ScaleX + val < 0.1) return;
if (scaleTransform.ScaleX + val > 100) return;
scaleTransform.CenterX = centerPoint.X;
scaleTransform.CenterY = centerPoint.Y;
scaleTransform.ScaleX += val;
scaleTransform.ScaleY += val;
if (e.Delta > 0)
{
slider.Value += 1;
}
if (e.Delta < 0)
{
slider.Value -= 1;
}
e.Handled = true;
}
private void OnSliderValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
scaleTransform.ScaleX = e.NewValue;
scaleTransform.ScaleY = e.NewValue;
var centerOfViewport = new System.Windows.Point(scrollViewer.ViewportWidth / 2, scrollViewer.ViewportHeight / 2);
lastCenterPositionOnTarget = scrollViewer.TranslatePoint(centerOfViewport, grid);
}
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
canvas.Children.Clear();
startPoint = e.GetPosition(canvas);
rect = new System.Windows.Shapes.Rectangle
{
Stroke = System.Windows.Media.Brushes.IndianRed,
StrokeThickness = 0.2,
StrokeDashArray = new DoubleCollection { 2 }
};
Canvas.SetLeft(rect, startPoint.X);
Canvas.SetTop(rect, startPoint.Y);
canvas.Children.Add(rect);
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Released || rect == null)
return;
var pos = e.GetPosition(canvas);
var x = Math.Min(pos.X, startPoint.X);
var y = Math.Min(pos.Y, startPoint.Y);
var w = Math.Max(pos.X, startPoint.X) - x;
var h = Math.Max(pos.Y, startPoint.Y) - y;
w1 = (int)w;
h1 = (int)h;
rect.Width = w;
rect.Height = h;
Canvas.SetLeft(rect, x);
Canvas.SetTop(rect, y);
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var rect = new Rect(canvas.RenderSize);
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
dc.DrawRectangle(new VisualBrush(canvas), null, rect);
}
var bitmap = new RenderTargetBitmap(
(int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Default);
bitmap.Render(visual);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using (var file = File.OpenWrite(#"C:\Users\citic\Desktop\test.jpg"))
{
encoder.Save(file);
}
}
}
I am a WPF novice, and many contents are still learning. Please help me, thank you!
The reason why it isn't working is because you're only capturing the Canvas and converting it to a bitmap. If you look at your layout the Image is on another layer. It is not placed on the Canvas.
<Grid>
<Viewbox>
<Image /> <!-- This is on a separate layer of the layout -->
</Viewbox>
<Canvas /> <!-- You're only capturing this -->
</Grid>
Instead of capturing the Canvas, maybe you should try the Grid instead.

How To Dynamically Add Arbitrary Number Of Line Series To WPF Toolkit Chart?

Is it possible to draw multiple lines in a single toolkit chart where line numbers are determined at run-time? I prefer a MVVM way of binding lines to a collection. For example below, there is only one "LineSeries" to be shown, but what if I want to show multiple lines. Thank you!
<ch:Chart.Series>
<ch:LineSeries Title="{Binding Title}"
ItemsSource="{Binding DataPoints}"
IndependentValueBinding="{Binding Path=X}"
DependentValueBinding="{Binding Path=Y}">
</ch:LineSeries>
</ch:Chart.Series>
EDIT 3 - Adding a Test button:
XAML:
<Grid>
<chartingToolkit:Chart x:Name="chart1" HorizontalAlignment="Left" Margin="10,10,0,0" Title="Chart Title" VerticalAlignment="Top" Width="498" Height="277">
</chartingToolkit:Chart>
<Button x:Name="button1" Content="ADD" HorizontalAlignment="Center" Margin="226,292,217.4,0" VerticalAlignment="Top" Width="75" Click="button1_Click"/>
</Grid>
Window:
int index;
MyViewModel2 viewModel;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
viewModel = new MyViewModel2();
DataContext = viewModel;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
PointCollection pc = new PointCollection();
for (int i = 1; i <= 10; i++)
pc.Add(new Point { X = i, Y = i * (2 + index) });
LineSeries series1 = new LineSeries();
series1.DependentValuePath = "Y";
series1.IndependentValuePath = "X";
series1.ItemsSource = pc;
chart1.Series.Add(series1);
viewModel.MyList.Add(pc);
index++;
}
EDIT 2 - Adding Series dynamically:
XAML:
<chartingToolkit:Chart x:Name="chart1" Margin="0" Title="Chart Title">
</chartingToolkit:Chart>
ViewModel:
public class MyViewModel2
{
public List<PointCollection> MyList { get; set; }
public MyViewModel2()
{
MyList = new List<PointCollection>();
}
}
Window:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
viewModel = new MyViewModel2();
DataContext = viewModel;
PointCollection pc1 = new PointCollection();
PointCollection pc2 = new PointCollection();
for (int i = 1; i <= 10; i++)
{
pc1.Add(new Point { X = i, Y = i * 2 });
pc2.Add(new Point { X = i, Y = i * 3 });
}
LineSeries series1 = new LineSeries();
series1.DependentValuePath = "Y";
series1.IndependentValuePath = "X";
series1.ItemsSource = pc1;
chart1.Series.Add(series1);
viewModel.MyList.Add(pc1);
LineSeries series2 = new LineSeries();
series2.DependentValuePath = "Y";
series2.IndependentValuePath = "X";
series2.ItemsSource = pc2;
chart1.Series.Add(series2);
viewModel.MyList.Add(pc2);
}
EDIT 1 - This should get you going:
XAML:
<Grid>
<chartingToolkit:Chart Margin="0" Title="Chart Title">
<chartingToolkit:LineSeries DependentValuePath="Y" IndependentValuePath="X" ItemsSource="{Binding MyPointCollection1}"/>
<chartingToolkit:LineSeries DependentValuePath="Y" IndependentValuePath="X" ItemsSource="{Binding MyPointCollection2}"/>
</chartingToolkit:Chart>
</Grid>
ViewModel:
public class MyViewModel
{
public PointCollection MyPointCollection1 { get; set; }
public PointCollection MyPointCollection2 { get; set; }
public MyViewModel()
{
MyPointCollection1 = new PointCollection();
MyPointCollection2 = new PointCollection();
}
}
Window:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
viewModel = new MyViewModel();
DataContext = viewModel;
for (int i = 1; i <= 10; i++)
{
viewModel.MyPointCollection1.Add(new Point { X = i, Y = i * 2 });
viewModel.MyPointCollection2.Add(new Point { X = i, Y = i * 3 });
}
}

How do you get Canvas.SetTop to work on ItemsCollection items?

Below is the complete program (XAML and code behind). When started you will see:
When you click [Show/Hide] you see:
When you uncheck Home and Documents and click [Apply] you see:
As you can see, the Home and Documents folder disappear, but the other folders do not move up. Looking at the two list boxes you see three items per line, folder label, the value for Canvas.SetTop, and True: Visibility.Visible or False: Visibility.Collapsed. The Original Placement list box are the original values. Each time you click [Apply] the New Placement List box shows that new values. The Visibility value gets applied and the result is visible, either the folder is there or it is not. However, applying the Canvas.SetTop does not work. And you can see that the values have changed for the Canvas.SetTop. And, if you look at the code, you see that it is applied to the same UIElement as the Visibility is applied to:
var f = Me[i];
Canvas.SetTop(iec, f.Top); // Why does this not work and
iec.Visibility = f.FolderVisible; // this does work?
I need the folders that are visible to move up to take the place of those that are collapsed. Canvas.SetTop is not working. How can I get the Folders to move?
Here is the Solution Explorer pane so that you know what is needed:
Here is the XAML:
<Window x:Class="FolderTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:FolderTest"
Title="Folder Test"
Width="450"
Height="410">
<Grid Margin="10">
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical">
<!-- Folder Show/Hide Button -->
<Button Name="FolderOptions" Content="Show/Hide" FontSize="8" FontWeight="Bold" Width="50" Height="20" Margin="116, 0, 0, 0" Click="Event_ShowHide_ButtonClick" />
<!-- Folders -->
<Grid>
<Canvas Name="xFolders"
Width="170"
Height="309"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Margin="0,10,0,0">
<Canvas.Resources>
<local:Folders x:Key="myFolders" />
</Canvas.Resources>
<ItemsControl ItemsSource="{Binding Source={StaticResource myFolders}}">
<ItemsControl.Template>
<ControlTemplate>
<ItemsPresenter />
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
</DataTemplate.Resources>
<Canvas Name="FolderCanvas"
Tag="{Binding Path=Number}"
Visibility="{Binding Path=FolderVisible}">
<Path Data="{Binding Path=FolderPath}"
Stroke="{Binding Path=Brush}"
Fill="{Binding Path=Brush}"/>
<StackPanel Orientation="Horizontal"
Canvas.Left="5"
Canvas.Top="2">
<TextBlock Text="{Binding Path=Label}"
FontSize="12"
Margin="20, 0, 0, 0" />
</StackPanel>
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Top"
Value="{Binding Top}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Canvas>
</Grid>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="10, 0, 0, 0">
<TextBlock Text="Original Placemet:" />
<ListBox Name="OriginalPlacement" />
<Button Name="Refresh" Content="New Placemet:" Margin="0, 10, 0, 0" Click="Event_OriginalPlacement_ButtonClick" />
<ListBox Name="NewPlacement" />
</StackPanel>
</StackPanel>
</Grid>
</Window>
Here is the C# Code Behind:
using System;
using System.Collections.Generic;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows;
using System.Collections.ObjectModel;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
namespace FolderTest
{
public struct GD
{
public static MainWindow MainWindow = null;
public static Button Refresh = null;
}
public partial class MainWindow : Window
{
public MainWindow()
{
GD.MainWindow = this;
InitializeComponent();
Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
GD.Refresh = Refresh;
Folders.Placement(ref OriginalPlacement);
}
private void Event_ShowHide_ButtonClick(object sender, RoutedEventArgs e)
{
var pu = Folders.FolderShowPopUp();
pu.PlacementTarget = FolderOptions;
pu.IsOpen = true;
}
private void Event_OriginalPlacement_ButtonClick(object sender, RoutedEventArgs e)
{
Folders.Placement(ref NewPlacement);
}
}
public class Folder
{// Specification for each folder tab seen on the left.
public int Number { get; set; } // Folder sequence number top to bottom starging with 1.
public string Label { get; set; } // The label that appears on the folder tab itself.
public double Top { get; set; } // Position of the upper left corner of this folder.
public SolidColorBrush Brush { get; set; } // Solid Color Brush.
public string FolderPath { get; set; } // Contains the geometric path to draw this folder and its tab.
public Visibility FolderVisible { get; set; } // This folder's Show/Hide flag.
public Folder(int Number, string Label, double Top, SolidColorBrush Brush, string FolderPath, Visibility FolderVisible)
{
this.Number = Number;
this.Label = Label;
this.Top = Top;
this.Brush = Brush;
this.FolderPath = FolderPath;
this.FolderVisible = FolderVisible;
}
}
public class Folders : ObservableCollection<Folder>
{
public static ObservableCollection<Folder> Me = null;
private static string[] Labels = new string[]
{
"Personal",
"Health",
"Finances",
"Home",
"Employment",
"Insurance",
"Documents",
"Contacts",
"Journal"
};
private static Dictionary<string, Tuple<bool, bool>> LabelData = new Dictionary<string, Tuple<bool, bool>>()
{// Label Show Hidable
{Labels[0], new Tuple<bool, bool>(true, false)},
{Labels[1], new Tuple<bool, bool>(true, true)},
{Labels[2], new Tuple<bool, bool>(true, true)},
{Labels[3], new Tuple<bool, bool>(true, true)},
{Labels[4], new Tuple<bool, bool>(true, true)},
{Labels[5], new Tuple<bool, bool>(true, true)},
{Labels[6], new Tuple<bool, bool>(true, true)},
{Labels[7], new Tuple<bool, bool>(true, false)},
{Labels[8], new Tuple<bool, bool>(true, true)}
};
private static string[] FolderColors = new string[]
{
"FF36579E",
"FFDF2024",
"FF16A146",
"FF00B2D4",
"FFF47B20",
"FF9F1F63",
"FF13A89E",
"FFB7B7E7",
"FF50CAF5",
"FFAA9E74",
"FF86787D",
"FF36D146",
};
private static byte[] ARGBColor = new byte[4]; // Byte array for the folder top color.
private static void ColorString2ARGB(ref byte[] bytes, string Hex)
{// Converts 8 char hex string to 4 byte array.
for (int i = 0; i < 8; i += 2)
bytes[i / 2] = Convert.ToByte(Hex.Substring(i, 2), 16);
}
private static int colorIndex = -1; // Initial value of the colorIndex.
private static string NextColor()
{// Returns a 8 char string containing the next top FolderColor. If at end, cycle to beginning.
colorIndex++;
if (colorIndex >= FolderColors.Length) colorIndex = 0;
return FolderColors[colorIndex];
}
private class FolderShow
{
public string Label { get; set; }
public bool Show { get; set; }
public bool Hidable { get; set; }
public FolderShow(string label, bool show, bool hidable)
{
Label = label;
Show = show;
Hidable = hidable;
}
}
private static List<FolderShow> FolderShowList = null;
public static Popup FolderShowPopUp()
{
var pu = new Popup()
{
Placement = PlacementMode.Right,
AllowsTransparency = true,
StaysOpen = false
};
var b = new Border()
{
BorderThickness = new Thickness(2),
BorderBrush = new SolidColorBrush() { Color = Colors.Black },
CornerRadius = new CornerRadius(5),
Background = new SolidColorBrush() { Color = Colors.White }
};
var sp = new StackPanel()
{
Orientation = Orientation.Vertical,
Margin = new Thickness(10)
};
var tb = new TextBlock()
{
Text = "Checked Folders will be Displayed: ",
FontSize = 16,
FontWeight = FontWeights.Bold,
};
sp.Children.Add(tb);
foreach (var fs in FolderShowList)
{
var cb = new CheckBox()
{
Content = fs.Label,
IsChecked = fs.Show,
IsEnabled = fs.Hidable,
FontSize = 14,
FontWeight = FontWeights.Bold,
Margin = new Thickness(0, 5, 0, 0)
};
cb.Click += new RoutedEventHandler(Event_CheckBoxFolderList_Click);
sp.Children.Add(cb);
}
var bp = new StackPanel()
{
Orientation = Orientation.Horizontal,
Margin = new Thickness(0, 5, 0, 0)
};
var ba = new Button() { Content = "Apply", Width = 50, Height = 25, BorderBrush = new SolidColorBrush(Colors.Transparent), Tag = pu };
ba.Click += new RoutedEventHandler(Event_ApplyFolderList_Click);
bp.Children.Add(ba);
var bc = new Button() { Content = "Cancel", Width = 50, Height = 25, BorderBrush = new SolidColorBrush(Colors.Transparent), Tag = pu, Margin = new Thickness(7, 0, 0, 0) };
bc.Click += new RoutedEventHandler(Event_CancelFolderList_Click);
bp.Children.Add(bc);
sp.Children.Add(bp);
var tbm = new TextBlock()
{
Text = "Disabled folders cannot be hidden.",
Margin = new Thickness(0, 5, 0, 0),
FontSize = 12,
Foreground = new SolidColorBrush() { Color = Colors.Red }
};
sp.Children.Add(tbm);
b.Child = sp;
pu.Child = b;
return pu;
}
private static void Event_CheckBoxFolderList_Click(object sender, RoutedEventArgs e)
{
var cb = (CheckBox)e.Source;
foreach (var fs in FolderShowList)
{
if (fs.Label == cb.Content as string)
{
fs.Show = (bool)cb.IsChecked;
break;
}
}
}
private static void Event_CancelFolderList_Click(object sender, RoutedEventArgs e)
{
((Popup)((Button)e.Source).Tag).IsOpen = false;
}
private static void Event_ApplyFolderList_Click(object sender, RoutedEventArgs e)
{
foreach (var fs in FolderShowList)
{
var sh = LabelData[fs.Label];
LabelData[fs.Label] = new Tuple<bool, bool>(fs.Show, sh.Item2);
}
((Popup)((Button)e.Source).Tag).IsOpen = false;
int p = 0;
foreach (var f in Me)
{
var fs = LabelData[f.Label].Item1 == true;
f.Top = p * folderPositionFactor;
f.FolderVisible = fs ? Visibility.Visible : Visibility.Collapsed;
if (fs) p += 1;
}
foreach (ItemsControl ic in GD.MainWindow.xFolders.Children)
{
for (int i = 0; i < ic.Items.Count; i++)
{
var ie = (UIElement)ic.ItemContainerGenerator.ContainerFromIndex(i);
var iec = Controls.FindChildByType<Canvas>(ie, "FolderCanvas");
if (iec != null)
{
var f = Me[i];
Canvas.SetTop(iec, f.Top); // Why does this not work and
iec.Visibility = f.FolderVisible; // this does work?
}
}
break;
}
GD.Refresh.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
}
public static void Placement(ref ListBox lb)
{
lb.Items.Clear();
foreach (ItemsControl ic in GD.MainWindow.xFolders.Children)
{
for (int i = 0; i < ic.Items.Count; i++)
{
var ie = (UIElement)ic.ItemContainerGenerator.ContainerFromIndex(i);
var iec = Controls.FindChildByType<Canvas>(ie, "FolderCanvas");
if (iec != null)
{
var f = Me[i];
lb.Items.Add(f.Label + ": " + f.Top.ToString() + ", " + (f.FolderVisible == Visibility.Visible ? "True" : "False"));
}
}
break;
}
}
public Folders()
{// The constructor, initializes itself by creating a folder for each label in Labels
FolderShowList = new List<FolderShow>();
for (int i = 0; i < Labels.Length; i++)
{
string n = Labels[i];
bool h = LabelData[Labels[i]].Item2;
bool s = h == true ? LabelData[Labels[1]].Item1 == true : true;
FolderShowList.Add(new FolderShow(n, s, h));
}
SetFolders();
Me = this;
}
const double folderPositionFactor = 31; // 21.80;
public void SetFolders()
{
SolidColorBrush[] scb = new SolidColorBrush[Labels.Length]; // Hold the linear solid color brush to assign to the folder.
Color[] pointerColor = new Color[Labels.Length]; // Hold the color to assign to the folder's solid color brush.
for (int i = 0; i < Labels.Length; i++)
{// Create a solid color brush for each folder.
ColorString2ARGB(ref ARGBColor, NextColor()); // Color into byte array.
Color TmpColor = Color.FromArgb(ARGBColor[0], ARGBColor[1], ARGBColor[2], ARGBColor[3]); // Create top color.
pointerColor[i] = TmpColor;
SolidColorBrush TmpSCB = new SolidColorBrush() { Color = TmpColor };
scb[i] = TmpSCB; // Assign the solid color brush.
}
// All is ready to create the individual folders.
const string folderHeight = "56"; // "44";
Brush FontColor = Brushes.Black; // Initial font color for labels.
string fp = "M0,7 A7,7 90 0 1 7,0 L100,0 105,18 150,18 150,FH 0,FH Z".Replace("FH", folderHeight); // Initial geometric path for folder design.
int afp = 0; // Actual Folder Position.
for (int i = 0; i < Labels.Length; i++)
{// Create the individual folders.
bool fs = FolderShowList[i].Show;
Add(new Folder(
i + 1, // Folder sequence count.
Labels[i], // Folder label.
afp * folderPositionFactor, // Position of top of folder.
scb[i % scb.Length], // Solid color brush.
fp, // Geometric path for folder design.
fs ? Visibility.Visible : Visibility.Collapsed // User Hidden.
)
);
if (fs) afp += 1;
if (i == 0)
{// First folder created, now set values for remaining folders.
FontColor = Brushes.White;
fp = "M0,25 A7,7 90 0 1 7,18 L13,18 18,0 100,0 105,18 150,18 150,FH 0,FH Z".Replace("FH", folderHeight);
}
}
}
}
public static class Controls
{
public static T FindChildByType<T>(DependencyObject parent, string childName) where T : DependencyObject
{
if (parent == null) return null; // No parent, get out of here.
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
// If the child is not of the request child type child
T childType = child as T;
if (childType == null)
{
// recursively drill down the tree
foundChild = FindChildByType<T>(child, childName);
// If the child is found, break so we do not overwrite the found child.
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
// If the child's name is set for search
if (frameworkElement != null && frameworkElement.Name == childName)
{
// if the child's name is of the request name
foundChild = (T)child;
break;
}
}
else
{
// child element found.
foundChild = (T)child;
break;
}
}
return foundChild;
}
}
}
Thanks for any help that you can provide.
I finally figured out the answer, and it is very simple.
This is the code to be changed (the center line only):
var f = Me[i];
Canvas.SetTop(iec, f.Top); // Why does this not work
iec.Visibility = f.FolderVisible; // and this does work?
This is the new code (only the center line is changed, actually, only one character is removed):
var f = Me[i];
Canvas.SetTop(ie, f.Top);
iec.Visibility = f.FolderVisible;
That is, change Canvas.SetTop(iec, f.Top); to Canvas.SetTop(ie, f.Top); that is, only change iec to ie and all works fine.

Picture Puzzle: Set one Image to the same size and position to another image

today I already asked you a question for my picture puzzle (Original Question).
I started to rewrite my code for better performance. And I got the most important part done!
But I have another problem.. I generate a gray overlay image to hide the image, but because I want to handle dynamic size of pictures I cannot set fixed width and height values for the "mask". So probably not the whole picture is overlayed with my "mask".
Does somebody have a solution for this? I don't know how to set the position and size of my mask exactly to the position and size of the picture.
I attached a screencast for demonstration.
XAML:
<Window x:Class="PicturePuzzle.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Loaded="WindowLoaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="80" />
</Grid.RowDefinitions>
<Grid x:Name="grid"
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Top">
<Image x:Name="imgPicture"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Source="Images/puzzle.gif"
Stretch="Uniform" />
<Image x:Name="imgMask" RenderOptions.EdgeMode="Aliased" />
</Grid>
<StackPanel Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
<Button x:Name="btnStart"
Width="60"
Margin="0,0,5,0"
Click="BtnStartClick"
Content="Start" />
<Button x:Name="btnStop"
Width="60"
Click="BtnStopClick"
Content="Stop"
IsEnabled="False" />
<ToggleButton x:Name="btnSolution"
Margin="5,0,0,0"
Checked="btnSolution_Checked"
Content="Lösung anzeigen"
Unchecked="btnSolution_Unchecked" />
</StackPanel>
<Slider x:Name="slSpeed"
IsDirectionReversed="True"
Maximum="10"
Minimum="1"
ValueChanged="SlSpeedValueChanged"
Value="10" />
</StackPanel>
</Grid>
</Window>
Codebehind:
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace PicturePuzzle
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
_positionAlphaValues = new Dictionary<Point, byte>();
_images = new List<FileInfo>();
using (var s = new StreamReader("Images.txt"))
{
while (!s.EndOfStream)
{
var line = s.ReadLine();
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
var fi = new FileInfo(line);
if (!fi.Exists)
{
continue;
}
_images.Add(fi);
}
}
}
private const int MaxQuadsX = 5;
private const int MaxQuadsY = 5;
private readonly List<FileInfo> _images;
private DispatcherTimer _timer;
private DispatcherTimer _alphaTimer;
private WriteableBitmap _bitmap;
private Size _size;
private List<Point> _positions;
private Dictionary<Point, byte> _positionAlphaValues;
private int _tickCounter;
private int _imageCounter;
private int _quadWidth;
private int _quadHeight;
private void WindowLoaded(object sender, RoutedEventArgs e)
{
_size = imgPicture.RenderSize;
var width = (int)Math.Ceiling(_size.Width);
var height = (int)Math.Ceiling(_size.Height);
_quadWidth = width / MaxQuadsX;
_quadHeight = height / MaxQuadsY;
imgPicture.Width = _quadWidth * MaxQuadsX - 5;
imgPicture.Height = _quadHeight * MaxQuadsY - 5;
_bitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);
imgMask.Source = _bitmap;
}
#region Click handlers
private void BtnStartClick(object sender, RoutedEventArgs e)
{
btnStart.IsEnabled = false;
btnStop.IsEnabled = true;
btnSolution.IsChecked = false;
// set the real picture
_imageCounter = 0;
_images.Shuffle();
SetPuzzlePicture();
_timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(slSpeed.Value / 10) };
_timer.Tick += TimerTick;
_timer.Start();
_alphaTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.1) };
_alphaTimer.Tick += AlphaTimerOnTick;
_alphaTimer.Start();
}
private void BtnStopClick(object sender, RoutedEventArgs e)
{
btnStart.IsEnabled = true;
btnStop.IsEnabled = false;
_timer.Stop();
_alphaTimer.Stop();
}
private void SlSpeedValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (_timer != null)
{
_timer.Interval = TimeSpan.FromSeconds(slSpeed.Value / 10);
}
}
private void btnSolution_Checked(object sender, RoutedEventArgs e)
{
btnStop.IsEnabled = false;
StopTimers();
imgMask.Visibility = Visibility.Hidden;
}
private void btnSolution_Unchecked(object sender, RoutedEventArgs e)
{
btnStart.IsEnabled = true;
btnStop.IsEnabled = false;
ResetMaskImage();
}
#endregion
private void SetPuzzlePicture()
{
_positionAlphaValues.Clear();
ResetMaskImage();
var imgFile = _images[_imageCounter++];
var image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(imgFile.FullName, UriKind.Absolute);
image.EndInit();
imgPicture.Source = image;
}
private void TimerTick(object sender, EventArgs e)
{
if (_tickCounter >= _positions.Count)
{
if (_imageCounter >= _images.Count)
{
_timer.Stop();
btnStart.IsEnabled = true;
btnStop.IsEnabled = false;
return;
}
SetPuzzlePicture();
}
var randomPoint = _positions[_tickCounter++];
_positionAlphaValues.Add(randomPoint, 255);
}
private void AlphaTimerOnTick(object sender, EventArgs eventArgs)
{
var updatedList = new Dictionary<Point, byte>();
foreach (var e in _positionAlphaValues)
{
var newValue = e.Value - (11 - slSpeed.Value) * 5;
if (newValue <= 0)
{
continue;
}
SetAlphaChannel(e.Key, (byte)newValue);
updatedList.Add(e.Key, (byte)newValue);
}
_positionAlphaValues = updatedList;
}
private void StopTimers()
{
if (_timer != null)
{
_timer.Stop();
}
if (_alphaTimer != null)
{
_alphaTimer.Stop();
}
}
private void ResetMaskImage()
{
imgMask.Visibility = Visibility.Visible;
var width = _quadWidth * MaxQuadsX;
var height = _quadHeight * MaxQuadsY;
var size = width * height * 4;
var buffer = new byte[size];
for (int i = 0; i < size; i++)
{
buffer[i++] = 128;
buffer[i++] = 128;
buffer[i++] = 128;
buffer[i] = 255;
}
var area = new Int32Rect(0, 0, width, height);
_bitmap.WritePixels(area, buffer, width * 4, 0);
_positions = GetPositions();
_tickCounter = 0;
}
private void SetAlphaChannel(Point point, byte alpha)
{
var size = _quadWidth * _quadHeight * 4;
var buffer = new byte[size];
for (int i = 0; i < size; i++)
{
buffer[i++] = 128;
buffer[i++] = 128;
buffer[i++] = 128;
buffer[i] = alpha;
}
var startX = (int)point.X * _quadWidth;
var startY = (int)point.Y * _quadHeight;
var area = new Int32Rect(startX, startY, _quadWidth, _quadHeight);
_bitmap.WritePixels(area, buffer, _quadWidth * 4, 0);
}
private List<Point> GetPositions()
{
var generated = new List<Point>();
for (int y = 0; y < MaxQuadsY; y++)
{
for (int x = 0; x < MaxQuadsX; x++)
{
var point = new Point(x, y);
generated.Add(point);
}
}
generated.Shuffle();
return generated;
}
}
}
Extensions.cs
using System;
using System.Collections.Generic;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace PicturePuzzle
{
public static class Extensions
{
public static Color GetPixel(this WriteableBitmap wbm, int x, int y)
{
if (y > wbm.PixelHeight - 1 || x > wbm.PixelWidth - 1)
return Color.FromArgb(0, 0, 0, 0);
if (y < 0 || x < 0)
return Color.FromArgb(0, 0, 0, 0);
if (!wbm.Format.Equals(PixelFormats.Bgra32))
return Color.FromArgb(0, 0, 0, 0);
IntPtr buff = wbm.BackBuffer;
int stride = wbm.BackBufferStride;
Color c;
unsafe
{
var pbuff = (byte*)buff.ToPointer();
int loc = y * stride + x * 4;
c = Color.FromArgb(
pbuff[loc + 3],
pbuff[loc + 2], pbuff[loc + 1],
pbuff[loc]);
}
return c;
}
public static void Shuffle<T>(this IList<T> list)
{
var rng = new Random();
int n = list.Count;
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
}
Example Images.txt (has to be in your output folder, the images also):
Desert.jpg
Hydrangeas.jpg
Jellyfish.jpg
Koala.jpg
Lighthouse.jpg
Penguins.jpg
Tulips.jpg
androids.gif
Chrysanthemum.jpg
And the screencast: Screencast Link
Thanks for any help!
You can set the HorizontalAlignment and VerticalAlignment of your mask Image to Stretch and the Stretch to Fill like so:
<Image HorizontalAlignment="Stretch" VerticalAlignment="Stretch" x:Name="imgMask" Stretch="Fill" RenderOptions.EdgeMode="Aliased" />
This will cause the mask image to fill the grid, which will be sized to the other image.

Categories

Resources