Printing a WPF UserControl created in Code behind - c#

I have a UserControl that I instantiate in code behind and would like to print. When I print this UserControl the code prints a blank piece of paper. Why is this? My code is as follows
private void PrintCurrentTab(object sender, RoutedEventArgs e)
{
PrintDialog printDlg = new PrintDialog();
var child = MyMainWindowViewModel.SelectedTab.Content;
if (child is ScrollViewer)
{
child = (((ScrollViewer)child).Content);
}
if (printDlg.ShowDialog() == true)
{
var printControl = new PrintingTemplate();
printDlg.PrintVisual(printControl, "User Control Printing.");
}
}
My UserControl is as follows
<UserControl x:Class="MyApp.Views.PrintingTemplate"
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"
MinHeight="500"
MaxHeight="1000"
MinWidth="200"
MaxWidth="1000"
Height="1056"
Width="816">
<StackPanel>
<Grid>
<Image Source="..\Resources\Images\PrintLogo.jpg" Width="150" HorizontalAlignment="Right" Margin="20"/>
<Rectangle Fill="Black" Margin="10,40,150,0" Height="2"/>
</Grid>
<Grid Name="PrintingGrid"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Label Content="Printed By:"/>
<Label Name="PrintedBy"/>
<Label Content="Printed On:"/>
<Label Name="PrintedDate"/>
</StackPanel>
</StackPanel>
</UserControl>

I got a similar problem where I was able to print from some computers but not from one (only blank page), on a physical printer (working OK with XPS). I finally got a working solution here:
» https://social.msdn.microsoft.com/Forums/vstudio/en-US/9eb79e11-ee5a-4687-ad4c-a6d96276a8f4/printing-a-wpf-usercontrol?forum=wpf
UserControlToPrint.Measure(New Size(816, 1056))
UserControlToPrint.Arrange(New Rect(New Size(816, 1056)))
UserControlToPrint.UpdateLayout()
Regards,
François from Québec

perhaps the new in the following code is the culprit
if (printDlg.ShowDialog() == true)
{
var printControl = new PrintingTemplate();
printDlg.PrintVisual(printControl, "User Control Printing.");
}
try to get the handle to the current control rather than create a new

