My MainPage.xaml is a pivot page with 3 PivotItems. Currently it is loading all of the necessary stuff for each of the PivotItems on the MainPage constructor. This is bad because it loads a lot of stuff that are not necessary.
Reading here and here suggests that I only load the first PivotItem and after it loads, load the rest of the items. Specifically :
Improve the performance of the pivot application by loading Pivot control content on-demand as opposed to loading everything at startup. One solution is to take the content from each PivotItem control and convert into UserControls. You can then subscribe to the LoadingPivotItem event on the root pivot control. Next, in the event handler, instantiate the proper UserControl and set it as the PivotItem content.
If I follow the suggestion:
private void OnLoadingPivotItem(object sender, PivotItemEventArgs e)
{
if (e.Item.Content != null)
{
// Content loaded already
return;
}
Pivot pivot = (Pivot)sender;
if (e.Item == pivot.Items[0])
{
e.Item.Content = new Page1Control();
}
else if (e.Item == pivot.Items[1])
{
e.Item.Content = new Page2Control();
}
else if (e.Item == pivot.Items[2])
{
e.Item.Content = new Page3Control();
}
}
I should use create class PageXControl ? Should it inherit somehow from main-page class ?
How do i take the content from each PivotItem control and convert into UserControls ?
Thanks
Extracting the content of your PivotItems into UserControls is actually very simple. First, create a new UserControl for each of your PivotItems. Then move the content of the PivotItems from the PivotItem into the UserControls. Then you create the controls in the OnLoadingPivotItem method as you specified. I have a created a small project on GitHub to show you how to do this. See: https://github.com/ErikSchierboom/pivotcontentdemo
As you can see, I derived the UserControls from a base class as they are semantically the same. However, this is by no means necessary, it is fine to just inherit from UserControl.
I prefer this approach over the approach where the PivotItems themselves are extracted into custom controls.
You could create your own Pivot items, which would inherit from PivotItem. I have put together a sample, based on the default Pivot project in VS, which splits out the two Pivot items into their own classes :-
http://www.smartmobiledevice.co.uk/projects/PivotItemUserControlSample.zip
Related
First part of my question
I am creating a UWP app which uses the NavigationView class and need a little help as to building a good approach as to how I manage control creation in code behind (not in a markup language).
I decided as opposed to adding controls in the markup language xaml that I would create a list of controls in C# and add these control as part of my NavView_Loaded method.
I understand there are benefits to simply working with xaml to create the UI. However, I intend to have various different circumstances under which controls are visible or collapsed and I find it easier to maintain the status of controls by working in code behind or in C# using my mainpage class.
Currently, I have something like the following
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
public ObservableCollection<NavigationViewItem> SetNavViewItems()
{
var navitems = new ObservableCollection<NavigationViewItem>
{
new NavigationViewItem()
{
Content = "Home",
Icon = new SymbolIcon(Symbol.Home),
Tag = "home",
Visibility = Visibility.Visible,
},
new NavigationViewItem()
{
Content = "Documents",
Icon = new SymbolIcon(Symbol.Document),
Tag = "documents",
Visibility = Visibility.Visible,
},
new NavigationViewItem()
{
Content = "Library",
Icon = new SymbolIcon(Symbol.Library),
Tag = "library",
Visibility = Visibility.Visible,
}
};
return navitemsHome;
}
private void NavView_Loaded(object sender, RoutedEventArgs e)
{
navitems = SetNavViewItems();
foreach (var navitem in navitems)
{
NavView.MenuItems.Add(navitem);
}
}
}
As I understand it, in this example I have used a strongly typed collection in order to contain a collection of NavigationViewItem's. My issue here is that I wish to create a collection, list or arraylist of various types of controls (i.e. NavigationViewItemHeader, NavigationViewItem, NavigationViewList, NavigationViewItemSeparator).... and I'm not sure what is most appropriate; a list, a collection (weakly typed), an arraylist or if there is a better option.
To round out my explanation.
I then have a separate list (of strings) which contains all of the navigation item tags which I use to test conditions and set whether a corresponding control is visible or not.
Second part of my question
One other UI control I'm struggling with which may or may not be fully implemented as part of the NavigationView class, is expanding an Item or Header to display a list of sub items. My current understanding is that NavigationViewItem is the most appropriate control to use as the main heading/item. The sub items should be using the NavigationViewList. I can then write a method for setting the visibility of the NavigationViewList controls which is triggered when the user clicks on the corresponding NavigationViewItem.
Third and final part
Whenever I create a control in my NavigationView (i.e. a stack panel), it appears to automatically create a NavigationViewItem with the content stack panel which has the default style (i.e. height). I expect that this is intended and any control created in the NavigationView inherets from the NavigationViewBase. Frustratingly I seem to have difficult displaying multiple rows of a stack panel or grid which inherets from NavigationViewBase. Can anyone shed some light? Is this in my imgaination or is there something important to understand when creating a control in the NavigationView class.
Any help much appreciated!!!
Thanks!
I have a custom control (let's say MyContainer) that simply is a ScrollViewer with a Canvas inside.
I'm able to add controls to MyContainer like in a Canvas but in XAML designer this controls aren't movable like in a normal Canvas; they can't be moved with the mouse.
Here's the MyContainer code:
[ContentProperty("Children")]
public class MyContainer : ScrollViewer, IAddChild
{
private Canvas _innerCanvas;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public UIElementCollection Children
{
get { return _innerCanvas.Children; }
}
public MyContainer()
{
this._innerCanvas = new Canvas();
this.Content = _innerCanvas;
this.Loaded += MyContainer_Loaded;
}
void MyContainer_Loaded(object sender, RoutedEventArgs e)
{
_innerCanvas.Height = this.ActualHeight;
_innerCanvas.Width = this.ActualWidth;
}
void IAddChild.AddChild(object value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
UIElement uie = value as UIElement;
if (uie == null)
{
throw new ArgumentNullException("value");
}
_innerCanvas.Children.Add(value as UIElement);
}
void IAddChild.AddText(string text)
{
;
}
}
Where am I wrong?
PS: please avoid replies like "don't use editor, use XAML code only"; I need to make a User Control usable via graphic interface.
I think that you did not choose the correct base class. In WPF there are certain extensibility points that you should use for certain types of UI elements and I guess that the designer is hard-wired to these classes.
The different types of UI Elements are:
Visuals: they usually derive from FrameworkElement and their purpose is to display something that the user normally does not interact with (e.g. a text block).
Controls: they represent something that the user can interact with, like buttons, check boxes, text boxes, scroll viewers, etc. They usually derive from Control or ContentControl.
Panels: their purpose is to layout other UI Elements, Grid or StackPanel are examples. They all derive from the Panel base class.
Items controls: they usually provide selection for a number of items. ListBox, ComboBox, and TreeView are examples for them. All of them derive from ItemsControl.
Another important thing is that ContentControls and ItemsControls can display any object, not only those that can render themselves. They use the WPF Data Templating mechanism for that (the default is calling ToString on a non-renderable object and putting the resulting string in a TextBlock).
According to your code, I would assume that you either want to implement a panel or an items control. For panels, you should know about the Measure - Arrange - Render cycle of WPF and how you can use it to layout the panel's children.
Implementing an items control is a little bit harder because essentially an items control uses items that wrap the actual content of each displayed object (e.g. ListBoxItem), a panel to layout these items, an items container generator to dynamically create the child items, and of course you can use styles and templates. Most of the items controls also incorporate a scroll viewer. If you want to learn more about items controls, I strongly encourage you to read the "Items Controls: A to Z" blog series by Dr. WPF.
I haven't tried it out but I'm sure if you choose the correct base class to extend from, then you can use your control with the designer properly.
On the main page of my app I have a grid with 6 x 4 columns and rows of buttons.
I want to move one of these buttons to the middle and then scale it larger using RadControls by Telerik.
I can do this easily however when I do the button is shown behind all the other buttons on the grid and I can't seem to make it come to the front.
Any help would be much appreciated.
The order that items were added to a panel/grid determines what control is above another. Looking around it looks like you have two options:
Change the Canvas.ZIndex for the button you want to be on top.
Yes it seems odd as there is no canvas, but it works for any panel or grid.
Remove and re-add the child from the parent grid so that it was last. I found a nice snippet of code here posted by "CleverCoder" : http://forums.silverlight.net/post/63607.aspx
//Originally posted by CleverCode - http://forums.silverlight.net/post/63607.aspx
public static void PushToTop(this FrameworkElement element)
{
if (element == null) throw new ArgumentNullException("element");
var parentPanel = element.Parent as Panel;
if (parentPanel != null)
{
// relocate the framework element to be the last in the list (which makes it "above" everything else)
parentPanel.Children.Remove(element);
parentPanel.Children.Add(element);
parentPanel.UpdateLayout();
}
}
First off, I'm new to WPF and C# so maybe the issue I have is really easy to fix. But I'm kinda stuck at the moment.
Let me explain my problem.
I have a WPF Window and two usercontrols (Controls and ContentDisplayer).
The usercontrol Controls, wich contains some buttons, is added in the XAML of the Window.
Nothing special here.
Window.XAML
<nv:Controls/>
Now, what I want to do is when a user is pressing a button in Controls, ContentDisplayer needs to be added to the Scatterview I have in my Window.
I solved the problem by adding the buttons to the Window, and not using the usercontrol Controls. But this is not what I want.
Window.XAML.CS
private static void Button_ContactChanged(object sender, ContactEventArgs e)
{
object ob = Application.LoadComponent(new Uri(
"NVApril;component\\XAML\\ContentDisplayer.xaml",
System.UriKind.RelativeOrAbsolute));
//Set a unique name to the UserControl
string name = String.Format("userControl{0}",
SurfaceWindow1_Scatterview.Items.Count);
UserControl userControl = ob as UserControl;
userControl.Name = name;
//Add the new control to the Scatterview
SurfaceWindow1_Scatterview.Items.Add(userControl);
SurfaceWindow1_Scatterview.RegisterName(name, userControl);
}
So the real question is: How do I add a usercontrol to the Window by pressing a button in an other usercontrol?
Thanks,
Toner
At the top of the window xaml add
xmlns:d="clr-namespace:SomeNamespace.Usercontrols"
where you these exist already, you can choose the namespace of your control from the intellesence list.
Then where you want to place the control type:
<d:yourusercontrolhere params />
and your usercontrols can be added there.
Within Controls expose an event that is fired when you want to add a new control.
public event EventHandler AddControl;
private void RaiseAddControl()
{
if (AddControl!= null)
{
AddControl(this, EventArgs.Empty);
}
}
Now sink that event in your Window
yourControl.AddControl += ContactChanged
In your window, it sounds like you need to add the event to the instances of Controls.
<local:ContentDisplayer>
...
<nv:Controls AddControl="ContactChanged"/>
...
Then in your ContactChanged event handler you can instantiate a new Controls control and add it to whatever collection you're using like in your Button_ContactChanged event handler above.
Let me know if you need further clarification.
I have no idea what you are trying to do your example,
So you have a control defined thus:
public partial class somecontrolname : UserControl
With your corresponding Xaml file
All you need to do to add it in code to your window is firstly you need a LayoutRoot such as Grid control in the window then just
[mylayoutcontrol].Children.Add(new somecontrolname());
Maybe I got wrong idea what you are trying to do, your example code doesn't make much sense to me, looks like you are trying to load the xaml source file
I'm rewriting an old application and use this as a good opportunity to try out C# and .NET development (I usually do a lot of plug-in stuff in C).
The application is basically a timer collecting data. It has a start view with a button to start the measurement. During the measurement the app has five different views depending on what information the user wants to see.
What is the best practice to switch between the views?
From start to running?
Between the running views?
Ideas:
Use one form and hide and show controls
Use one start form and then a form with a TabControl
Use six separate forms
Creating a bunch of overlaid panels is a design-time nightmare.
I would suggest using a tab control with each "view" on a separate tab, and then picking the correct tab at runtime. You can avoid showing the tab headers by putting something like this in your form's Load event:
tabControl1.Top = tabControl1.Top - tabControl1.ItemSize.Height;
tabControl1.Height = tabControl1.Height + tabControl1.ItemSize.Height;
tabControl1.Region = new Region(new RectangleF(tabPage1.Left, tabPage1.Top, tabPage1.Width, tabPage1.Height + tabControl1.ItemSize.Height));
What I do is to have a Panel where your different views will sit on the main form.
then create user controls for your different views.
Then when I want to switch between a'view' you dock it to Panel on the main form.. code looks a little like this.
i preffer this because you can then reuse your views, like if you want to open up a view in a tab you can dock your user controls inside tab pages.. or even inherit from
tabpage instead of usercontrol to make things a bit more generic
public partial class MainForm : Form
{
public enum FormViews
{
A, B
}
private MyViewA viewA; //user control with view a on it
private MyViewB viewB; //user control with view b on it
private FormViews _formView;
public FormViews FormView
{
get
{
return _formView;
}
set
{
_formView = value;
OnFormViewChanged(_formView);
}
}
protected virtual void OnFormViewChanged(FormViews view)
{
//contentPanel is just a System.Windows.Forms.Panel docked to fill the form
switch (view)
{
case FormViews.A:
if (viewA != null) viewA = new MyViewA();
//extension method, you could use a static function.
this.contentPanel.DockControl(viewA);
break;
case FormViews.B:
if (viewB != null) viewB = new MyViewB();
this.contentPanel.DockControl(viewB);
break;
}
}
public MainForm()
{
InitializeComponent();
FormView = FormViews.A; //simply change views like this
}
}
public static class PanelExtensions
{
public static void DockControl(this Panel thisControl, Control controlToDock)
{
thisControl.Controls.Clear();
thisControl.Controls.Add(controlToDock);
controlToDock.Dock = DockStyle.Fill;
}
}
Tabbed forms are usually good... but only if you want the user to be able to see any view at any time... and it sounds like you might not.
Separate forms definitely works, but you need to make sure that the switch is seemless...if you make sure the new form appears the same exact size and location of the old form, it will look like it thew same for with changing controls.
The method I often use is actually to pre-setup all my controls on individual "Panel" controls and then show and hide these panels as I need them. The "Panel" control is basically a control container... you can move the panel and all controls on it move relative. And if you show or hide the panel, the controls on it do the same. They are great for situations like this.
The method I often use is actually to
pre-setup all my controls on
individual "Panel" controls and then
show and hide these panels as I need
them.
Instead of making each view a panel within a single form you could make each view a UserControl. Then create a single form and write code to create and display the correct UserControl in the Form and to switch from one to the next. This would be easier to maintain because you will have a separate class for each view instead of a single Form class with 6 panels each with their own controls -- that seems difficult and error prone to maintain.
I would also check out Composite Application Guidance for WPF or Smart Client Software Factory