I have created a BaseWindowView
and a BaseViewModel
in a self-defined framework which I'd like to use as a basis in all of my applications.
In the BaseViewModel
I have, for example, a method which allows me to add buttons. I can define a Command
, a ButtonImage
and a LabelString
. Here is the sample code for the call of this method:
AddButton(OpenAnyTabCommand, "../Images/image.png", "LabelString");
In my BaseWindowView
I have a RibbonMenue
where all of the RibbonButtons
that I have defined in the BaseViewModel
are shown:
<ItemsControl x:Name="CButtons" ItemsSource="{Binding Buttons}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel x:Name="ButtonStackPanel" Orientation="Horizontal">
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ribbon:RibbonButton
x:Uid="Button"
LargeImageSource="{Binding Path=ImageString}"
Label="{Binding Path=LabelString}"
Command="{Binding Path=ButtonCommand}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I have this in a sample project, and it works fine. Now I want to outsource the BaseWindowView
and the BaseViewModel
to a framework and use it from there.
My plan is: In each of my applications, I'd like to set the BaseWindowView
as the MainWindow
of my application. In this application itself I just want to have some UserControls
which should be shown as tabs in my BaseWindowView
. The buttons I've defined in the BaseViewModel
should call the defined Command
which opens a new tab and shows the ViewModel
behind this Command
.
So what is the best way to handle my problem? I know that there is no "classic inheritance" in XAML. Can I just do something like define the StartUpUri
in the App.xaml
to the framework view or is it "a little bit" trickier?
As an addition: I found that I can define the DataTemplate
for the TabItems
(which are UserControls
) in the App.xaml
like the following:
<DataTemplate DataType="{x:Type ViewModel:AnyViewModel}">
<view:TabItemAny/>
</DataTemplate>
@Sheridan: Here is the question about the BaseWindowView
.
Ok, so to start with, let's address using your BaseWindowView
as the MainWindow
:
First, in the App.xaml
file, remove the declaration of Startup
and StartupUri
properties from the Application
definition. Then in the App.xaml.cs
class, add a startup handler:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
BaseWindowView baseWindowView = new BaseWindowView();
baseWindowView.Show();
}
This will open your Window
instead of the MainWindow
.
Now onto view inheritance... as you know, there is no such thing in WPF, but there (kind of) is a way around this problem. If, as you say, all of your views are UserControl
based, then we can use ContentControl
objects to display them, provided that relevant DataTemplate
objects exist.
This basically means that if you want to use a particular Window
as an outer template for your views, then you can if you add a ContentControl
to display the view. As an example, I have an animated Window
that appears as a dialogue control with buttons which I bind several different UserControl
s to, so that they all have the same overall appearance.
In xaml:
...
<Border CornerRadius="3.5" BorderBrush="{StaticResource TransparentBlack}"
BorderThickness="1" Padding="1">
<ContentControl Content="{Binding ViewModel, RelativeSource={RelativeSource
FindAncestor, AncestorType={x:Type Controls:AnimationWindow}}}" />
</Border>
...
And in the Window
code behind:
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.
Register("ViewModel", typeof(BaseViewModel), typeof(AnimationWindow));
public BaseViewModel ViewModel
{
get { return (BaseViewModel)GetValue(ViewModelProperty); }
set { SetValue(ViewModelProperty, value); }
}
Using this class, I can either bind to this ViewModel
property in xaml, or set it from a value passed in through a constructor. As all of my view models extend this BaseViewModel
class, I can set this property to any of them.
UPDATE >>>
The point of using the ContentControl
and the DataTemplate
s to connect the views/view models is that we get away from 'hard coding'. I can use this setup in every application and I'm not tied to using any particular implementation.
Now if you're saying that you actually want to use the same view/view model pairings in all of your different applications, then you should put your DataTemplate
s to connect the views/view models in a separate Resources
xaml file. That way, you can merge this file into your App.xaml
Resources
section in applications where you need to and not when you don't:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ViewModelToViewDataTemplates.xaml"/>
<ResourceDictionary>
<!-- Add your normal resources here -->
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>