Have you debugged this at all? Your question seems incomplete, and I don't really know what you're trying to accomplish. I DO notice that an important step is missing. Here are some questions I have though:
Is MyMainWindowViewModel.SelectedTab.Content == null?
What is child's type?
What is the purpose of child = (((ScrollViewer)child).Content);--that's ugly
Actually why is any of the child code in there, its not being used!
Anyways, you can't print a control that hasn't gone through a layout pass. So now you might ask, "how do I force a control to be rendered?" Simple, like this:
if (printDlg.ShowDialog() == true)
{
var printableArea = new Size(printDlg.PrintableAreaWidth, printDlg.PrintableAreaHeight)
var printControl = new PrintingTemplate();
//Set the drawing dimensions/boundaries - notice (Acutal)Width/Height = 0
printControl.Measure(printableArea);
printControl.Arrange(new Rect(new Point(), printableArea);
//"Render"!
printcontrol.UpdateLayout();
//At this point you should see the (Acutal)Width/Height be > 0!
printDlg.PrintVisual(printControl, "User Control Printing.");
}

Related

How to add some of my code to xaml property ResizeMode= CanResizeWithGrip or whenever it is called

Hi at the begining of this question i want to say that i'm beginer and thing i've done here could prolly be done better but i'm still learnig. i want to set a value of some variable that contains the actual width of grid, and whenever i resize my window obviously this width change and I don't know how to access it. What i want to do ? Just want my progress bar to scale up or down when resizing
Here is some code
<Window x:Class="Lista6.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"
xmlns:local="clr-namespace:Lista6"
mc:Ignorable="d"
Title="MainPage" Height="650" Width="1000"
Background="#36393F"
ResizeMode="CanResizeWithGrip"
Icon="/img/Ikonka2.png"
WindowStyle="None">
///other xaml code
<ProgressBar Foreground="White"
Value="50"
BorderThickness="0"
Background="Gray"
Height="5"
Width="{Binding Path=ProgresBarWidth[0], Mode=OneWay}"/>
</StackPanel>
</Grid>
</Grid>
</Window>
ObservableCollection<double> width = new ObservableCollection<double> { };
public ObservableCollection<double> ProgresBarWidth
{
get
{
return width;
}
set
{
width = value;
}
}
public AppOperator()
{
width.Add(0);
}
private void ProgresbarWidthSetter()
{
MainPage mp = new MainPage();
width[0] = mp.MusicBar.Width;
}
Here as u can see i ve binded progres bar width to ObservColl property, and i want to call it when im resizing my window but i ve no idea how to do that.
Thanks for any help and wish u all good.

Howto add textboxes in runtime to a WPF Window in C#? [duplicate]

This question already has answers here:
Append a child to a grid, set it's row and column
(4 answers)
Closed 1 year ago.
I am learning algorithmics and C#, and I wanted to write a sudoku solver with some WPF interface.
I need 81 textboxes (one for each sudoku box) and I wanted to generate them with code and put them in array, instead of having 81 different objects.
I used the Visual Studio toolbox to drag and drop buttons in my main window. I also drag and dropped TextBoxes to get an idea how they would look like.
I don't find how to add the TextBoxes to the main Window, using a loop.
Here is the MainWindow.x.aml code :
<Window x:Class="SudokuPOO.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:SudokuPOO"
mc:Ignorable="d"
Title="Solveur de Sudoku" Height="260" Width="210">
<Grid>
<!--
<TextBox x:Name="T0" HorizontalAlignment="Left" Margin=" 10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="20"/>
<TextBox x:Name="T1" HorizontalAlignment="Left" Margin=" 30,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="20"/>
[ I DELETED STUFF HERE ]
-->
<Button Content="Résoudre" HorizontalAlignment="Left" Margin="10,210,0,0" VerticalAlignment="Top" Click="Resoudre"/>
<Button Content="Effacer tout" HorizontalAlignment="Left" Margin="75,210,0,0" VerticalAlignment="Top" Click="Effacer"/>
</Grid>
Here is the MainWindow.x.aml.cs I am trying to edit :
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent(); // Was already here.
GenerateTextBoxes(); // I added that manually.
}
public void GenerateTextBoxes()
{
TextBox[] TextBoxes = new TextBox[5];
for (int i = 0; i<=4; i++)
{
TextBox TBox = new TextBox();
TBox.Margin = new Thickness(10+20*i, 10, 0, 0);
TBox.Text = i.ToString();
TBox.Width = 20;
TBox.Height = 20;
// this.Controls.Add(TBox); // Doesn't work.
this.Content = TBox; // Trouble here.
TextBoxes[i] = TBox;
}
}
}
I tried with only 5 textboxes to understand what is happening.
This code runs, it displays the MainWindow, but with only one TextBox with "4" in it.
My guess is that
this.Content = Tbox;
replaces all content of the window with only one TBox.
How do I a just add the Tbox ?
The XAML files suggests that a "TextBox" is inside a "Grid" that is inside the "MainWindow", but "this.Grid" doesn't exist, neither "MainWindow.Grid".
I tried stuff like "LayoutRoot.Children.Add", "this.Controls.Add", "this.Grid.Add" and so on, nothing works. Almost all the code I can find online related to TextBox in C# uses "Windows Forms" and not "WPF" and doesn't work in my case (like how to define an array of textboxes in c#? ).
Give the root panel in the XAML markup a name:
<Grid x:Name="grid">
...and then add the textboxes to the panel's Children collection:
grid.Children.Add(TBox);
Also note that that there might be better panels to use for layout instead of mocking around with margins: https://learn.microsoft.com/en-us/dotnet/desktop/wpf/controls/panels-overview?view=netframeworkdesktop-4.8

C# WPF - Popup which doesn't get focused

