My goal is to create a usercontrol which will redraw when I change its size in designer. For simplicity I created usercontrol Cross. (I am rather a beginner in WPF).
Cross.xaml:
<UserControl x:Class="WpfApplication2.Cross"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Name="Grid1">
</Grid>
</UserControl>
Cross.xaml.cs (without using statements):
namespace WpfApplication2
{
/// <summary>
/// Interaction logic for Cross.xaml
/// </summary>
///
public partial class Cross : UserControl
{
public Cross()
{
InitializeComponent();
Line l = new Line();
l.X1 = 0; l.Y1 = 0; l.X2 = 300; l.Y2 = 300;
l.Stroke = new SolidColorBrush(Colors.Black);
Grid1.Children.Add(l);
l = new Line();
l.X1 = 0; l.Y1 = 300; l.X2 = 300; l.Y2 = 0;
l.Stroke = new SolidColorBrush(Colors.Black);
Grid1.Children.Add(l);
}
}
}
So when I change the size of a Cross in designer from 300 to 600 I want there 2 lines - [0,0,600,600], [0,600,600,0] rather than [0,0,300,300], [0,300,300,0].
Try using The ViewBox Control , Change your xaml to
<UserControl x:Class="WpfApplication2.Cross"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Viewbox>
<Grid Name="Grid1"/>
</Viewbox>
</Grid>
</UserControl>
Related
I'm trying to take a screenshot of user control (viewport) in WPF application. My problem is that I don't know how to get the position of window or viewport while staying in accord with MVVM pattern.
Here is the method, but it takes all the screen instead of my viewport, since I don't know how to bind window/viewport properties to it.
private void saveScreenshot()
{
double screenLeft = SystemParameters.VirtualScreenLeft;
double screenTop = SystemParameters.VirtualScreenTop;
double screenWidth = SystemParameters.VirtualScreenWidth;
double screenHeight = SystemParameters.VirtualScreenHeight;
using (Bitmap bmp = new Bitmap((int)screenWidth, (int)screenHeight))
{
using (Graphics g = Graphics.FromImage(bmp))
{
string fileName = "ScreenCapture -" + DateTime.Now.ToString("ddMMyyyy-hhmmss") + ".png";
g.CopyFromScreen((int)screenLeft, (int)screenTop, 0, 0, bmp.Size);
SaveFileDialog saveFile = new SaveFileDialog(); ;
saveFile.Filter = "JPEG|*.jpeg|Bitmap|*.bmp|Gif|*.gif|Png|*.png";
if (saveFile.ShowDialog() == true)
{
bmp.Save(saveFile.FileName);
}
}
}
}
I was trying to bind some window properties to ViewModel, to get access to window position on screen, but it didn't work.
XAML:
<Window
x:Class="SimpleDemo.MainView"
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:hx="http://helix-toolkit.org/wpf/SharpDX"
xmlns:hw="http://helix-toolkit.org/wpf"
xmlns:local="clr-namespace:SimpleDemo"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="Point cloud visualization"
Width="1280"
Height="720"
Left="{Binding LeftScreenPosition, Mode=TwoWay}"
Top="{Binding TopScreenPosition, Mode=TwoWay}"
mc:Ignorable="d" Background="#FF465065" Foreground="#FFFFFEFE">
And here is the ViewModel (SetValue contains PropertyChanged event things)
private double leftScreenPosition;
private double topScreenPosition;
public double LeftScreenPosition
{
get { return leftScreenPosition; }
set { SetValue(ref leftScreenPosition, value); }
}
public double TopScreenPosition
{
get { return leftScreenPosition; }
set { SetValue(ref leftScreenPosition, value); }
}
I would be really grateful if someone could explain to me where is the mistake, or show me another way to deal with it (Please consider that i'm a total beginner, thank you).
Trick with CommandParameter can let you pass some FrameworkElement to your command placed in your ViewModel. My example
xaml (you can refine if you need only your control in CommandParameter)
<Window x:Class="WpfTestApp.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:WpfTestApp"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
d:DataContext="{d:DesignInstance Type=local:YourViewModel, IsDesignTimeCreatable=True}">
<Grid>
<Button Content="Make screenShot" Command="{Binding MakeScreenShotCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
</Grid>
ViewModel
public class YourViewModel
{
private ICommand _makeScreenShotCommand;
public ICommand MakeScreenShotCommand => _makeScreenShotCommand ?? (_makeScreenShotCommand = new ActionCommand(TakeScreenShot));
private void TakeScreenShot(object control)
{
FrameworkElement element = control as FrameworkElement;
if (element == null)
throw new Exception("Invalid parameter");
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap((int)element.ActualWidth, (int)element.ActualHeight, 96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(element);
PngBitmapEncoder pngImage = new PngBitmapEncoder();
pngImage.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
using (Stream fileStream = File.Create("filePath"))
{
pngImage.Save(fileStream);
}
}
}
Im trying to to render on the UI a red box using the WriteableBitmap object . The application works as intended on UWP :
And on Linux using Gtk.Skia, nothing is being displayed (Shares the same code) :
Here is the C# code :
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
Paint();
}
private void Paint()
{
WriteableBitmap _wb = new WriteableBitmap(100, 100);
byte[] imageArray = new byte[_wb.PixelHeight * _wb.PixelWidth * 4];
for (int i = 0; i < imageArray.Length; i += 4)
{
imageArray[i] = 0;
imageArray[i + 1] = 0;
imageArray[i + 2] = 255;
imageArray[i + 3] = 255;
}
using (Stream stream = _wb.PixelBuffer.AsStream())
{
stream.Write(imageArray, 0, imageArray.Length);
}
test.Source = _wb;
}
}
XAML code :
<Page
x:Class="test.Uno.MainPage"
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"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Image x:Name="test" VerticalAlignment="Top" />
</Grid>
Support for WriteableBitmap is not yet available on Skia. Here's the related issue for this.
Update (2020-09-18): WriteableBitmap is available for Skia GTK/WPF in Uno.UI 3.1.0-dev.364 and later.
I'm currently trying out WPF for the first time, because I have used WinForms before. I started with a little practice and wanted to create a program which draws a line to wherever you click on a canvas. I programatically added the line to the canvas, but it seems that it doesn't draw it. The lines become children of the canvas though.
C# Code
private ArrayList arl = new ArrayList();
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
drawArea.Children.Clear();
arl.Add(Mouse.GetPosition(drawArea));
Point[] points = new Point[arl.Count];
for (int i = 0; i < arl.Count; i++)
points[i] = (Point)arl[i];
Line[] lines = new Line[points.Length - 1];
if(lines.Count() > 0)
{
for (int i = 0; i < lines.Length; i++)
{
lines[i] = new Line();
lines[i].Stroke = SystemColors.WindowFrameBrush;
lines[i].X1 = points[i + 1].X;
lines[i].X2 = points[i].X;
lines[i].Y1 = points[i + 1].Y;
lines[i].Y2 = points[i].Y;
}
foreach (var item in lines)
drawArea.Children.Add(item);
}
}
XAML
<Window x:Class="WPFttest.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:WPFttest"
mc:Ignorable="d"
Title="MainWindow" Height="362" Width="525" MouseDown="Window_MouseDown" BorderBrush="Red" ResizeMode="NoResize" KeyDown="Window_KeyDown" WindowStyle="None">
<Grid x:Name="mainGrid" HorizontalAlignment="Left" Height="362" VerticalAlignment="Top" Width="525" OpacityMask="#00000000">
<Canvas x:Name="drawArea" HorizontalAlignment="Left" Height="312" Margin="0,50,0,0" VerticalAlignment="Top" Width="525" Background="White" MouseDown="Canvas_MouseDown">
</Canvas>
<Grid HorizontalAlignment="Left" Height="50" VerticalAlignment="Top" Width="525" MouseDown="Grid_MouseDown_1" OpacityMask="#00000000" Background="#00000000"/>
</Grid>
I am unable to run the animation. I searched the web and on the website, I did hours of changes but the storyboard does not start. I will not use BeginAnimation. I hope that my problem can also serve to someone else to understand the Storyboard.
enter code here
using HelixToolkit.Wpf;
using System;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Media.Media3D;
namespace test_storyboard_02
{
public partial class MainWindow : Window
{
public Storyboard myStoryboard = new Storyboard();
Model3DGroup cubelet;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
LoadObj();
view1.ZoomExtents();
FrameworkContentElement element = new FrameworkContentElement();
NameScope.SetNameScope(element, new NameScope());
AxisAngleRotation3D rotation = new AxisAngleRotation3D(new Vector3D(0, 0, 1), 180);
RotateTransform3D myRotateTransform3D = new RotateTransform3D(rotation, new Point3D(0, 0, 0));
cubelet.Transform = myRotateTransform3D;
element.RegisterName("rotation", rotation);
DoubleAnimation animation = new DoubleAnimation();
animation.By = 5;
animation.Duration = TimeSpan.FromSeconds(0);
Storyboard.SetTarget(animation, rotation);
Storyboard.SetTargetProperty(animation, new PropertyPath("Angle"));
myStoryboard.Children.Add(animation);
myStoryboard.Duration = TimeSpan.FromSeconds(4);
myStoryboard.Begin(element, HandoffBehavior.Compose);
}
private void LoadObj()
{
view1.Children.Clear();
//cubelets = new Model3DGroup[1, 1, 1];
cubelet = new Model3DGroup();
ModelImporter importer = new ModelImporter();
Model3D ModelCube = importer.Load(#"e:\x.obj");
cubelet.Children.Add(ModelCube);
view1.Children.Add(new ModelVisual3D { Content = cubelet });
}
}
}
There are problems in these lines of code :
FrameworkContentElement element = new FrameworkContentElement();
NameScope.SetNameScope(element, new NameScope());
...
element.RegisterName("rotation", rotation);
Changes :
NameScope scope = new NameScope();
FrameworkContentElement element = new FrameworkContentElement();
NameScope.SetNameScope(element, scope);
...
element.RegisterName("rotation", scope);
See this solves your problem.
This is the xaml file that I used.
<Window x:Class="test_storyboard_02.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:test_storyboard_02"
xmlns:HelixToolkit="clr-namespace:HelixToolkit.Wpf;assembly=HelixToolkit.Wpf"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Grid>
<Canvas Name="LayoutRoot" HorizontalAlignment="Left" Height="319" VerticalAlignment="Top" Width="517">
<HelixToolkit:HelixViewport3D x:Name="view1" Background="Gray" Height="278" Canvas.Left="25" Canvas.Top="22" Width="463">
<HelixToolkit:DefaultLights/>
<!--<local:RubikCube x:Name="cube1" /> -->
</HelixToolkit:HelixViewport3D>
</Canvas>
</Grid>
SOLVED Finally the program WORKS, thanks to #AnjumSKhan. I hope that the code that I enclose will also serve to someone else. Thanks also to stackoverflow.
MainWindow.xaml
<Window x:Class="test_storyboard_02.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:test_storyboard_02"
xmlns:HelixToolkit="clr-namespace:HelixToolkit.Wpf;assembly=HelixToolkit.Wpf"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Window.Resources>
</Window.Resources>
<Grid>
<Canvas Name="LayoutRoot" HorizontalAlignment="Left" Height="319" VerticalAlignment="Top" Width="517">
<HelixToolkit:HelixViewport3D x:Name="view1" Background="Gray" Height="278" Canvas.Left="25" Canvas.Top="22" Width="463">
<HelixToolkit:DefaultLights/>
<!--<local:RubikCube x:Name="cube1" /> -->
</HelixToolkit:HelixViewport3D>
</Canvas>
</Grid>
MainWindow.xaml.cs
using HelixToolkit.Wpf;
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Media3D;
using System.Windows.Shapes;
namespace test_storyboard_02
{
public partial class MainWindow : Window
{
public Storyboard myStoryboard = new Storyboard();
public Model3DGroup MainModel3Dgroup = new Model3DGroup();
Model3DGroup modelFloor;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
LoadObj();
view1.ZoomExtents();
NameScope scope = new NameScope();
FrameworkContentElement element = new FrameworkContentElement();
NameScope.SetNameScope(element, scope);
// Create a box that will be the target
// of the animation.
// Material material = HelixToolkit.Wpf.MaterialHelper.CreateMaterial(Colors.DarkBlue);
// MeshBuilder meshBuilder = new MeshBuilder();
// meshBuilder.AddBox(new Point3D(0, 0, 0), 200, 200, 200);
// GeometryModel3D modelFloor = new GeometryModel3D(meshBuilder.ToMesh(), material);
// modelFloor.SetName("floor");
// MainModel3Dgroup.Children.Add(modelFloor);
var lights = new DefaultLights();
view1.Children.Add(lights);
ModelVisual3D model_visual = new ModelVisual3D();
model_visual.Content = modelFloor;
view1.Children.Add(model_visual);
view1.ZoomExtents();
AxisAngleRotation3D rotation = new AxisAngleRotation3D(new Vector3D(0, 0, 1), 0);
RotateTransform3D myRotateTransform3D = new RotateTransform3D(rotation, new Point3D(0, 0, 0));
modelFloor.Transform = myRotateTransform3D;
element.RegisterName("rotation", rotation);
// Create two DoubleAnimations and set their properties.
DoubleAnimation animation = new DoubleAnimation();
animation.From = 0;
animation.To = 200;
animation.Duration = TimeSpan.FromSeconds(2);
Storyboard.SetTargetProperty(animation, new PropertyPath("Angle"));
Storyboard.SetTargetName(animation, "rotation");
myStoryboard.Children.Add(animation);
myStoryboard.Duration = TimeSpan.FromSeconds(2);
// Make the Storyboard a resource.
this.Resources.Add("unique_id1", myStoryboard);
myStoryboard.Begin(element, HandoffBehavior.Compose);
}
private void LoadObj()
{
view1.Children.Clear();
modelFloor = new Model3DGroup();
ModelImporter importer = new ModelImporter();
Model3D ModelCube = importer.Load(#"e:\x.obj");
modelFloor.Children.Add(ModelCube);
view1.Children.Add(new ModelVisual3D { Content = modelFloor });
}
}
}
I need to show multiple buttons, but each one must have a different background than other buttons, I have been working on it, but I only got to display multiple buttons but with the same background.
Here is the XAML:
<Window x:Class="apple.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="370" Width="525">
<Grid>
<Image Source="C:\Users\Public\Pictures\Sample Pictures\Koala.jpg" Stretch="Fill"/>
<DockPanel Name="dock">
<UniformGrid Name="gridx" DockPanel.Dock="Top" Rows="3" Columns="3" Height="334">
</UniformGrid>
</DockPanel>
</Grid>
</Window>
Also, here is the C# code:
namespace apple
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
masterGUI();
}
public void masterGUI()
{
ImageBrush ib = new ImageBrush();
IconImage[] ico = null;
Bitmap[] img = null;
string[] list = null;
string[] link = Directory.GetFiles(#"C:\ProgramData\Microsoft\Windows\Start Menu\Programs", "*.lnk", SearchOption.AllDirectories);
list = new string[link.Length];
ico = new Icon[link.Length];
img = new Bitmap[link.Length];
for (int n = 0; n < link.Length; n++)
{
System.Windows.Controls.Button newBtn = new Button();
list[n] = System.IO.Path.GetFileNameWithoutExtension(link[n]);
FileToImageIconConverter some = new FileToImageIconConverter(link[n]);
ImageSource imgSource = some.Icon;
ib.ImageSource = imgSource;
newBtn.Background = ib;
newBtn.Content = list[n];
gridx.Children.Add(newBtn);
}
}
}
}
Any idea? thank you.
The ImageBrush needs to be created in the for-loop individually for each item. Otherwise you will end up with the same background for every item.
Also you are approaching this the "wrong" way, in WPF you should use data binding and data templating for this sort of thing instead of imperative looping.