I'm using Catel in my application and I have problem with changing screens.
I have a ribbon navigation and a ContentPresenter for a screen. When I click ribbon button, I change ActiveView property in my ViewModel
It looks like this:
<ContentPresenter Margin="5 5 5 0" Content="{Binding ActiveView, Converter={StaticResource ViewModelToViewConverter}}" />
ActiveView is a ViewModel of my UserControl for specific view.
The problem is, that everytime I change screen (click ribbon button), I have a lag ~100ms which is very irritating.
I have also tried with DataTemplates for ContentPresenter, but there is no Performance boost with it.
Is there a way of boot performance of this? Maybe a way to pre-construct view, and then only show it? (because right now View is being constructed everytime I click a ribbon button)
Of course I'm checking it on Release build (on debug there is much more lag) :)
Please check the performance considerations in the docs. A few hints:
Have you tried without a debugger attached?
Are there log listeners doing a lot of work?
Enable Api cop to see what features you are not using but are taking time. Then you can disable them.
Probably it's the control looking for the InfoBarMessageControl (which you can simply disable).
Related
I have a user control that has a list of items.
If an item is selected, I want to show/replace the view with a panel and some buttons and what not.
When the user has finished with this view by pressing a button or something, I want to revert back to the list again and continue the process.
Essentially, this is a wizard.
What to do?
Sorry, I forgot to mention that I am using MVVM.
Solution:
Thanks to all for the help. My test application wasn't working which prompted me to ask SO.
My test application wasn't working because I had missed the {x:type} in the DataTemplate.
To simply:
I created different datatemplates in the resources with the {x:Type}
My viewmodel:
contained a compositecollection of IWizardPageViewModel.
contained a currentPage property.
contained NextCommand/BackCommand to change the currentPage
I bind the currentPage property to the control and the datatemplates take over.
Because of the {x:Type} it wasn't working.
I don't know whether this is right or wrong, but it works and is mostly controlled by the viewmodel rather than triggers on the view.
Consider a list of usercontrols - one for each page of your wizard. The top level usercontrol (the wizard control) will own this list. For navigation, you can;
Have buttons on the top level wizard usercontrol. When pressed, these notify the children of the navigation so that they can finish their work or cancel the navigation. You will want a common interface for the pages. IWizardPage perhaps?
Use a routed commands to notify the wizard usercontrol http://msdn.microsoft.com/en-us/library/ms752308.aspx#Four_main_Concepts
You can use Triggers and Selectors to update the view (DataTemplate) based on user actions.
Let me know if you need code snippet for the same.
First thing that comes to my mind (and easiest) is to use Visibility property and bind it to some boolean flags in ViewModel that will indicate current UI state. Of course in this case you should apply a Converter to properly convert bool value to Visibility. There are dozens of examples of such kind of convertors.
But this is relevant only in for of small amount of such Controls. In case of really lots of UI elements that should be shown and replaced on a view it's better to use framework like Prism. From scratch it will be not so straightforward, but then you'll feel all power of flexibility.
In case you're not following MVVM culture (or you don't like having such backing properties) you can bind Visibility property of control A that should be shown to Booleaen property of element B which stands for show/hide logic. To make it clear:
<TextBlock x:Name="A" Visibility="{Binding IsChecked, ElementName=B, Converter={StaticResource boolToVisibilityConverter}}" Text="Some text."/>
<ToggleButton x:Name="B" IsChecked="False"/>
(I am trying to learn WPF using tutorials and documentation, and trying to develop a user interface for my backend-complete application while I do say. I've heard people say that the learning curve is quite steep. But sometimes I wonder whether what I'm trying to do is actually something that's hard to do in WPF, or if it's simple but I'm thinking in wrong terms, or if it's neither, it's quite simple but I just happen not to know how.)
Here's my current question. I wanted clicking that clicking some part of my UI will bring up a 'popup' where the user can enter more information. I would like a 'lightbox-style' popup, i.e. the popup is modal to the page, it darkens the rest of the page to become the center of attention, etc. These are seen commonly on Web sites.
A bit of searching led me to the WPF Popup control. I added it, put my content in, set the IsOpen property to True, and -- presto! A popup. Then I added an invisible Rectangle that covers my whole window, and set it to Visible as well when I want my popup to open. Great!
So now I wanted to do this dynamically, because sometimes I will be loading a record which will sometimes have a need to open another control (a UserControl) in a popup to edit its information. So I made myself a method called OpenPopup. But I can't seem to find a way to write this method using WPF. In Windows Forms I'd have written: (I use VB.NET)
Sub ShowPopup (form as Form, ctrl as Control)
'Create 'rect' as new dark rectangle control
'Z-order it to the top
'form.Controls.Add 'rect'
'form.Controls.Add ctrl
'Z-order 'ctrl' to the top
'Center 'ctrl'
'Set focus to it
End Sub
But with WPF I run into problems:
1) I can't add it to the WPF window, because it already has a child.
2) If that child is a Canvas, that's not too bad. I can detect that, and add it to the Canvas. I have to find some way to set its Left, Top etc. properties and Width and Height, since those do not seem to be properties of the Rectangle control but rather extended by the Canvas object -- in XAML they're called Cavnas.Top etc. but Intellisense is not showing them when I try to use it in code.
3) But if it's a StackPanel? Then my rectangle will just be stacked below the other controls! And not covering them! Is there a way around this?
4) And if the window contains only one control and no container control at all?
5) I think there were more problems I ran into. But let's start with these.
Thanks in advance for your help.
1) I can't add it to the WPF window, because it already has a child.
Ah, the evils of codebehind. The solution is not to add it to the visual tree, it is to place it in the visual tree, ready and waiting to pounce, but hide it from the user's view.
Here's a sample you can drop in Kaxaml that demonstrates the point. Set the Lightbox Grid's Visibility to Hidden to access the hidden content.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Viewbox>
<TextBox Text="SIMULATING CONTENT" />
</Viewbox>
<Grid x:Name="Lightbox" Visibility="Visible">
<Rectangle Fill="Black" Opacity=".5"/>
<Border
Margin="100"
Background="white"
BorderBrush="CornflowerBlue"
BorderThickness="4"
CornerRadius="20">
<Viewbox Margin="25">
<TextBox Text="SIMULATING LIGHTBOX"/>
</Viewbox>
</Border>
</Grid>
</Grid>
</Page>
2) (snip) Intellisense is not showing them when I try to use it in code.
Canvas.Top etal are Attached Properties. Attached Properties are extremely convenient and easy to use in XAML, but they are very confusing and hard to use from code. Another reason why codebehind is evil.
3) But if it's a StackPanel? Then my rectangle will just be stacked below the other controls! And not covering them! Is there a way around this?
I redirect you back to 1. There are also many other container controls in WPF. You should investigate them and observe how they control layout. For instance, my use of the Grid was not to make use of its ability to block off sections of UI for controls, but for its ability to layer controls ontop of each other and to stretch them out to their maximum available size for the available space (the viewboxes are just there to zoom the controls instead of stretch them).
4) And if the window contains only one control and no container control at all?
The root of a window would almost always be a container control. But you control that, so if you needed to add controls to the visual tree at runtime you could easily ensure the child of the window is a container control you could deal with.
5) I think there were more problems I ran into. But let's start with these.
No kidding. My number one suggestion for people in your situation is to drop what you're doing and learn about MVVM. The Model-View-ViewModel is a very simple way to code WPF applications that takes advantage of many of the features of WPF--databinding, templating, commands, etc. It allows you to code your logic not in codebehind (RETCH) but in easy to create and test classes.
As a new comer to WPF, I would like to clarify my approach to build a UI in WPF. I am using WPF with MVVM. My approach is to use a main window which contains user controls which can run several levels deep in the UI tree. For example, I have an editor in a window. Many items can be edited in the editor and the UI for each items are different, but the editor always shows an OK and Cancel button. So the main editor window with OK and Cancel can be shared between several editors. I am designing the app in such a way that the editor user control will just bind the view model for the item which is edited. So when designing the UI for editing individual items OK or Cancel Button is not pulled in, but simply put the item into the main editor which will provide the buttons. I am pretty sure I can handle the commands correctly with WPF command infrastructure.
If I can make it clear with some xaml here it is.Please dont mind the control placement itself, I mean to explain the basic idea of sharing the Common UI across many items.
<UserControl Name="EditorMainWindow">
<Grid>
<StackPanel>
<ItemsControl ItemsSource="{Binding ItemToBeEdited}">
</ItemsControl>
<Button Content="OK" Width="120" Command="{Binding SomethingforOK}" />
<Button Content="Cancel" Width="120" Command="{Binding SomethingforCancel}"/>
</StackPanel>
</Grid>
</UserControl>
The way I am doing it, the user interface tree can go several levels deep. I will be tremendously benefitted, because if the client ask to change the UI in one particular place, I need not got and change it in many places(provided it is shared).
As I am new to WPF I would like to know if there is any catch in this approach. Could you please tell me if this makes sense or not?
You can save yourself a lot of time. Catel already provides such a window:
DataWindow
It is fully ready for MVVM (Catel is also an MVVM framework) which supports dynamic nested user controls. The nice thing is that it also supports error handling out of the box, so as soon as an error occurs in the window template, the user will see the error in the InfoBarMessageControl.
I'm using "Microsoft Ribbon for WPF" and creating multiple RibbonTab. I cannot figure out a way to view/focus different tabs in the designer and it by default show the "Home" tab. To see design/xaml changes I made to tabs other than the "Home" tab, I have to debug the project every time and click through the tabs, which is not very convenient. Or I can command out the tab xaml I want to to ignore. Anyone body out there has a solution?
You can also use the SelectedIndex property on the Ribbon to set which tab is the currently selected tab (0 being the first tab, 1 being the second, etc.)
<ribbon:Ribbon SelectedIndex="0" />
The only way I have found is to set the Selector.IsSelected property to true. This will cause the tab to become visible at design time.
<ribbon:RibbonTab Selector.IsSelected="True" ...
I can't confirm this is working right now because my preview in general is not working properly, but this works in general in WPF when trying to hide something at design time only.
Include the namespace for blend
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
Then in the element you want to hide use d:IsHidden="True". This will only affect design time, which eliminates the problem of forgetting to change the selected index to the correct value before building.
FindAncestor RelativeSource only supports 'Self' and 'TemplatedParent',
but I have to bind the width of a popup to the width of the page.
Giving the page a name causes problems because sometimes it will
throw exceptions saying a control with that name is already present in the visual tree.
<Popup IsOpen="True"
Width="{Binding ElementName=BordPage, Path=Width}"
Height="{Binding ElementName=BordPage, Path=Height}">
Background information:
I'm using a SL4 navigation based application here. BordPage is a navigation page,
which I'm using multiple times within the application. So giving it a name in the page itself is not really a good idea,
but I don't know how else I can bind to the width and height of the page.
What I'm trying to do is have a black border (with opacity 0.8) cover the entire screen,
(including the controls of the MainPage). Then on top of that I want to display some other controls.
Since the application is touch controlled, providing the user with a ComboBox to select a value doesn't really work wel. Instead I want to show this black overlay window with a listbox taking up most of the screen so the user can simply touch the value he wants with a single click.
Update: I just realized I can use the ChildWindow class to do this.
But my original question remains.
My general solution for this problem is by writing a custom behavior. It's not a pure XAML solution but it gives you a lot more flexibility.
Create a behavior that searches up the VisualTree to find the right item and then have it set the width of the Popup correctly.
It may be a little more complicated than a straight binding but it avoids all the naming issues.
Put the following in the constructor of your control so you can avoid naming it:
DataContext = this;