Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,741 questions
This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Hello
I have a problem with my app and the content dialog
So I have an app, that creates an STL based on a drawing
I also wanted to open a content dialog, with the canvas on one side and the point on other side. The idea is to draw a point, when I heck a checkbox and remove it when I uncheck (This will tell the user in Realtime what is happening)
MainviewModel
using NanoFlow.Views.Dialog;
using System.Globalization;
using System.IO;
using System.Linq;
using Path = System.IO.Path;
namespace NanoFlow.ViewModels {
public partial class MainViewModel : ObservableObject {
private const string NanoFlowFolder = "NanoFlow";
private const int gridSpacing = 20; // Spacing between grid lines in pixels
private readonly int _canvasSize = 378; // Size of the canvas in pixels
private bool _areGridMarginsAdded = false;
private readonly List<Line> _gridMarginLines = []; // To track grid lines
private readonly List<TextBlock> _gridTextBlocks = [];
private Grid? _rootContainer;
private Canvas? _canvas;
private PointModel? _previousPoint;
public readonly ObservableCollection<PointModel> Points = [];
public readonly ObservableCollection<LineModel> Lines = [];
public readonly List<Tuple<PointModel, PointModel>> LineData = [];
public readonly List<PointModel> _selectedPoints = [];
public void SetRootContainer(object sender, RoutedEventArgs args) {
_rootContainer = sender as Grid;
}
[RelayCommand]
async Task SaveToSTLAsync() {
// Create the dialog
var fileNameDialog = new ContentDialog {
Title = "Save Design",
Content = new StackPanel {
Children =
{
new TextBlock { Text = "Enter a name for your design:" },
new TextBox { PlaceholderText = "MyDesign.stl", Name = "FileNameTextBox" }
}
},
PrimaryButtonText = "Save",
CloseButtonText = "Cancel",
XamlRoot = _rootContainer?.XamlRoot
};
// Show the dialog
var result = await fileNameDialog.ShowAsync();
if(result == ContentDialogResult.Primary) {
// Retrieve the TextBox value
var stackPanel = (StackPanel)fileNameDialog.Content;
var textBox = stackPanel.Children.OfType<TextBox>().First();
var fileName = textBox.Text;
// Validate the file name
if(string.IsNullOrWhiteSpace(fileName)) {
// Use a default file name if none is provided
fileName = "MyDesign.stl";
}
else if(!fileName.EndsWith(".stl", StringComparison.OrdinalIgnoreCase)) {
// Append the ".stl" extension if it's missing
fileName += ".stl";
}
// Generate the STL file
GetLineData(); // Ensure LineData is updated
ExportSTL(fileName, 5.0);
Console.WriteLine($"STL file '{fileName}' generated successfully.");
}
}
[RelayCommand]
void CreateNewDesign() {
DrawCanvas();
if(_canvas != null) {
_canvas!.PointerPressed += Canvas_PointerPressed;
_canvas.PointerMoved += Canvas_PointerMoved;
_canvas.PointerReleased += Canvas_PointerReleased;
}
Points.Clear();
Lines.Clear();
LineData.Clear();
Console.WriteLine("Create New Design: Canvas initialized and data cleared.");
}
[RelayCommand]
async Task GuidedProcessAsync() {
Points.Clear();
_selectedPoints.Clear();
DrawCanvas();
for(int i = 0; i < _canvasSize; i += gridSpacing) {
for(int j = 0; j < _canvasSize; j += gridSpacing) {
var point = new PointModel(i, j, DrawPoint);
Points.Add(point);
}
}
// Open the dialog and pass the ViewModel
var dialog = new GuidedProcessDialog(this) {
XamlRoot = _rootContainer?.XamlRoot
};
await dialog.ShowAsync();
}
[RelayCommand]
void AddMargin() {
if(_canvas == null) {
return;
}
if(_areGridMarginsAdded) {
RemoveGridMarginsAndTextBlocks();
_areGridMarginsAdded = false;
}
else {
DrawGridMarginsAndTextBlocks();
_areGridMarginsAdded = true;
}
}
private void RemoveGridMarginsAndTextBlocks() {
var allItems = _gridMarginLines.Cast<UIElement>()
.Concat(_gridTextBlocks.Cast<UIElement>())
.ToList();
foreach(var element in allItems) {
_canvas!.Children.Remove(element);
}
// Clear both lists afterward
_gridMarginLines.Clear();
_gridTextBlocks.Clear();
}
private void DrawCanvas() {
_canvas = new Canvas {
Background = new SolidColorBrush(Color.FromArgb(255, 0, 128, 0)),
Width = _canvasSize,
Height = _canvasSize,
};
if(_rootContainer != null) {
_rootContainer.Children.Add(_canvas);
Grid.SetRow(_canvas, 1);
}
}
private void DrawGridMarginsAndTextBlocks() {
if(_canvas == null) {
return;
}
for(int i = 0; i < _canvas!.Width; i += gridSpacing) {
for(int j = 0; j < _canvas.Height; j += gridSpacing) {
// Draw vertical and horizontal lines crossing at intersections
if(i == 0) {
var horizontalLine = new Line {
X1 = 0,
Y1 = j,
X2 = _canvas.Width,
Y2 = j,
Stroke = new SolidColorBrush(Colors.Gray),
StrokeThickness = 1
};
_canvas.Children.Add(horizontalLine);
_gridMarginLines.Add(horizontalLine);
}
if(j == 0) {
var verticalLine = new Line {
X1 = i,
Y1 = 0,
X2 = i,
Y2 = _canvas.Height,
Stroke = new SolidColorBrush(Colors.Gray),
StrokeThickness = 1
};
_canvas.Children.Add(verticalLine);
_gridMarginLines.Add(verticalLine);
}
// Add a TextBlock at each intersection
var textBlock = new TextBlock {
Text = $"({i / gridSpacing},{j / gridSpacing})",
Foreground = new SolidColorBrush(Colors.Black),
FontSize = 6
};
Canvas.SetLeft(textBlock, i + 2); // Position slightly offset for visibility
Canvas.SetTop(textBlock, j + 2);
_canvas.Children.Add(textBlock);
_gridTextBlocks.Add(textBlock);
}
}
}
private void DrawLine(PointModel startPoint, PointModel endPoint) {
var line = new Line {
X1 = startPoint.X,
Y1 = startPoint.Y,
X2 = endPoint.X,
Y2 = endPoint.Y,
Stroke = new SolidColorBrush(Colors.White),
StrokeThickness = 2,
};
_canvas!.Children.Add(line);
Lines.Add(new LineModel(startPoint, endPoint));
}
private void DrawPoint(PointModel point) {
if(_selectedPoints.Contains(point)) {
var toRemove = _canvas!.Children.OfType<Ellipse>().FirstOrDefault(e => e.Tag == point);
if(toRemove != null) {
_canvas.Children.Remove(toRemove);
}
// Remove the point from the selected points list
_selectedPoints.Remove(point);
}
else {
var ellipse = new Ellipse {
Width = 4,
Height = 4,
Fill = new SolidColorBrush(Colors.Red)
};
Canvas.SetLeft(ellipse, point.X - 2);
Canvas.SetTop(ellipse, point.Y - 2);
_canvas!.Children.Add(ellipse);
// Connect with the previous point if one exists
if(_selectedPoints.Count > 0) {
var lastPoint = _selectedPoints[^1];
DrawLine(lastPoint, point);
}
_selectedPoints.Add(point);
}
}
public List<Tuple<PointModel, PointModel>> GetLineData() {
LineData.Clear();
foreach(var line in Lines) {
LineData.Add(new Tuple<PointModel, PointModel>(line.Start, line.End));
}
return LineData;
}
private PointModel3D Create3DPoint(PointModel point, double z) {
return new PointModel3D(point.X, point.Y, z);
}
public List<Tuple<PointModel3D, PointModel3D, PointModel3D, PointModel3D>> Generate3DLines(double thickness) {
List<Tuple<PointModel3D, PointModel3D, PointModel3D, PointModel3D>> extrudedLines = [];
foreach(var line in LineData) {
var startBase = Create3DPoint(line.Item1, 0);
var endBase = Create3DPoint(line.Item2, 0);
var startTop = Create3DPoint(line.Item1, thickness);
var endTop = Create3DPoint(line.Item2, thickness);
extrudedLines.Add(new Tuple<PointModel3D, PointModel3D, PointModel3D, PointModel3D>(
startBase, endBase, endTop, startTop
));
}
return extrudedLines;
}
public void ExportSTL(string filePath, double thickness) {
GetLineData();
var extrudedLines = Generate3DLines(thickness);
// Validate extrudedLines before proceeding
if(extrudedLines.Count == 0) {
throw new InvalidOperationException("No 3D geometry created. Check the logic in Generate3DLines.");
}
var desinsFolder = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), NanoFlowFolder);
if(!Directory.Exists(desinsFolder)) {
Directory.CreateDirectory(desinsFolder);
}
var stlFilePath = Path.Combine(desinsFolder, filePath);
var stlContent = new StringWriter(CultureInfo.InvariantCulture);
stlContent.WriteLine("solid Model");
foreach(var rectangle in extrudedLines) {
var p1 = rectangle.Item1;
var p2 = rectangle.Item2;
var p3 = rectangle.Item3;
var p4 = rectangle.Item4;
AddRectangleToSTL(stlContent, p1, p2, p3, p4);
}
stlContent.WriteLine("endsolid Model");
File.WriteAllText(stlFilePath, stlContent.ToString());
}
private void AddRectangleToSTL(StringWriter stl, PointModel3D p1, PointModel3D p2,
PointModel3D p3, PointModel3D p4) {
// Define two triangles for the rectangle
AddTriangleToStl(stl, p1, p2, p3); // Triangle 1
AddTriangleToStl(stl, p1, p3, p4); // Triangle 2
}
private void AddTriangleToStl(StringWriter stl, PointModel3D v1, PointModel3D v2, PointModel3D v3) {
stl.WriteLine(" facet normal 0 0 0"); // Normal vector (set to 0 for simplicity)
stl.WriteLine(" outer loop");
stl.WriteLine($" vertex {v1.X} {v1.Y} {v1.Z}");
stl.WriteLine($" vertex {v2.X} {v2.Y} {v2.Z}");
stl.WriteLine($" vertex {v3.X} {v3.Y} {v3.Z}");
stl.WriteLine(" endloop");
stl.WriteLine(" endfacet");
}
#region UI Event Handlers
private void Canvas_PointerPressed(object sender, PointerRoutedEventArgs e) {
var position = e.GetCurrentPoint(_canvas).Position;
// Create the PointModel with the action(s) required
var currentPoint = new PointModel((int)position.X, (int)position.Y, DrawPoint);
// Set the previous point for line drawing
_previousPoint = currentPoint;
// Trigger the action to draw the point
DrawPoint(currentPoint);
}
private void Canvas_PointerMoved(object sender, PointerRoutedEventArgs e) {
if(_previousPoint != null && e.Pointer.IsInContact) {
var position = e.GetCurrentPoint(_canvas).Position;
// Create the PointModel dynamically with the actions
var currentPoint = new PointModel((int)position.X, (int)position.Y, DrawPoint);
// Draw a line between the points
DrawLine(_previousPoint, currentPoint);
// Update the previous point
_previousPoint = currentPoint;
}
}
private void Canvas_PointerReleased(object sender, PointerRoutedEventArgs e) {
// Reset the previous point to stop drawing
_previousPoint = null;
}
#endregion
}
}
Model
public partial class PointModel(int x, int y, Action<PointModel> selectAction) : ObservableObject {
public int X { get; set; } = x;
public int Y { get; set; } = y;
private const int GridSpace = 20;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(DisplayText))]
private bool isSelected;
private readonly Action<PointModel> selectAction = selectAction;
public string DisplayText => $"Point ({X / GridSpace}, {Y / GridSpace})";
partial void OnIsSelectedChanged(bool value) {
selectAction?.Invoke(this);
}
}
Dialog
Title="Guided Process"
Width="800"
Height="600"
PrimaryButtonText="Close">
<Grid>
<!-- Define Columns -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<!-- Left Side: GridView -->
<ColumnDefinition Width="3*" />
<!-- Right Side: Canvas -->
</Grid.ColumnDefinitions>
<!-- GridView for Point Selection -->
<GridView
Grid.Column="0"
ItemsSource="{x:Bind ViewModel.Points}"
SelectionMode="None">
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:PointModel">
<CheckBox
Content="{x:Bind DisplayText}"
IsChecked="{x:Bind IsSelected, Mode=TwoWay}" />
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
<!-- Canvas for Real-Time Drawing -->
<Canvas
x:Name="DrawingCanvas"
Grid.Column="1"
Width="378"
Height="378"
Background="#FF008000" />
</Grid>
</ContentDialog>
public sealed partial class GuidedProcessDialog : ContentDialog {
MainViewModel? ViewModel { get; set; }
public GuidedProcessDialog(MainViewModel ViewModel) {
InitializeComponent();
DataContext = ViewModel;
}
}
DI
public static ServiceProvider? Services { get; private set; }
private const string SyncfusionLicense = "MzczMDcxNEAzMjM4MmUzMDJlMzBrV3dmVEhRTFFJRmtZRGZUdzRqeEJmN3lOcU5wUkwzb2tBRnRuOVNyOHJzPQ==";
public App() {
SyncfusionLicenseProvider.RegisterLicense(SyncfusionLicense);
var services = new ServiceCollection();
services.AddSingleton<MainViewModel>();
services.AddTransient(p =>
new MainWindow(
p.GetRequiredService<MainViewModel>()));
Services = services.BuildServiceProvider();
InitializeComponent();
}
protected override void OnLaunched(LaunchActivatedEventArgs args) {
var window = Services!.GetRequiredService<MainWindow>();
window.Activate();
var hwnd = WindowNative.GetWindowHandle(window);
var windowId = Win32Interop.GetWindowIdFromWindow(hwnd);
var appWindow = AppWindow.GetFromWindowId(windowId);
var presenter = appWindow.Presenter as OverlappedPresenter;
presenter?.Maximize();
}
}
}