Adding models/content to the HelixViewport3D in Helix 3D Toolkit - c#

I am trying to load and display a 3d model in the HelixViewport3D.
I can get as far as loading the model (OBJ), but I cannot understand how to get the model into the viewport.
Here's a screenshot of my WPF form...
The viewprot is named as 'myView' - I thought I could hook into that to add my model, but I don't see anything obvious to use.
Here's my XAML of the form :
<Window x:Class="HelixTrial.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:HelixToolkit="clr-namespace:HelixToolkit.Wpf;assembly=HelixToolkit.Wpf"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid HorizontalAlignment="Left" Height="250" Margin="241,37,0,0" VerticalAlignment="Top" Width="250">
<HelixToolkit:HelixViewport3D x:Name="myView" ZoomExtentsWhenLoaded="True">
<!-- Remember to add light to the scene -->
<HelixToolkit:SunLight/>
<!-- You can also add elements here in the xaml -->
<HelixToolkit:GridLinesVisual3D Width="8" Length="8" MinorDistance="1" MajorDistance="1" Thickness="0.01"/>
</HelixToolkit:HelixViewport3D>
</Grid>
</Grid>
And here is the code for my form.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Media3D;
using HelixToolkit.Wpf;
namespace HelixTrial
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ObjReader CurrentHelixObjReader = new ObjReader();
Model3DGroup MyModel = CurrentHelixObjReader.Read("C:/Users/Roger/Desktop/cube/cube.obj");
// Now how to load it into the viewport... ?
}
}
}
You can see where I am stuck. Could someone help get me on track please.

After some experimenting I found the solution.
I added the following to my XAML :
<ModelVisual3D x:Name="foo"/>
The trick was to give it a name, ie 'foo' for example. The XAML will now look like this :
<Window x:Class="HelixTrial.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:HelixToolkit="clr-namespace:HelixToolkit.Wpf;assembly=HelixToolkit.Wpf"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid HorizontalAlignment="Left" Height="250" Margin="241,37,0,0" VerticalAlignment="Top" Width="250">
<HelixToolkit:HelixViewport3D x:Name="myView" ZoomExtentsWhenLoaded="True">
<!-- Remember to add light to the scene -->
<HelixToolkit:SunLight/>
<ModelVisual3D x:Name="foo"/>
<!-- You can also add elements here in the xaml -->
<HelixToolkit:GridLinesVisual3D Width="8" Length="8" MinorDistance="1" MajorDistance="1" Thickness="0.01"/>
</HelixToolkit:HelixViewport3D>
</Grid>
</Grid>
Then in the code (as per what I posted in my original question above) you can do this :
ObjReader CurrentHelixObjReader = new ObjReader();
Model3DGroup MyModel = CurrentHelixObjReader.Read("C:/Users/Roger/Desktop/cube/cube.obj");
// Display the model
foo.Content = MyModel;
Easy when you find out how ;)

# This is my code which works fine #
<Window x:Class="Helix_Car_Demo.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:Helix_Car_Demo"
xmlns:helix="http://helix-toolkit.org/wpf"
mc:Ignorable="d"
Background="Black"
WindowState="Maximized" WindowStyle="None"
Title="MainWindow" Height="350" Width="525">
<Grid>
<helix:HelixViewport3D Name="viewport3D" ZoomExtentsWhenLoaded="True" MouseDoubleClick="viewport3D_MouseDoubleClick">
<helix:SunLight/>
</helix:HelixViewport3D>
</Grid>
Here is my .cs File
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ModelVisual3D device = new ModelVisual3D();
device.Content = getModel("hearse.3ds");
viewport3D.Children.Add(device);
}
public Model3D getModel(string path)
{
Model3D device = null;
try
{
viewport3D.RotateGesture = new MouseGesture(MouseAction.LeftClick);
ModelImporter import = new ModelImporter();
device = import.Load(path);
}
catch (Exception e)
{ }
return device;
}
}
}