Im simply trying to make a little popup which shows a message in the corner. This Popup shuld be at the top of every other Window which I achieved with "TopMost", but I can't seem to get the unfocusable thing to work...
My PopUp XAML:
<Window x:Class="message.Popup"
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:message"
mc:Ignorable="d"
Title="Popup" Height="129.808" Width="300" Focusable="False" Topmost="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="179*"/>
<ColumnDefinition Width="113*"/>
</Grid.ColumnDefinitions>
<Label x:Name="label" Content="" HorizontalAlignment="Left" Margin="10,40,0,0" VerticalAlignment="Top" Width="272" Grid.ColumnSpan="2"/>
</Grid>
How I call it (from annother Window):
private void textBox_TextChanged(object sender, TextChangedEventArgs e)
{
new Popup(textBox.Text).Show();
}
PopUp code:
public Popup(string text)
{
InitializeComponent();
label.Content = text;
}
you must define your Mainwindow as Owner of the Popup and center the StartupLocation Property. Something like this:
PopUpWindow.Owner = MainWindow;
PopUpWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
Or if you are calling it from another window:
PopUpWindow.Owner = this;
PopUpWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
However I must say: this is not MVVM, since you are storing text in the Window class, and I strongly recommend you start reading about MVVM.

UWP Moving Childs to Other Parent Problems

