WPF Window.Measure not setting the DesiredSize - wpf

I am trying to setup a printable view of my WPF window and I'm having a very hard time getting the content to size properly (surprise!).
Specifically, Measure doesn't seem to be setting the DesiredSize property of my window.
The basic approach I'm trying to take is that I've created a separate Window object (PrintView) that contains the controls I wish to print. I'm now programmatically attempting to instantiate the Window and then send it to the printer.
PrintView printView = new PrintView(m_Model.Clone() as MyModel);
printView.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
printView.Arrange(new Rect(new Point(0, 0), printView.DesiredSize));
thePrintDialog.PrintVisual(printView, "Strategy");//blank page every time
Unfortunately, printView.DesiredSize on line 3 there is always 0,0 after a call to .Measure, which causes the printed page to be blank, of course. I thought that .Measure is supposed to set that property. Interestingly, if stick a call to .ShowDialog() in there instead of the Measure & Arrange, it works properly, so as I understand it, that means the issue is that the layout pass has not occured. I just can't figure out how to force it to occur.
Any help would be greatly appreciated.
EDIT: POSTING CODE FOR PrintView
public PrintView(MyModel p_Model)
{
InitializeComponent();
TabSetContent1.Initialize(p_Model, p_Model, new Model.Workbook());
TabCompareContent1.Initialize(p_Model, new Model.Workbook());
}
And the XAML:
<Window x:Class="Cmi.Analytics.DecisionPathway.Ui.UserControls.Printing.PrintView"
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:components="clr-namespace:MyNamespace">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<components:TabSetContent x:Name="TabSetContent1" Grid.Row="0" IsPrintView="true" />
<components:TabCompareContent x:Name="TabCompareContent1" Grid.Row="1" IsPrintView="true" />
</Grid>
</Window>
The calls to Initialize for each of the usercontrols kick off lots of stuff for binding, etc... There's quite a bit of code involved. These exact same controls are used on the main.xaml page with the same calls to .Initialize() and everything works as expected.

Maybe a call to UpdateLayout, at the point where showing the dialog worked, might do the trick.

Related

How to disable resizing of user control in WPF

I have Usercontrol.I want to disable its resizing.
The usercontrol is:
<UserControl x:Class="DocumentUpload"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerikGrid="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.GridView"
xmlns:telerikGrid1="clr-namespace:Telerik.Windows.Controls.GridView;assembly=Telerik.Windows.Controls.GridView"
xmlns:telerikInp="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Input"
xmlns:telerikNav="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Navigation"
xmlns:telerikData="clr-namespace:Telerik.Windows.Data;assembly=Telerik.Windows.Data"
xmlns:telerik="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Height="auto" Width="auto" MaxWidth="520">
I got to know that there is property called
ResizeMode="NoResize"
.But it is not available in UserControl.Any suugestion?
You have Width and Height set to Auto, so I guess you want to allow the control to take as much space as needed but not more.
Also, UserControl is not resizing by itself, but depends upon the layout that it's part of.
So, the quickest way to fix your issue would be to set HorizontalAlignment="Left" and VerticalAlignment="Top". But you should consider the whole layout of your application and how the UC is affected by-/affects on other components of the UI.
Then the Parent property of your UserControl is holding the Window instance. Most of times, it will be NavigationWindow. Try the below code in loaded event of your UserControl and it will work.
((NavigationWindow)this.Parent).ResizeMode = ResizeMode.NoResize

Combobox Dropdown event triggers parent window Z index to change