Related

Getting and setting large amount of text data in clipboard

I'm making simple tool app in C#, I have a textbox and I want to paste some text (around 300k lines), but this makes the app unresponsive. I waited like 10 minutes and nothing moved forward.
Is there some way to handle paste and copy operations on large data sets in smoother way? For example pasting and copying same amount of data in Windows Notepad takes just few seconds.
I use
Windows.ApplicationModel.DataTransfer.Clipboard.GetContent()
and at this app hangs.
Example Code
Xaml
<Window
x:Class="App2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="1" Grid.RowSpan="1">
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0" Grid.RowSpan="1" Margin="5" VerticalScrollBarVisibility="Visible" >
<TextBox VerticalAlignment="Stretch" HorizontalAlignment="Stretch" IsReadOnly="False" Header="Query Result" Text='{x:Bind pasteResult, Mode=TwoWay}' PlaceholderText="Paste results here" TextWrapping="Wrap"/>
</ScrollViewer>
</Grid>
</Window>
cs file
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace App2
{
/// <summary>
/// An empty window that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainWindow : Window
{
public string pasteResult;
public MainWindow()
{
this.InitializeComponent();
}
}
}
As #Simon Mourier mentioned in the comments, the performance problem is not related to the clipboard, but the TextBox control processing that amount of data.
So, let me give you another option using the ItemsRepeater which comes with virtualization built-in. (In my laptop) it takes approx. 3 secs to show 500K lines of text from the clipboard.
MainWindow.xaml
<Window
x:Class="ClipboardTests.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"
mc:Ignorable="d">
<Grid RowDefinitions="Auto,*">
<StackPanel
Grid.Row="0"
Orientation="Horizontal">
<Button
Click="PasteButton_Click"
Content="Paste" />
<Button
Click="ClearButton_Click"
Content="Clear" />
<TextBlock
x:Name="MessageTextBox"
VerticalAlignment="Center" />
</StackPanel>
<ScrollViewer Grid.Row="1">
<ItemsRepeater x:Name="TextItemsRepeaterControl" />
</ScrollViewer>
</Grid>
</Window>
MainWindow.xaml.cs
using Microsoft.UI.Xaml;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel.DataTransfer;
namespace ClipboardTests;
public sealed partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private static async Task<IEnumerable<string>> GetTextLinesFromClipboard()
{
DataPackageView dataPackageView = Clipboard.GetContent();
if (dataPackageView.Contains(StandardDataFormats.Text) is true)
{
string text = await dataPackageView.GetTextAsync();
string[] lines = text
.ReplaceLineEndings()
.Split(Environment.NewLine, StringSplitOptions.None);
return lines;
}
return Enumerable.Empty<string>();
}
private async void PasteButton_Click(object sender, RoutedEventArgs e)
{
Stopwatch stopwatch = Stopwatch.StartNew();
IEnumerable<string> lines = await GetTextLinesFromClipboard();
this.TextItemsRepeaterControl.ItemsSource = lines;
stopwatch.Stop();
this.MessageTextBox.Text = $"Pasted {this.TextItemsRepeaterControl.ItemsSourceView.Count} items in {stopwatch.Elapsed.TotalSeconds} s.";
}
private void ClearButton_Click(object sender, RoutedEventArgs e)
{
this.TextItemsRepeaterControl.ItemsSource = null;
}
}

How to bind properties both ways WPF

