Reputation: 2762
I am new to WPF with mostly Winforms and Webforms experience. I am trying to learn WPF and one thing that I am trying to learn is creating beautiful UI in XAML. I have been trying to replicate the UI of StaffLynx application. The screen shots are present here
http://nextver.com/site/portfolio/stafflynx/
I cannot figure out in WPF, what will be the best way to create the placeholder container for the windows. In the link above you can see all the pages (views) are loaded in a custom shaped window. How can I create a re-usable window like this?
Should I just override the template of some control? In short I am not sure what is the right way to create a custom shaped window such as the one used by StaffLynx app.
Please advise.
Upvotes: 1
Views: 5283
Reputation: 2933
Maybe you should try using a ContentTemplateSelector. Here's a good example..
Here's a simple example that I made that may fit to your scenario. I have a window that has a border and inside the border is a ContentControl that has a template selector that will allow you to choose which view to display.
Here's the view:
Take a look at the local:MyContentTemplateSelector tag.
<Window x:Class="WpfApplication2.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:WpfApplication2"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="FirstTemplate">
<TextBlock Text="First" />
</DataTemplate>
<DataTemplate x:Key="SecondTemplate">
<TextBlock Text="Second" />
</DataTemplate>
<local:MyContentTemplateSelector FirstTemplate="{StaticResource FirstTemplate}" SecondTemplate="{StaticResource SecondTemplate}"
x:Key="mytemplateSelector" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border BorderThickness="1" BorderBrush="Red" Grid.Row="0">
<ContentControl ContentTemplateSelector="{StaticResource mytemplateSelector}" Content="{Binding SelectedViewModel}"/>
</Border>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="1">
<Button Command="{Binding SelectFirstViewModel}">Go to First Template</Button>
<Button Command="{Binding SelectSecondViewModel}">Go to Second Template</Button>
</StackPanel>
</Grid>
</Window>
Here's the view model:
public class MainVm : ViewModelBase
{
private FirstVm _FirstViewModel;
public FirstVm FirstViewModel
{
get { return _FirstViewModel; }
set { Set(ref _FirstViewModel, value); }
}
private SecondVm _SecondViewModel;
public SecondVm SecondViewModel
{
get { return _SecondViewModel; }
set { Set(ref _SecondViewModel, value); }
}
private ViewModelBase _SelectedViewModel;
public ViewModelBase SelectedViewModel
{
get { return _SelectedViewModel; }
set { Set(ref _SelectedViewModel, value); }
}
public ICommand SelectFirstViewModel
{
get
{
return new RelayCommand(() => { this.SelectedViewModel = FirstViewModel; });
}
}
public ICommand SelectSecondViewModel
{
get
{
return new RelayCommand(() => { this.SelectedViewModel = SecondViewModel; });
}
}
public MainVm()
{
FirstViewModel = new FirstVm();
SecondViewModel = new SecondVm();
SelectedViewModel = this.FirstViewModel;
}
}
These can be any view model that you have for your pages:
public class FirstVm : ViewModelBase
{
}
public class SecondVm : ViewModelBase
{
}
And here's the template selector. This is the the important part. Whenever you change the content of you ContenControl, in this case the content is bound to the SelectedViewmodel property of the MainVm, the SelectTemplate method in this class will be called. that's where you put the logic on which view or data template display.
public class MyContentTemplateSelector : DataTemplateSelector
{
public DataTemplate FirstTemplate { get; set; }
public DataTemplate SecondTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is FirstVm)
return FirstTemplate;
if (item is SecondVm)
return SecondTemplate;
return null;
}
}
It will look like something like these:
Upvotes: 1
Reputation: 23290
Oh, ok if you just want one of many examples how to do that sort of thing. Here's a quick example of how to cut a corner like that using Clip, give it a shot. Hope it helps.
<Window x:Class="NestedCutCornerWindowCWSO"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="NestedCutCornerWindowCWSO" Height="500" Width="800">
<Grid Height="350" Width="500">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Rectangle Fill="Navy"
Clip="M0,0 L485,0 500,15 500,100 0,100 z"/>
<TextBlock Foreground="White" FontSize="20" Text="Something" Margin="5"/>
<Rectangle Grid.Row="1"
Fill="White"
Stroke="Navy" StrokeThickness="2"/>
<TextBlock Grid.Row="1" Foreground="Black" FontSize="30"
HorizontalAlignment="Center" VerticalAlignment="Center"
Text="Some Other Stuff..."/>
</Grid>
</Window>
Upvotes: 0