I have a problem with a WPF business line application prototype that I do not know where to start to debug.
My Master Window (A) opens a "dialog" window using Dialog.Show(). The child window (B) has a combobox on it.
When the combobox is clicked (to expand and to show all the options) the entire second window (B) is hidden except the dropdownlist appearing from the combobox. The combobox isn't there, the window isn't there. Nothing is there except the dropdownlist and the master window behind it. If I click the master window then focus is once again set to window B and it shows as it should (because I set the Owner of window B to be window A).
To make it more interesting this bug is not consistent. It appears maybe 1 of 20 times I use the application, and when it starts appearing it can appear several times in a row and then stop happening again.
Possibly related is the fact that I think I have the same bug some times with MessageBoxes. When using MessageBox.Show() (Win forms msgbox) from a viewmodel when only the master window (A) is showing the box occationally appears behind the master window making it invisible for the user.
My application is using GalaSoft MvvmLight (if that could have anything to do with it) and quite a few telerik components. Other than that I am not sure what data to provide. I don't think anyone can tell me the source of the problem based on this information, but where would you start looking for the problem?
Update :
Good news! I have isolated the problem and found the combination of prerequisites for the phenomena to occur:
a) A component showing a PDF file is currently open anywhere withing the application.
b) A telerik component has been undocked and redocked.
I will include the code below, but I think the issue is buried deep within the RadDocking or WebBrowser component.
MainWindow
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void OpenWindowClick(object sender, RoutedEventArgs e)
{
var w = new TestWindow { Owner = this, DataContext = new TestViewModel()};
w.Show();
}
}
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerikDocking="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Docking"
x:Class="TelerikGridDockingVsBrowserVsWindowBug.MainWindow"
Title="MainWindow" Height="750" Width="925">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="200"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<telerikDocking:RadDocking Grid.Row="0">
<telerikDocking:RadSplitContainer>
<telerikDocking:RadPaneGroup>
<telerikDocking:RadPane Header="I make bugs combined with a webbrowser showing a pdf document">
<TextBlock Text="1. Drag me and dock on the same or another location"/>
</telerikDocking:RadPane>
</telerikDocking:RadPaneGroup>
</telerikDocking:RadSplitContainer>
</telerikDocking:RadDocking>
<Button Grid.Row="1" Click="OpenWindowClick" Content="2. Open window" Height="50" Margin="0,20"/>
<WebBrowser Grid.Row="2" Source="http://www.kb.nl/sites/default/files/docs/pdf_guidelines.pdf"/>
</Grid>
TestWindow :
public partial class TestWindow : Window
{
public TestWindow()
{
InitializeComponent();
}
}
<Window x:Class="TelerikGridDockingVsBrowserVsWindowBug.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestWindow" Height="150" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock> 3. Click on the combobox.</TextBlock>
<ComboBox Grid.Row="1" ItemsSource="{Binding Options}" SelectedItem="{Binding SelectedOption}" Height="50"></ComboBox>
<TextBlock Grid.Row="2"> This window will then disappear behind its owner</TextBlock>
</Grid>
TestWindow ViewModel:
public class TestViewModel
{
public List<string> Options { get; set; }
public string SelectedOption { get; set; }
public TestViewModel()
{
Options = new List<string> { "String1", "String2" };
SelectedOption = Options.First();
}
}
I have an open ticket with Telerik about this, so I will update here if I find out anything.
I have been in your situation before... you have an unexplained problem... it doesn't make any sense... you've tried everything that you can think of... in a last ditch effort to fix the problem, you throw it out to all the experienced users here... then nothing... no responses... no help.
The thing is that if you can't find and fix the problem with all of your code right in front of you, then how can we fix it without any code?
All I can suggest is for you to try to locate exactly where the problem originates. You can do this by commenting out sections of code and then running your solution to see if that has removed the problem or whether it still exists. The fact that your problem only occurs infrequently will make this stage even more tricky.
However, with perseverance, you should be able to narrow down where the problem arises. Once you have managed to exclude enough of your code, the last step is to see if you re-create it in a much smaller new WPF project. If you manage to get to this stage, please come back and show your reduced code... then, we may be able to help you further.