I am a reeeally noob beginner WPF developer, and getting the hang of c#.
I am creating an app, where I need a knob Button and a TextBox Display, where the knob adjusts the text from the display, and the display, if text is changed, updates the knob position.
Inage example of my application
I've managed to create the Knob Button, which spins when clicked and dragged, and also managed to bind it's value to the TextBox, it displays the value perfectly, but I can't make the TextBox Text update the Knob's position, which is defined by Angle variable (from the RotateTransform thing), the code is as follows:
<UserControl x:Class="quaselaeuespero.VolumeControl"
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"
xmlns:local="clr-namespace:quaselaeuespero"
mc:Ignorable="d"
d:DesignHeight="154" d:DesignWidth="148">
<Grid>
<Image Name="aPorradoknob" Source="Knob.png" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<RotateTransform Angle="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:VolumeControl}}, Path=Angle}"/>
</Image.RenderTransform>
</Image>
</Grid>
</UserControl>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace quaselaeuespero
{
/// <summary>
/// Interaction logic for VolumeControl.xaml
/// </summary>
public partial class VolumeControl : UserControl
{
public static readonly DependencyProperty AngleProperty =
DependencyProperty.Register("Angle", typeof(double), typeof(VolumeControl), new UIPropertyMetadata(0.0));
public double Angle
{
get { return (double)GetValue(AngleProperty); }
set { SetValue(AngleProperty, value); }
}
public VolumeControl()
{
InitializeComponent();
this.Angle = 120;
this.MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseLeftButtonDown);
this.MouseUp += new MouseButtonEventHandler(OnMouseUp);
this.MouseMove += new MouseEventHandler(OnMouseMove);
}
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(this);
}
private void OnMouseUp(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(null);
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (Mouse.Captured == this)
{
// Get the current mouse position relative to the volume control
Point currentLocation = Mouse.GetPosition(this);
// We want to rotate around the center of the knob, not the top corner
Point knobCenter = new Point(this.ActualHeight / 2, this.ActualWidth / 2);
// Calculate an angle
double radians = Math.Atan((currentLocation.Y - knobCenter.Y) /
(currentLocation.X - knobCenter.X));
this.Angle = radians * 180 / Math.PI;
// Apply a 180 degree shift when X is negative so that we can rotate
// all of the way around
if (currentLocation.X - knobCenter.X < 0)
{
this.Angle += 180;
}
if(this.Angle >= -90 && this.Angle <= -45)
{
this.Angle = 270;
}
if (this.Angle >= -45 && this.Angle <= 0)
{
this.Angle = 1;
}
this.Angle = Math.Round(this.Angle, 1);
}
}
}
}
The Knob is <VolumeControl/> and Display is <DisplayBPM/>, in the main Window I tried to bind them both:
<Window x:Class="quaselaeuespero.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:quaselaeuespero"
mc:Ignorable="d"
Title="MainWindow" Height="540" Width="960">
<Grid>
<Grid.Background>
<ImageBrush ImageSource="Background.png"/>
</Grid.Background>
<local:VolumeControl x:Name="Knobão" Margin="123,240,675,111" RenderTransformOrigin="0.5,0.5" Angle="{Binding ElementName=BPMDisplay, Path=BPM, UpdateSourceTrigger=Explicit}"/>
<local:DisplayBPM x:Name="BPMDisplay" BPM="{Binding ElementName=Knobão, Path=Angle, UpdateSourceTrigger=Explicit}" Margin="68,153,656,274" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</Window>
The following is the code for DisplayBPM:
<UserControl x:Class="quaselaeuespero.DisplayBPM"
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"
xmlns:local="clr-namespace:quaselaeuespero"
mc:Ignorable="d"
d:DesignHeight="79
" d:DesignWidth="229"
Name="Display">
<Grid Margin="0">
<TextBox x:Name="BPMTexto" Text="{Binding ElementName=Display, Path=BPM}" HorizontalAlignment="Right" Margin="0,0,4,0" Width="222" BorderBrush="{x:Null}" SelectionBrush="{x:Null}" Foreground="#FFCF1D1D" FontSize="80" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontFamily="DS-Digital" RenderTransformOrigin="0.5,0.5" CaretBrush="#FFCF1D1D">
<TextBox.Background>
<ImageBrush ImageSource="Display BPM.png" Stretch="Uniform"/>
</TextBox.Background>
</TextBox>
</Grid>
</UserControl>
and the DisplayBPM.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace quaselaeuespero
{
/// <summary>
/// Interaction logic for DisplayBPM.xaml
/// </summary>
public partial class DisplayBPM : UserControl
{
private void BPMTexto_TextChanged(object sender, EventArgs e)
{
BPM = Convert.ToDouble(BPMTexto.Text);
}
public static readonly DependencyProperty BPMProperty =
DependencyProperty.Register("BPM", typeof(double), typeof(DisplayBPM), new UIPropertyMetadata(0.0));
public double BPM
{
get { return (double)GetValue(BPMProperty); }
set { SetValue(BPMProperty, value); }
}
public DisplayBPM()
{
InitializeComponent();
BPM = 1;
}
}
}
The problem is that BPM (variable from DisplayBPM, from which TextBox gets its input) doesn't seem to be changed, and if it is changed, it is not changing Angle (variable from RotateTransform that determines the Knob position). Can anyone help me? I know there are probably tons of basic problems, it would really help me if you could explain them to me. Thank you so much!
To start, making a custom user control that has Dependency Properties is not the solution for every problem in WPF.
WPF Apps are primarily architected with MVVM: Model - View - ViewModel
With that stated for your specific need I would keep the VolumeControl as that is the correct way to create custom UserControls that have custom DependencyProperties
I would then delete the DisplayBPM class as it is not needed.
I would setup a ViewModel to interact between your controls that contains a single BPM string property.
Here is an example ViewModel I would use:
public class MainWindowViewModel : INotifyPropertyChanged
{
private string _bpm;
public string BPM
{
get => _bpm;
set
{
_bpm = value;
RaisePropertyChanged(nameof(BPM));
}
}
public void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
public event PropertyChangedEventHandler PropertyChanged;
}
As a side note, I would suggest reading up on INotifyPropertyChanged
as there are many libraries out there that you can use to help with
WPF and MVVM
I would then setup the Window with the VolumeControl and just a TextBox to hold the BPM value. Both of these should have a {Binding BPM, Mode=TwoWay} so that you pass the BPM value between controls.
You can then decide on the TextBox binding if you want the value to take as the user is typing or after the user leaves the field (usually with the Tab key). To have the value update the VolumeControl as the user is typing have UpdateSourceTrigger=PropertyChanged in the binding.
See my example here:
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.Background>
<ImageBrush ImageSource="Background.png"/>
</Grid.Background>
<local:VolumeControl
x:Name="Knobão"
Margin="123,240,675,111"
RenderTransformOrigin="0.5,0.5"
Angle="{Binding BPM, Mode=TwoWay}" />
<TextBox
Text="{Binding BPM, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="68,153,656,274"
MinWidth="222"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<TextBox.Background>
<ImageBrush
ImageSource="Display BPM.png"
Stretch="Uniform" />
</TextBox.Background>
</TextBox>
</Grid>
If you are not familiar with how ViewModels and DataContext work within WPF I would recommend reading up on that as that is the primary way to setup an MVVM architecture for WPF apps.

