c# wpf layout reusability - c#

I'm trying to make a window layout usable from different windows.
As you can see from image, I've got a logo, a left vertical progress bar and two control buttons in the bottom part of the window (plus menu bar and status bar).
Those parts should be always the same in different windows, and play/stop should be interacting run-time with the common parts but also with parts build in the middle of the window ("part in each window different").
I can't understand what i should use for creating a standard layout callable from each window where I need it, made in a way were I can replace for each of those windows just the middle part.
Any tips? I probably just need to understand the way to go (sad to be c# wpf newbie)!

You can use a content control and then just switch the content
Master page for regions
This link has what you need. You can put the page templates in a separate file if you will be doing lots of content switching

If you create a user control with a <ContentPresenter> where you want the variable content to be, you can inject your own controls into the user control.
The user control would look like:
<UserControl>
<Grid>
<!-- Header Stuff -->
<ContentPresenter Name="MyContentPresenter" />
<!-- Footer Stuff -->
</Grid>
</UserControl>
In your windows, you'd have:
<Window>
<Grid>
<MyUserControl>
<MyUserControl.Content>
<!-- your window specific code here -->
</MyUserControl.Content>
</MyUserControl>
</Grid>
</Window>
You will need to expose a property called Content on your user control that returns/sets the Content property of the ContentPresenter element on the user control.
In the code-behind of the user control:
public object Content
{
get { return MyContentPresenter.Content; }
set { MyContentPresenter.Content = value; }
}

Related

Opening a subwindow as part of the MainWindow

Overview
Hey everyone, I'm working on a project that is a C# WPF desktop app to create and edit a complex system. Simply think of it as and editor that can put together a full description of a car with all it's subcomponents.
I want each different component of the car to have a separate editor window. Like select the painting on the car and tada a sidewindow appears where you can fully customize the car's paint. Then when you click on the engine, that same sidewindow get's replaced by a new editor about the car's engine.
Question
How can I make that editor window that I already created with xaml and codebehind to appear as a part of the MainWindow, embedded as a sidebar?
If possible, I would avoid any 3rd party libraries, but if there is no other 'clean' way of doing it then I'm open to suggestions in that area as well.
I have fully functional windows that I created with the designer, wrote all the code for it to work, now I just have to find a way to embed those into the MainWindow on a press of a button.
Thanks for any answers
If you want something to "part of the MainWindow", you should not create another window because a Window cannot be a child of another element.
What you probably want to do is to move the XAML markup and code-behind from your current subwindow into a UserControl. You can then put the UserControl(s) into an appropriate Panel in your MainWindow.
For example, if you want UserControl to appear a sidebar in the window, you could use a DockPanel to dock it to the right:
<DockPanel>
<Border DockPanel.Dock="Right" Background="Yellow">
<local:SidebarUserControl Margin="10" />
</Border>
<TextBlock>main content...</TextBlock>
</DockPanel>

navigation/load different views on WPF/MVVM

I am quite new to WPF development, and currently I am trying to use the MVVM on my application development. I have read a lot about MVVM navigation and switching views, but I can't find a solution for my current situation. Let's explain what it is:
First of all, I have my main View element, a Dockpanel, with some fixed areas, and a main "dynamic" area where the content should change, depending on actions:
<DockPanel>
<Label Content="Top Fixed element"/>
<StackPanel Orientation="Vertical" Height="auto" Width="150" DockPanel.Dock="Left">
<Label Content="SomeOptions"/>
<!-- some more elements -->
</StackPanel>
<Label DockPanel.Dock="Bottom" Content="Foot"/>
<ContentControl Content="{Binding CurrentMainViewElementViewModel}"/>
</DockPanel>
I have defined some DataTemplates that I would like to load in this ContentControl, here there is one of the Data Templates as example:
<Window.Resources>
<DataTemplate DataType="{x:Type ViewModel:FileLoaderVM}">
<View:FileLoaderView/>
</DataTemplate>
</Window.Resources>
This FileLoader (View and View Model are implemented, using the RelayCommand and the INotifyPropertyChanged) opens a dialog box after clicking a button, where after selecting a file it is opened and parsed, and show all the found elements inside a ListView with multiple selection(in this case, persons with their data).
What I want to do now is to load another user control in this ContentControl, when I click a button. This button is defined in my view model like this:
public ICommand LoadPersons
{
get { return new RelayCommand(param => this.loadSelectedPersons(), param => (SelectedPersons!=null && SelectedPersons.Any()));}
}
My question comes at this point, how can I modify the content of the ContentControl, loading another User Control instead of the current one directly from my view model (in this "this.loadSelectedPersons()")?
If this is not possible, how should I approach to solve this problem?
Next to this action, I want to show all the previously selected elements and manipulate in different possible ways (inserting in a DB, saving in another file and so on), and I have already for that the appropriate User Control, that I would like to show in my main view element in the ContentControl section, keeping the other elements as they are originally.
lets see if i get you right.
you have a mainviewmodel with a property (CurrentMainViewElementViewModel) bound to the ContentControl. your MainViewmodel set the FileLoaderVM to this Property. now you wanna show a "new/other" Viewmodel when a File is seleted in your FileLoaderVM?
why dont you simply expose a event from your FileLoaderVM and subscribe to this event in your MainViewModel? if you do so your MainViewModel can then set the "new/other" Viewmodel to the ContentControl
To change content of ContentControl you do not load another user control, but change value of CurrentMainViewElementViewModel (to which ContentControl.Content is bound) to a new ViewModel, which will load another UserControl (defined in DataTemplate same way as FileLoaderVM is).
This looks like a job for main ViewModel (where CurrentMainViewElementViewModel is located).
Easiest solution is to provide a method in that ViewModel
public Switch()
{
CurrentMainViewElementViewModel = SomeViewModel;
}
and call this method from FileLoaderVM.

Open WPF Window in StackPanel [duplicate]

I am currently writing a desktop application, but I cannot seem to get my head around what to use when redirecting someone to a new section of the application.
My options appear to be
Window
Page
UserControl
but I don't understand what the difference between them is, and when I should use each one.
Could someone explain the differences for me, and give an example of what situations/applications you may use each one for?
A Window object is just what it sounds like: its a new Window for your application. You should use it when you want to pop up an entirely new window. I don't often use more than one Window in WPF because I prefer to put dynamic content in my main Window that changes based on user action.
A Page is a page inside your Window. It is mostly used for web-based systems like an XBAP, where you have a single browser window and different pages can be hosted in that window. It can also be used in Navigation Applications like sellmeadog said.
A UserControl is a reusable user-created control that you can add to your UI the same way you would add any other control. Usually I create a UserControl when I want to build in some custom functionality (for example, a CalendarControl), or when I have a large amount of related XAML code, such as a View when using the MVVM design pattern.
When navigating between windows, you could simply create a new Window object and show it
var NewWindow = new MyWindow();
newWindow.Show();
but like I said at the beginning of this answer, I prefer not to manage multiple windows if possible.
My preferred method of navigation is to create some dynamic content area using a ContentControl, and populate that with a UserControl containing whatever the current view is.
<Window x:Class="MyNamespace.MainWindow" ...>
<DockPanel>
<ContentControl x:Name="ContentArea" />
</DockPanel>
</Window>
and in your navigate event you can simply set it using
ContentArea.Content = new MyUserControl();
But if you're working with WPF, I'd highly recommend the MVVM design pattern. I have a very basic example on my blog that illustrates how you'd navigate using MVVM, using this pattern:
<Window x:Class="SimpleMVVMExample.ApplicationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SimpleMVVMExample"
Title="Simple MVVM Example" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:HomeViewModel}">
<local:HomeView /> <!-- This is a UserControl -->
</DataTemplate>
<DataTemplate DataType="{x:Type local:ProductsViewModel}">
<local:ProductsView /> <!-- This is a UserControl -->
</DataTemplate>
</Window.Resources>
<DockPanel>
<!-- Navigation Buttons -->
<Border DockPanel.Dock="Left" BorderBrush="Black"
BorderThickness="0,0,1,0">
<ItemsControl ItemsSource="{Binding PageViewModels}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.ChangePageCommand,
RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding }"
Margin="2,5"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
<!-- Content Area -->
<ContentControl Content="{Binding CurrentPageViewModel}" />
</DockPanel>
</Window>
Window is like Windows.Forms.Form, so just a new window
Page is, according to online documentation:
Encapsulates a page of content that can be navigated to
and hosted by Windows Internet Explorer, NavigationWindow, and Frame.
So you basically use this if going you visualize some HTML content
UserControl is for cases when you want to create some reusable component (but not standalone one) to use it in multiple different Windows
All depends on the app you're trying to build. Use Windows if you're building a dialog based app. Use Pages if you're building a navigation based app. UserControls will be useful regardless of the direction you go as you can use them in both Windows and Pages.
A good place to start exploring is here: http://windowsclient.net/learn
We usually use One Main Window for the application and other windows can be used in situations like when you need popups because instead of using popup controls in XAML which are not visible we can use a Window that is visible at design time so that'll be easy to work with
on the other hand we use many pages to navigate from one screen to another like User management screen to Order Screen etc In the main Window we can use Frame control for navigation like below
XAML
<Frame Name="mainWinFrame" NavigationUIVisibility="Hidden" ButtonBase.Click="mainWinFrame_Click">
</Frame>
C#
private void mainWinFrame_Click(object sender, RoutedEventArgs e)
{
try
{
if (e.OriginalSource is Button)
{
Button btn = (Button)e.OriginalSource;
if ((btn.CommandParameter != null) && (btn.CommandParameter.Equals("Order")))
{
mainWinFrame.Navigate(OrderPage);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
That's one way of doing it We can also use a Tab Control instead of Fram and Add pages to it using a Dictionary while adding new page check if the control already exists then only navigate otherwise add and navigate. I hope that'll help someone
Most of all has posted correct answer. I would like to add few links, so that you can refer to them and have clear and better ideas about the same:
UserControl:
http://msdn.microsoft.com/en-IN/library/a6h7e207(v=vs.71).aspx
The difference between page and window with respect to WPF:
Page vs Window in WPF?

Change a section of a window upon click event

I have a treeview at the left side of the screen, and when I click on any of the TreeViewItem, I want the right side of the screen to change accordingly.
For example, clicking on 'Project' would display on the right half of the screen, a label for project name along with the project name in a text box, and a similar label-textbox pair for some other fields. Clicking on a sub-option of 'Project' such as 'Task 1' should change the right half of the screen such that instead of labels and textboxes for project name and details, it should now be for task name/details. Atm, I only care about label-textbox pairs but in the future I'll need some more sophisticated options, maybe buttons and tables.
What I thought of was to have a grid premade for each option, when I clicked on 'Project' there would be a grid which displays all the info for a Project. And when I then clicked on 'Task 1', the Project grid should be hidden and the Task grid should be displayed with the fields filled out.
Is this possible? What should I be using to create templates that I can then choose from?
Firoz already mentioned the important bit. A rough guess is that you're not using MVVM pattern, so to minimize the adaption effort, you could add a Content Control to your window and set the content of this control whenever a selection is made. You can put any User Control in there.
Using MVVM would mean you bind that Content Control to a property on your ViewModel (of type UIElement or UserControl) and set an instance whenever a bound selected values changes. Speaking of selected Value, I think the default TreeView is not really Binding-friendly, so you might end up with behaviours that do the binding for you.
What you are asking to do is quite easy and possible, but I don't think you are thinking quite big enough.
As your project grows and the number of different things that you want to show expands, then you are going to need to show and hide more and more controls. This is quite quickly going to get unmanageable. Instead think about some other controls deal with this, in some ways you are doing something very like a tabbed dialog, just with a hierarchical set of tabs.
A tabbed dialog has a panel and a set of tabs, when you click on each tab, the content of the panel changes. In fact you can create UserControls one for each specialised set of UI that you want to display, e.g. you could have a ProjectControl that displays all of your project textboxes, labels, buttons etc.
In addition WPF has this neat feature called DataTemplates, these define how a type of data should look when it is displayed. So if you where to have a
public class MyProject
{
public string Name {get;set;}
}
Then you could define
<DataTemplate DataType="{x:Type MyProject}>
<TextBox Text="{Binding Name}"/>
</DataTemplate>
And WPF will automatically convert the data into to its visual form if you set it as the content of the tab panel.
However this type of displaying content in a panel is not the only WPF control that does this. There is also something called a NavigationFrame, which also can be used wrapped into a Window as a NavigationWindow. This control provides you ways to navigate to the next Page to display. Pages can be just like the UserControls in a tabbed dialog, but can also be URIs, enabling you to link in content from the web if you wish. In addition you can call NavigateTo from other controls enabling you build much more usable interfaces.
I worked through the process of building a full windows control panel style interface in
http://alski.net/post/2012/01/11/WPF-Wizards.aspx
and http://alski.net/post/2012/01/13/WPF-Wizards-part-2-Glass.aspx
I've added later VS2012 style glows in
http://alski.net/post/2013/09/14/WPF-Re-creating-VS2012Office-2013-window-glow.aspx
And then released the entire source code as open source at
http://winchrome.codeplex.com/
This comes with support for embedding Navigation panels with
<WinChrome:SearchableNavigationWindow
x:Class="WinChrome.Win7Demo.MainWindow"
...
xmlns:WinChrome="clr-namespace:WinChrome;assembly=WinChrome"
Style="{StaticResource Win7NavigationWindow}">
<WinChrome:SearchableNavigationWindow.Navigation>
<view:Navigation x:Name="navigationTree"/>
</WinChrome:SearchableNavigationWindow.Navigation>
(Full source code)
Where the navigation window is embedded as, but can also be a TreeView.
<UserControl x:Class="WinChrome.View.Navigation" ...>
<ScrollViewer HorizontalScrollBarVisibility="Disabled" Padding="12,0"
VerticalScrollBarVisibility="Auto" >
<StackPanel>
<Button
Margin="0,12,0,0" Style="{StaticResource LinkNavigatorButtonStyle}"
Content="Home"
Command="{Binding
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Win7Demo:MainWindow}, AncestorLevel=1},
Path=GoHomeCommand}" />
</StackPanel>
</ScrollViewer>
(Full source code)

Changing content of Window (WPF)

I've created a simple WPF application which has two Windows. The user fills in some information on the first Window and then clicks Ok which will take them to the second Window. This is working fine but I'm trying to incorporate both Windows into a single Window so just the content changes.
I managed to find this Resource management when changing window content which seems like it is what I'm after. However, I've search for ContentPresenter but couldn't find much help for how I need to use it. For example, if I use a ContentPresenter, where do I put the existing XAML elements that are in the two Windows? I'm guessing the first Window will go into the ContentPresenter but the second one will need to be put somewhere for when it needs to be switched in.
Any help would be great. A simple working example would be even better.
TIA
A ContentPresenter is normally used when restyling existing controls. It is the place where the Content of a control is placed. Instead you should use a ContentControl, which is simply a control that has a content element. Alternatively, you could directly set the Content of your window.
You extract the contents of your two existing windows into two UserControls. Then you create a new Window which will host the contents. Depending on your business logic, you set the content of that window (or that window's ContentControl if you want additional "master" content) to either of those two UserControls.
EDIT:
As a starting point. This is not complete working code, just to get you started. Note that this is bad architecture; you should probably use a MVVM or similar approach once you get this running!
<Window>
<ContentControl Name="ContentHolder" />
</Window>
<UserControl x:Class="MyFirstUserControl" /> <!-- Originally the first window -->
<UserControl x:Class="MySecondUserControl" /> <!-- Originally the second window -->
In code behind of Window:
// Somewhere, ex. in constructor
this.ContentHolder.Content = new MyFirstUserControl;
// Somewhere else, ex. in reaction to user interaction
this.ContentHolder.Content = new MySecondUserControl;
I use ContentPresenter for snapping in content. In the window, I put something like this:
<ContentPresenter Content="{Binding MainContent}" />
In the view model, I have a property called MainContent of type object:
public object MainContent { get { return (object)GetValue(MainContentProperty); } set { SetValue(MainContentProperty, value); } }
public static readonly DependencyProperty MainContentProperty = DependencyProperty.Register("MainContent", typeof(object), typeof(SomeViewModel), new FrameworkPropertyMetadata(null));
Whatever you set MainContent to will show up in the window.
To keep the separation between view and view model, I typically set the MainContent property to another view model and use a data template to map that view model to a view:
<DataTemplate DataType="{x:Type viewmodels:PlanViewModel}">
<views:PlanView />
</DataTemplate>
I put that data template in some central resource dictionary along with a bunch of other view-model-to-view mappers.

Categories