First of all I am new to UWP and I have already searched almost everywhere (using Google and Stackoverflow) for the answer but couldn't find the answer for my problem.
So, Here is the problem:
I planned to create a pixel paint app that has tab function like Edge (utilizing title bar) for UWP using Visual Studio 2017 and Target Sdk: Creators Update.
I wanted to move the custom title bar I made to the content view when the app in fullscreen condition.
I wanted to move from here (windows title bar, this is just the button XAML code, I'm not including the tab bar XAML code because it's a commercial project):
<Grid x:Name="btnMenuPlace1" Grid.Column="0">
<Grid x:Name="btnMenuPlaceContent" Background="{StaticResource SystemControlHighlightListAccentMediumBrush}">
<Button x:Name="btnMenu" FontFamily="Segoe MDL2 Assets" Content=""
Width="50" Height="50" Background="Transparent" Click="btnMenu_Click"/>
</Grid>
</Grid>
To here (user view):
<Grid x:Name="btnMenuPlace2" Grid.Column="0">
</Grid>
Both parent of those Grid is an another Grid using Grid.ColumnDefinitions like this:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
And here's my C# Code:
private void WindowSizeChanged(object sender, WindowSizeChangedEventArgs e)
{
var appView = ApplicationView.GetForCurrentView();
if (appView.IsFullScreenMode)
{
Utility.RemoveChild(btnMenuPlaceContent);
btnMenuPlace2.Children.Add(btnMenuPlaceContent);
Utility.RemoveChild(tabBarPlaceContent);
tabBarPlace2.Children.Add(tabBarPlaceContent);
}
else
{
Utility.RemoveChild(btnMenuPlaceContent);
btnMenuPlace1.Children.Add(btnMenuPlaceContent);
Utility.RemoveChild(tabBarPlaceContent);
tabBarPlace1.Children.Add(tabBarPlaceContent);
}
e.Handled = true;
}
And here is my Utility RemoveChild Code:
public static void RemoveChild(DependencyObject parent, UIElement child)
{
var parentAsPanel = VisualTreeHelper.GetParent(child);
if (parentAsPanel != null)
{
parentAsPanel.Children.Remove(child);
return;
}
var parentAsContentPresenter = parent as ContentPresenter;
if (parentAsContentPresenter != null)
{
if (parentAsContentPresenter.Content == child)
{
parentAsContentPresenter.Content = null;
}
return;
}
var parentAsContentControl = parent as ContentControl;
if (parentAsContentControl != null)
{
if (parentAsContentControl.Content == child)
{
parentAsContentControl.Content = null;
}
return;
}
}
This is my app looks like before entered the fullscreen mode:
So the problem is whenever the app entered the fullscreen mode, the child does move to the new parent, but the button is not there only the background color of the grid remaining and I can't click any of them (not a single click event work), take a look:
And when I switched back to not fullscreen view the proggressbar loading on the new tab not shown.
I don't know which one I did was wrong XAML or the C# code.
Any help would be appreciated.
P.S. I'm Indonesian, so maybe there is something wrong with my sentence, hopefully You are understand what I'm talking about.
There are somethings wrong with your code snippet. For example, RemoveChild method has two parameters but you only provide one when you invoking it. And without assign the parentAsPanel variable type, you cannot get the Children property.
Since the code is not completed, after code updated and add some other code needed I can run your code snippet correctly and cannot reproduce the issue above. Here is my completed testing code:
XAML
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<Grid x:Name="btnMenuPlace1" Grid.Column="0" Grid.Row="0">
<Grid x:Name="btnMenuPlaceContent" Background="{StaticResource SystemControlHighlightListAccentMediumBrush}">
<StackPanel Orientation="Horizontal">
<Button x:Name="btnMenu" FontFamily="Segoe MDL2 Assets" Content="" Width="50" Height="50" Background="Transparent" />
<!--<local:CustomTitleBar Width="200" Height="50"></local:CustomTitleBar>-->
</StackPanel>
</Grid>
</Grid>
<Grid x:Name="btnMenuPlace2" Grid.Column="1" Grid.Row="1"/>
<TextBlock Text="text" x:Name="txtresult"></TextBlock>
<Button x:Name="ToggleFullScreenModeButton" Margin="0,10,0,0" Click="ToggleFullScreenModeButton_Click">
<SymbolIcon x:Name="ToggleFullScreenModeSymbol" Symbol="FullScreen" />
</Button>
</StackPanel>
</Grid>
Code behind
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
Window.Current.SetTitleBar(btnMenuPlace1);
Window.Current.SizeChanged += Current_SizeChanged;
}
private void Current_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
var appView = ApplicationView.GetForCurrentView();
if (appView.IsFullScreenMode)
{
RemoveChild(btnMenuPlace1, btnMenuPlaceContent);
btnMenuPlace2.Children.Add(btnMenuPlaceContent);
}
else
{
RemoveChild(btnMenuPlace2, btnMenuPlaceContent);
btnMenuPlace1.Children.Add(btnMenuPlaceContent);
}
e.Handled = true;
}
public void RemoveChild(DependencyObject parent, UIElement child)
{
Grid parentAsPanel = VisualTreeHelper.GetParent(child) as Grid;
if (parentAsPanel != null)
{
parentAsPanel.Children.Remove(child);
return;
}
var parentAsContentPresenter = parent as ContentPresenter;
if (parentAsContentPresenter != null)
{
if (parentAsContentPresenter.Content == child)
{
parentAsContentPresenter.Content = null;
}
return;
}
var parentAsContentControl = parent as ContentControl;
if (parentAsContentControl != null)
{
if (parentAsContentControl.Content == child)
{
parentAsContentControl.Content = null;
}
return;
}
}
private void ToggleFullScreenModeButton_Click(object sender, RoutedEventArgs e)
{
var view = ApplicationView.GetForCurrentView();
if (view.IsFullScreenMode)
{
view.ExitFullScreenMode();
}
else
{
if (view.TryEnterFullScreenMode())
{
txtresult.Text = "full screen";
}
else
{
txtresult.Text = "no full screen";
}
}
}
}
My testing environment is OS build 15063. If you still have issues please provide the minimal reproduced project. You may just try to reproduce the issue on my testing demo. More details please reference the official sample.
Sorry it was My mistake, that above code I post is actually working (just some of the code wrongly copied, like for example the parameter on the utility code is not necessary).
The false is on it's parent, i forgot to add row definition on the second place (btnPlace2) parent.
Now it works and looks great now :)
Here is some picture of em:
On FullScreen Mode:
Thanks to anyone answering and voting this question up.
Best regards,
andr33ww

Make a UserCOntrol on a Page the same size as the MainWindow in WPF