Need help to refresh a brush of a visual child object (a Border) within viewport2DVisual3D object class

I am using the Planerator control which works great. The only problem is that the brush of the Border object I added inside it doesn't get changed. It rotates well, but the brush seems frozen. I tried many things, but no can do.
Control link: https://github.com/pauldotknopf/WPF-MediaKit/blob/master/SampleApplication/Controls/Planerator.cs
I search a lot on many help sites, including stackoverflow. Here is what I tried without any success;
Important: I am working from code behind, not XAML.It worked fine in XAML
this.UpdateLayout();
this.InvalidateMeasure();
this.InvalidateVisual();
this.InvalidateArrange();
((UIElement)_originalChild).UpdateLayout();
var child = VisualTreeHelper.GetChild(viewport2DVisual3D, 0);
((UIElement)child).UpdateLayout();
((UIElement)child).InvalidateMeasure();
((UIElement)child).InvalidateVisual();
((UIElement)child).InvalidateArrange();
From this code;
// Interactive frontside Visual3D
Viewport2DVisual3D frontModel = new Viewport2DVisual3D() { Geometry = simpleQuad, Visual = _logicalChild, Material = frontMaterial, Transform = xfGroup };
Now, after testing, I am suspecting that once the object is added inside Viewport2DVisual3D has a child, color & brushes don't get refreshed anymore, but it will until/before that point. See "Visual = _logicalChild" above.
I have no error message, it rotates well, but the brush and color of my border don't get updated if I change the color.
Here is my working markup;
<Window
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:TestPlaneratorInXAML"
xmlns:Planerator="clr-namespace:Planerator;assembly=Planerator" x:Class="TestPlaneratorInXAML.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Planerator:Planerator x:Name="aPlaneratorControl" Height="100" VerticalAlignment="Top" Width="100">
<Border BorderBrush="Black" BorderThickness="5" HorizontalAlignment="Center" Height="100" VerticalAlignment="Top" Width="100" CornerRadius="5" Background="Black"/>
</Planerator:Planerator>
<Button x:Name="ChangeBackground" Content="Change background" HorizontalAlignment="Left" VerticalAlignment="Top" Width="160" PreviewMouseDown="ChangeBackground_PreviewMouseDown"/>
</Grid>
</Window>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace TestPlaneratorInXAML
{
/// <summary>
/// Logique d'interaction pour MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ChangeBackground_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
((Border)aPlaneratorControl.Child).Background = Brushes.Red;
}
}
}