How to make a windows slide out using WPF( expression Blend 4and C#)

I am trying to figure out how to connect windows so the slide out using a small button from the left or right of a main window. What I am trying to do is create a main form with 2 windows connected to it. For one of the windows when the user presses a button on the main window it makes the window seem to slide out rather than pop up. Here is where I got the idea http://www.youtube.com/watch?v=CVlSj0yr3rg&feature=related ..The user then changes a value and the main windows is updated with new information. Honestly I have finished writing all my code and got everything working in Windows Forms in visual studio 2010 (with pop up windows).But I am thinking to make a more appealing gui WPF is the way to go, plus I like learning about it. If you have any forums, tutorials or general answers that would be great.
OK, so judging from the video you really want some kind of expander that opens and not a Window. A Window is an area with border, and the standard buttons and titlebar at the top.
This can be done with a grid with two columns. One is set to Auto width, one is set to * width. In the Auto sized one you can put your expanding content, and have your always visible content in the other.
The simple way to do this:
The Xaml
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StackOverflow"
x:Class="MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="7"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid x:Name="ExpandoGrid"/>
<Button Content="..." Grid.Column="0" HorizontalAlignment="Right" Margin="0" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5" Width="6" Height="40" Click="Button_Click"/>
<Grid x:Name="OtherContentGrid" Grid.Column="1" HorizontalAlignment="Left" Height="100" Margin="-7,0,0,0" VerticalAlignment="Top" Width="100"/>
</Grid>
</Window>
The Code-behind
Imports System.Collections.ObjectModel
Class MainWindow
Public Sub New()
InitializeComponent()
End Sub
Private Sub Button_Click(ByVal sender as Object, ByVal e as System.Windows.RoutedEventArgs)
If Me.ExpandoGrid.Width = 7 Then Me.ExpandoGrid.Width = 200 Else Me.ExpandoGrid.Width = 7
End Sub
End Class
This is by no means the complete way, or the best way. It is one of the simplest to implement though. A better way would be with a ViewModel which would handle the state of the expanded area, along with some animations to make it a smooth transition. If you want the sliding behaviour that is done in that video, animations are where it is at. If you are using Blend, then you have the right tool for animations.
Personally I would have this Windows ViewModel have a property (lets call it DrawerExpanded as Boolean) that a customized Expander would bind its IsExpanded property to. I would then create an open animation that sets the width of the content in the expander, and a close animation that sets the width to 0. Additionally, in each of these I would probably include setting the visibility and opacity to make the effect better and not weird. So lets say expand animation sets Width to 350 at .5 seconds, Visibility to visible at .5 seconds, and then opacity from 0 to 100 from .5 seconds to .7 seconds. That way the drawer slides out and the content fades quickly into view.
If you want a code example of that, you may have to give me a few mins.
I would really just take the easy/friendly route of creating Visual States in Expression Blend. There's basically just an "in state" and "out state", and an InteractionTrigger that allows the control to trigger the state change. Its awesome and extremely user friendly.
No code behind :) Hope it helps you!
As a bonus, you can easily add transition effects just like in a powerpoint. The xaml code gets pretty verbose, but working in Blend allows you to use the IDE to manage everything you add visually.
You can even use the Interaction Trigger to toggle between visibility states of the other controls, rather than writing converters, etc.

How to display a busy message over a wpf screen

