How can I use a view from a framework in an applic

2019-08-29 07:13发布

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.

标签: c# .net wpf xaml mvvm
1条回答
爷的心禁止访问
2楼-- · 2019-08-29 07:47

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 UserControls 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 DataTemplates 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 DataTemplates 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>
查看更多
登录 后发表回答