XAML code won't compile

Please can someone be of help. Below is my XAML code that won't compile
<Window x:Class="XAMLCalendar.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:XAMLCalendar"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel Orientation = "Horizontal">
<!-- Create a Calendar that displays dates through
Januarary 31, 2015 and has dates that are not selectable. -->
<Calendar Margin = "20" SelectionMode = "MultipleRange"
IsTodayHighlighted = "false"
DisplayDate = "1/1/2015"
DisplayDateEnd = "1/31/2015"
SelectedDatesChanged = "Calendar_SelectedDatesChanged"
xmlns:sys = "clr-namespace:System;assembly =mscorlib">
<Calendar.BlackoutDates>
<CalendarDateRange Start = "1/2/2015" End = "1/4/2015"/>
<CalendarDateRange Start = "1/9/2015" End = "1/9/2015"/>
<CalendarDateRange Start = "1/16/2015" End = "1/16/2015"/>
<CalendarDateRange Start = "1/23/2015" End = "1/25/2015"/>
<CalendarDateRange Start = "1/30/2015" End = "1/30/2015"/>
</Calendar.BlackoutDates>
<Calendar.SelectedDates>
<sys:DateTime>1/5/2015</sys:DateTime>
<sys:DateTime>1/12/2015</sys:DateTime>
<sys:DateTime>1/14/2015</sys:DateTime>
<sys:DateTime>1/13/2015</sys:DateTime>
<sys:DateTime>1/15/2015</sys:DateTime>
<sys:DateTime>1/27/2015</sys:DateTime>
<sys:DateTime>4/2/2015</sys:DateTime>
</Calendar.SelectedDates>
</Calendar>
</StackPanel>
</Grid>
</Window>
Below is the c# partial class behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace XAMLCalendar
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
{
var calendar = sender as Calendar;
// ... See if a date is selected.
if (calendar.SelectedDate.HasValue)
{
// ... Display SelectedDate in Title.
DateTime date = calendar.SelectedDate.Value;
this.Title = date.ToShortDateString();
}
}
}
}
Below is the error messages I get
Severity Code Description Project File Line Suppression State
Error  Unknown build error, ''clr-namespace:System;assembly =mscorlib' mapping URI is not valid. Line 6 Position 9.' XAMLCalendar C:\Users\mypc\documents\visual studio 2017\Projects\XAMLCalendar\XAMLCalendar\MainWindow.xaml line 6 
Severity Code Description Project File Line Suppression State
Error  The URI "clr-namespace:System;assembly =mscorlib" is not a valid namespace identifier. XAMLCalendar C:\Users\mypc\documents\visual studio 2017\Projects\XAMLCalendar\XAMLCalendar\MainWindow.xaml line 20 
Severity Code Description Project File Line Suppression State
Error  The name "DateTime" does not exist in the namespace "clr-namespace:System;assembly =mscorlib". XAMLCalendar C:\Users\mypc\documents\visual studio 2017\Projects\XAMLCalendar\XAMLCalendar\MainWindow.xaml  line 31 
Severity Code Description Project File Line Suppression State
Error  The name "DateTime" does not exist in the namespace "clr-namespace:System;assembly =mscorlib". XAMLCalendar C:\Users\mypc\documents\visual studio 2017\Projects\XAMLCalendar\XAMLCalendar\MainWindow.xaml  line 32 
........and the same errors as the one directly above, up to line 37
Please can someone tell me why it won't compile. I've tried adding mscorlib reference to my project, but it won't let me. Saying "This component is already automatically referenced by the build system" 
Also there's a wriggle line under xmlns:sys  in the Calender element in the XAML above. When I hover my mouse over it, the intellisense says "The URI "clr-namespace:System;assembly =mscorlib" is not a valid namespace identifier
Cheers. Am using Microsoft visual studio 2017 community
Just remove the extra whitespace in namespace declaration.
<Window x:Class="XAMLCalendar.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:XAMLCalendar"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel Orientation = "Horizontal">
<!-- Create a Calendar that displays dates through
Januarary 31, 2015 and has dates that are not selectable. -->
<Calendar Margin = "20" SelectionMode = "MultipleRange"
IsTodayHighlighted = "false"
DisplayDate = "1/1/2015"
DisplayDateEnd = "1/31/2015"
SelectedDatesChanged = "Calendar_SelectedDatesChanged"
xmlns:sys = "clr-namespace:System;assembly=mscorlib">
<Calendar.BlackoutDates>
<CalendarDateRange Start = "1/2/2015" End = "1/4/2015"/>
<CalendarDateRange Start = "1/9/2015" End = "1/9/2015"/>
<CalendarDateRange Start = "1/16/2015" End = "1/16/2015"/>
<CalendarDateRange Start = "1/23/2015" End = "1/25/2015"/>
<CalendarDateRange Start = "1/30/2015" End = "1/30/2015"/>
</Calendar.BlackoutDates>
<Calendar.SelectedDates>
<sys:DateTime>1/5/2015</sys:DateTime>
<sys:DateTime>1/12/2015</sys:DateTime>
<sys:DateTime>1/14/2015</sys:DateTime>
<sys:DateTime>1/13/2015</sys:DateTime>
<sys:DateTime>1/15/2015</sys:DateTime>
<sys:DateTime>1/27/2015</sys:DateTime>
<sys:DateTime>4/2/2015</sys:DateTime>
</Calendar.SelectedDates>
</Calendar>
</StackPanel>
</Grid>
</Window>