Hey,
I have a WPF application based on Prism4. When performing slow operations, I want to show a busy screen. I will have a large number of screens, so I'm trying to build a single solution into the framework rather than adding the busy indicator to each screen.
These long running operations run in a background thread. This allows the UI to be updated (good) but does not stop the user from using the UI (bad). What I'd like to do is overlay a control with a spinning dial sort of thing and have that control cover the entire screen (the old HTML trick with DIVs). When the app is busy, the control would display thus block any further interaction as well as showing the spinny thing.
To set this up, I thought I could just have my app screen in a canvas along with the spinny thing (with a greater ZIndex) then just make the spinny thing visible as required.
This, however, is getting hard. Canvases do not seem well set up for this and I think I might be barking up the wrong tree.
I would appreciate any help. Thanks.
I have done this with a few programs. Here it is in a nutshell:
(This is easiest with MVVM. It has been so long since I used the codebehid for things like this I can't really say if there is a good way to do it.)
Create a border on your Main Window. I usually make it black with a 50% transparency. Add a grid to it, and put whatever you want inside to tell users it is busy. Size the border and the controls inside it to fill the screen.
Create a property on your main ViewModel for IsBusy as boolean. Initialize it as False. Bind the Visibility property of the Busy Border to that property.
Next, make a converter class for Busy(Boolean) to Visibility. Write the logic into that so that when value is True, Then visibility is Visible, when value is false, visibility is collapsed. ( http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx ).
Back on the border, add your converter to the binding. Add code to the ViewModel for each of your Pages or Views that calls back to that property and sets it to true when your other thread is busy.
Cory
Edit:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Grid>
<Border BorderBrush="Black" BorderThickness="1" Background="#80000000" Visibility="Collapsed">
<Grid>
<TextBlock Margin="0" TextWrapping="Wrap" Text="Busy...Please Wait" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="26.667" FontWeight="Bold" Foreground="#7EFFFFFF"/>
</Grid>
</Border>
<DockPanel x:Name="LayoutRoot">
<CheckBox Content="CheckBox" VerticalAlignment="Top"/>
<TextBlock TextWrapping="Wrap"><Run Text="TextBlock"/></TextBlock>
<UserControl x:Name="ViewViewView"/>
</DockPanel>
</Grid>
Look at this WPF toolkit with a busy indicator: https://github.com/xceedsoftware/wpftoolkit/wiki/BusyIndicator
I do this by simply displaying a dialog (so the user cannot interact with anything else and it will be displayed on top) then handle the Closing event (as the user could press Alt-F4) to see if the operation has finished otherwise I cancel the closing event:
myWaitWindow.ShowDialog(); // this can be borderless window with a spinny thing
void Window_Closing(object sender, CancelEventArgs e)
{
if(this.myOperation.IsRunning) // you would have to have some way to see when your operation has finished
e.Cancel = true;
}

New to WPF - What Control to Use / Getting Started?

I'm a WPF n0ob and I'm struggling with selecting the appropriate control to get the layout I want.
What I'm trying to do is draw a bunch of squares (virtual post-it notes) onto the screen. Each note is going to be a decent size (~150 pixels or so) and there could be hundreds of these notes. I want the whole thing to be scrollable so that you can resize the window however you like and the whole thing should be zoomable.
I've done this and it works.
But what I've done seems awfully wrong....
In the code, I'm dynamically creating post it notes and adding them to a giant canvas. I'm manually doing the math to determine where to place each note and how big the canvas should be. I added some labels at the top and had to go back and add a 'Y Offset' value to push all the squares down. I actually generate three different canvas controls and then add each one of them to a stack panel that is inside of a ScrollViewer. I added a scroll bar and set the the stack panel to zoom in and out as you adjust the bar.
It 'works', but I feel like I'm really not using WPF the way it's meant to be used. I tried achieving the same thing with a grid, but the grid didn't seem to want to size itself appropriately.
Can someone tell me a 'better' way to achieve the same look?
Here's my Xaml code - as you can see; there isn't much to it....
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition />
</Grid.RowDefinitions>
<Slider x:Name="ZoomSlider" Minimum="0.01" Value="1" Maximum="2" Margin="0,0,0,6" />
<ScrollViewer x:Name="MyScroller" Grid.Row="1" HorizontalScrollBarVisibility="Visible" HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
<StackPanel x:Name="TicketsGrid" Background="White" HorizontalAlignment="Center">
</StackPanel>
</ScrollViewer>
</Grid>
And then here is what I'm doing in code (ugly!!!)
For Each myWorkItem As WorkItem In myWorkItems
Dim newRect As New Border
newRect.Width = TicketSizeX
newRect.Height = TicketSizeY
If myWorkItem.State.ToUpper.Contains("HOLD") Then
newRect.Background = New SolidColorBrush(Colors.Purple)
Else
newRect.Background = New SolidColorBrush(Color)
End If
newRect.CornerRadius = New System.Windows.CornerRadius(5)
newRect.BorderThickness = New System.Windows.Thickness(1)
newRect.BorderBrush = New SolidColorBrush(Colors.Black)
Dim myPanel As New StackPanel
newRect.Child = myPanel
Dim lblTitle As New Label
lblTitle.Content = myWorkItem.Id
lblTitle.FontWeight = System.Windows.FontWeights.Bold
Dim lblDesc As New TextBlock
lblDesc.Text = myWorkItem.Title
lblDesc.TextWrapping = TextWrapping.Wrap
myPanel.Children.Add(lblTitle)
myPanel.Children.Add(lblDesc)
newRect.SetValue(Canvas.LeftProperty, CType(((TicketCount Mod TicketsXPerUser) * TicketStepX) + (xOffset * TicketStepX * TicketsXPerUser), Double))
newRect.SetValue(Canvas.TopProperty, CType(((Math.Floor((TicketCount / TicketsXPerUser)) * TicketStepY)) + NameLabelHeight, Double))
myCanvas.Children.Add(newRect)
TicketCount += 1
Next
MyCanvas.Width = (TicketStepX * TicketsXPerUser) * myTFS.SharedCodeTeam.Count
MyCanvas.Height = (CType(((Math.Floor((MaxTicket / TicketsXPerUser)) + 1) * TicketStepY), Double))
TicketsGrid.Children.Add(MyCanvas)
ScrollViewer with an ItemsControl inside.
Bind the ItemsSource property of the ItemsControl to an ObservableCollection<PostIt> (where PostIt is a plain old CLR object with all the info that goes on the post it).
Add a DataTemplate to the ItemsTemplate property of the ItemsControl
Add controls to the DataTemplate and bind them directly to an instance of PostIt
Add PostIt instances to the ObservableCollection<PostIt> in your code.
The ScrollViewer handles all scrolling. That's all you need.
The ItemsControl is designed to bind against a collection. For each instance in the collection, it figures out what DataTemplate to use, creates a copy of the template, sets the root's DataContext to the instance it pulled from the collection, and adds the template to itself. It does this for each instance found in the collection.
In your codebehind, all you need to do is create a bunch of PostIts and add them to the collection. No godawful construction of UI elements like you're doing. Urgh.
If you can grasp this concept, you are a step away from understanding MVVM, the Model-View-Controller pattern in WPF. Read about it, try it out. Its a very simple way of making very complex applications with complex UI but with a minimum of code (and none of that crap you're doing currently).

Resources