I have a WPF application. It consists of:
A MainWindow which loads a Page which contains a UserControl.
The UserControl is simply a MediaElement with play/pause controls etc.
Here is the XAML for the UserControl:
<UserControl x:Class="InstallerToolkit.UserControls.UserControlVideoPlayer"
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="464">
<Grid Margin="0,0,0,0" Background="Black">
<StackPanel Margin="0,0,0,0" VerticalAlignment="Bottom">
<MediaElement Name="MediaElement" MediaOpened="Element_MediaOpened" LoadedBehavior="Manual" UnloadedBehavior="Stop"/>
<StackPanel DockPanel.Dock="Bottom" Background="DarkGray" HorizontalAlignment="Center" Orientation="Horizontal">
<Image Source="/Images/control_play.png" MouseDown="OnMouseDownPlayMedia" Margin="5" />
<Image Source="/images/control_pause.png" MouseDown="OnMouseDownPauseMedia" Margin="5" />
<Image Source="/images/control_stop.png" MouseDown="OnMouseDownStopMedia" Margin="5" />
<TextBlock Foreground="White" Margin="5" VerticalAlignment="Center"><Run Text="Seek To"/></TextBlock>
<Slider x:Name="timelineSlider" Thumb.DragStarted="DragStarted" Thumb.DragCompleted="DragCompleted" Margin="5" ValueChanged="SeekToMediaPosition" Width="70"/>
<TextBlock x:Name="lblProgressStatus" Margin="5"><Run Text="00:00"/></TextBlock>
<TextBlock x:Name="lblSepatator" Margin="5"><Run Text="/"/></TextBlock>
<TextBlock x:Name="lblTotalLength" Margin="5" RenderTransformOrigin="3.607,0.455"><Run Text="00:00"/></TextBlock>
<Image Source="/images/control_stop.png" Margin="145,0,0,0" MouseLeftButtonDown="Image_MouseLeftButtonDown" />
</StackPanel>
</StackPanel>
</Grid>
Here is the positon of my UserControl normally:
I have added a button to the UserControl to try and make it go the full size of the MainWindow.
WHen I click the fullscreen button I have an event on my page which does the following:
private void VideoPlayer_FullScreenSelected(object sender, EventArgs e)
{
var parentWindowWidth = ((System.Windows.Controls.Panel)(Application.Current.MainWindow.Content)).ActualWidth;
var parentWindowHeight = ((System.Windows.Controls.Panel)(Application.Current.MainWindow.Content)).ActualHeight;
Thickness margin = new Thickness(0,0,0,0);
VideoPlayer.Margin = margin;
VideoPlayer.Width = parentWindowWidth;
VideoPlayer.Height = parentWindowHeight;
}
When I do this I see the VideoPlayer appearing larger like so:
Note how it is the size of my Page but not the MainWindow which I want ot to be.
So then I have added an event to my Page which triggers a function in my MainWindow that tries to grab the MediaElement from my Page and make it fullscreen. But I dont know how to grab my UserCOntrol from here and make it the size I need.
How can I do this??
You are grabbing window content height and width which is page instead and not your window.
Instead of
var parentWindowWidth = ((System.Windows.Controls.Panel)
(Application.Current.MainWindow.Content)).ActualWidth;
var parentWindowHeight = ((System.Windows.Controls.Panel)
(Application.Current.MainWindow.Content)).ActualHeight;
you should use MainWindow height and width:
var parentWindowWidth = Application.Current.MainWindow.ActualWidth;
var parentWindowHeight = Application.Current.MainWindow.ActualHeight;
I found another way around this problem.
I created a new Window and made its size to be 1200x750. On this window I placed my VideoPlayer Usercontrol and made it full screen.
Thwn when I click the 'fullscreen' button I simply launch this new window and pass it the current position of my video to make it appear like its continuing playing. When this window is closed I pass the current video positon back again and continue from there.
private void VideoPlayer_FullScreenSelected(object sender, EventArgs e)
{
VideoPlayer.Pause();
//Get the current media position
_currentMediaPosition = VideoPlayer.CurrentPosition;
VideoFullScreenWindow fullScreenVideo = new VideoFullScreenWindow(_currentMediaPosition, _videoFile);
fullScreenVideo.ShowDialog();
TimeSpan pos = fullScreenVideo.Position;
VideoPlayer.SeekToPosition(pos);
VideoPlayer.Play();
}

Categories