Embedding XpsDocument PowerPoint slide shows into a WPF DocumentViewer

I've recently had a go at embedding a PowerPoint file as an XpsDocument in WPF.
It is a simple WPF application in which I embed a DocumentViewer property into my MainWindow.xaml grid:
<Window x:Class="PowerPoint2.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:PowerPoint2"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DocumentViewer
Name="DocumentviewPowerPoint"
VerticalAlignment="Top"
HorizontalAlignment="Left" />
</Grid>
To create the document bound to "DocumentviewPowerPoint" I convert the PowerPoint file that has been opened into Xps format and bind this variable to the XAML property mentioned earlier:
using System;
using System.IO;
using System.Windows;
using System.Windows.Xps.Packaging;
using Microsoft.Office.Core;
using Microsoft.Office.Interop.PowerPoint;
using Application = Microsoft.Office.Interop.PowerPoint.Application;
namespace PowerPoint2
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
const string powerPointFile = #"c:\temp\ppt.pptx";
var xpsFile = Path.GetTempPath() + Guid.NewGuid() + ".pptx";
var xpsDocument = ConvertPowerPointToXps(powerPointFile, xpsFile);
DocumentviewPowerPoint.Document = xpsDocument.GetFixedDocumentSequence();
}
private static XpsDocument ConvertPowerPointToXps(string pptFilename, string xpsFilename)
{
var pptApp = new Application();
var presentation = pptApp.Presentations.Open(pptFilename, MsoTriState.msoTrue, MsoTriState.msoFalse,
MsoTriState.msoFalse);
try
{
presentation.ExportAsFixedFormat(xpsFilename, PpFixedFormatType.ppFixedFormatTypeXPS);
}
catch (Exception ex)
{
MessageBox.Show("Failed to export to XPS format: " + ex);
}
finally
{
presentation.Close();
pptApp.Quit();
}
return new XpsDocument(xpsFilename, FileAccess.Read);
}
}
}
This all works well enough when running the program, showing the Xps document embedded into the WPF:
My question is how can I further modify my code in order to display the PowerPoint not just as a series of scrollable slides as shown, but as an actual slide show? I would like to make further updates to enable the user to navigate to the following slide on each mouse click - like a 'proper' presentation. My problem is that I am unfamiliar with the usage of the XpsDocument Apis - I don't know if it's a case of using these to achieve what I want or is it in the settings properties of the presentation variable that gets converted to the Xps format.
I managed to solve the particular problem I was interested in.
Please refer to this blog posting for a detailed explanation:
Controlling DocumentViewer methods and properties using MVVM
The solution addresses the problem of being able to enable individual PowerPoint slides (converted to xps file format) to occupy the WHOLE of the available windows space by invoking the relevant combination of DocumentViewer methods.
On pressing the screen button to invoke the RelayCommand, the following combination of DocumentViewer API calls in the MainWindowViewModel.cs class was observed to work:
public ICommand Command
{
get
{
return _command ?? (_command = new RelayCommand(
x =>
{
DocumentViewer = MainWindow.GetInstance();
const string powerPointFile = #"c:\temp\ppt.pptx";
var xpsFile = Path.GetTempPath() + Guid.NewGuid() + ".xps";
var xpsDocument = ConvertPowerPointToXps(powerPointFile, xpsFile);
FixedFixedDocumentSequence = xpsDocument.GetFixedDocumentSequence();
DocumentViewer.Document = FixedFixedDocumentSequence;
DocumentViewer.GoToPage(1);
DocumentViewer.FitToMaxPagesAcross(1);
WindowState = WindowState.Maximized;
DocumentViewer.FitToMaxPagesAcross(1);
}));
}
}
And to obtain the DocumentViewer instance itself? I also need to update the MainWindow.xaml.cs to get it to return the instance of the DocumentViewer object:
using System.Windows.Controls;
namespace DocumentView
{
public partial class MainWindow
{
private static DocumentViewer _docViewer;
public MainWindow()
{
InitializeComponent();
_docViewer = DocumentViewPowerPoint;
}
public static DocumentViewer GetInstance()
{
return _docViewer;
}
}
}
Where DocumentViewPowerPoint is the name given to the DocumentViewer in the MainWindow.xaml:
<Window x:Class="DocumentView.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:DocumentView"
mc:Ignorable="d"
WindowState="{Binding WindowState, Mode=TwoWay}"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<DocumentViewer
Grid.Row="0"
Document="{Binding FixedFixedDocumentSequence}"
Name="DocumentViewPowerPoint"
VerticalAlignment="Top"
HorizontalAlignment="Left" />
<Button
Grid.Row="1"
Command="{Binding Command}"
Width="70" Height="30" Content="Press" />
</Grid>

Categories