Prism / WPF视图/视图模型被创建两次

问题描述 投票:0回答:1

我有一个Prism 7 / WPF / MVVM应用程序,该应用程序在具有viewmodel的视图中配置为AutowireViewModel =“ True”。我的大多数视图模型都具有在Prism Unity容器中配置的依赖项,并且这些依赖项已注入到viewmodel构造器中。我没有在任何地方的代码后显式创建视图/视图模型的实例。我也没有在XAML中设置数据上下文,即d:DataContext)。 XAML中唯一的引用是视图(即HamburgerMenu控件的一部分)。

所有工作正常,除了每个视图/视图模型出于某种原因构造两次。我将断点放置在模块管理器中(仅命中一次)-以及放置在命中两次的视图构造函数和viewmodel构造函数中。 以下是我的名为Messaging的模块的代码,该模块在运行时未按需加载-我不确定要发布什么代码。由于希望尽可能多地使用MVVM模式,因此视图后面的代码中几乎没有代码。

模块管理器(我已经省略了RegisterTypes方法,因为依赖项没有问题):

public void OnInitialized(IContainerProvider containerProvider)
{
    // Register main view with region manager
    var regionManager = containerProvider.Resolve<IRegionManager>();
    regionManager.RegisterViewWithRegion("MainRegion", typeof(MessagingMainView));
}

MessagingMainView:

<UserControl x:Class="Ascensos.Wpf.Modules.Messaging.Views.MessagingMainView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
         xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
         xmlns:materialDesignConverters="clr-namespace:MaterialDesignThemes.Wpf.Converters;assembly=MaterialDesignThemes.Wpf"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:views="clr-namespace:Ascensos.Wpf.Modules.Messaging.Views"
         xmlns:helpers="clr-namespace:Ascensos.Wpf.Modules.Messaging.Helpers"
         xmlns:prism="http://prismlibrary.com/"
         prism:ViewModelLocator.AutoWireViewModel="True"
         d:DesignHeight="300"
         d:DesignWidth="400"
         mc:Ignorable="d">

<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Themes/HamburgerMenu.xaml" />
        </ResourceDictionary.MergedDictionaries>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
        <helpers:HamburgerMenuIconItemTemplateSelector x:Key="myDataTemplateSelector"/>

        <!--  This is the template for the menu items (no badge/count control).  -->
        <DataTemplate x:Key="MenuItemTemplate" DataType="{x:Type Controls:HamburgerMenuIconItem}">
            <Grid Height="48">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="48" />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <ContentControl Grid.Column="0"
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                Content="{Binding Icon}"
                                Focusable="False"
                                IsTabStop="False" />
                <TextBlock Grid.Column="1"
                           VerticalAlignment="Center"
                           FontSize="16"
                           Text="{Binding Label}" />
            </Grid>
        </DataTemplate>

        <!--  This is the template for the menu items (with badge/count control).  -->
        <DataTemplate x:Key="MenuItemTemplateBadged" DataType="{x:Type Controls:HamburgerMenuIconItem}">
            <Grid Height="48">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="48" />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <Controls:Badged Grid.Column="0"
                                 Badge="{Binding Tag.DataContext.UnreadMessagesCount}"
                                 BadgeBackground="Red"
                                 HorizontalAlignment="Center"
                                 VerticalAlignment="Center">
                    <ContentControl Content="{Binding Icon}"
                                    Margin="2"
                                    Focusable="False"
                                    IsTabStop="False" />
                </Controls:Badged>
                <TextBlock Grid.Column="1"
                           VerticalAlignment="Center"
                           FontSize="16"
                           Text="{Binding Label}" />
            </Grid>
        </DataTemplate>

        <!--  This is the template for all menu items. In this sample we use the glyph items.  -->
        <DataTemplate x:Key="HamburgerMenuItem" DataType="{x:Type Controls:HamburgerMenuGlyphItem}">
            <DockPanel Height="48" LastChildFill="True">
                <Grid x:Name="IconPart"
                      Width="48"
                      DockPanel.Dock="Left">
                    <Image Margin="12"
                           HorizontalAlignment="Center"
                           VerticalAlignment="Center"
                           Source="{Binding Glyph}"
                           Stretch="UniformToFill" />
                </Grid>
                <TextBlock x:Name="TextPart"
                           VerticalAlignment="Center"
                           FontSize="16"
                           Text="{Binding Label}" />
            </DockPanel>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Controls:HamburgerMenu}}, Path=PanePlacement}" Value="Right">
                    <Setter TargetName="IconPart" Property="DockPanel.Dock" Value="Right" />
                    <Setter TargetName="TextPart" Property="Margin" Value="8 0 0 0" />
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>

        <!--  This is the template for the option menu item  -->
        <DataTemplate x:Key="HamburgerOptionsMenuItem" DataType="{x:Type Controls:HamburgerMenuIconItem}">
            <DockPanel Height="48" LastChildFill="True">
                <ContentControl x:Name="IconPart"
                                Width="48"
                                Content="{Binding Icon}"
                                DockPanel.Dock="Left"
                                Focusable="False"
                                IsTabStop="False" />
                <TextBlock x:Name="TextPart"
                           VerticalAlignment="Center"
                           FontSize="16"
                           Text="{Binding Label}" />
            </DockPanel>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Controls:HamburgerMenu}}, Path=PanePlacement}" Value="Right">
                    <Setter TargetName="IconPart" Property="DockPanel.Dock" Value="Right" />
                    <Setter TargetName="TextPart" Property="Margin" Value="8 0 0 0" />
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>

        <ObjectDataProvider x:Key="DisplayModeEnumValues"
                            MethodName="GetValues"
                            ObjectType="{x:Type Controls:SplitViewDisplayMode}">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="Controls:SplitViewDisplayMode" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>

        <ObjectDataProvider x:Key="VisibilityEnumValues"
                            MethodName="GetValues"
                            ObjectType="{x:Type Visibility}">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="Visibility" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>

        <materialDesignConverters:BrushRoundConverter x:Key="BrushRoundConverter" />

        <Style x:Key="MahApps.Styles.ListBoxItem.HamburgerMenuItem.Ripple"
               BasedOn="{StaticResource MahApps.Styles.ListBoxItem.HamburgerMenuItem}"
               TargetType="{x:Type ListBoxItem}">
            <Setter Property="Controls:ItemHelper.ActiveSelectionBackgroundBrush" Value="Transparent" />
            <Setter Property="Controls:ItemHelper.ActiveSelectionForegroundBrush" Value="{DynamicResource MahApps.Brushes.AccentBase}" />
            <Setter Property="Controls:ItemHelper.DisabledForegroundBrush" Value="{DynamicResource MahApps.Brushes.Gray}" />
            <Setter Property="Controls:ItemHelper.DisabledSelectedBackgroundBrush" Value="Transparent" />
            <Setter Property="Controls:ItemHelper.DisabledSelectedForegroundBrush" Value="{DynamicResource MahApps.Brushes.Gray}" />
            <Setter Property="Controls:ItemHelper.HoverBackgroundBrush" Value="{DynamicResource MahApps.Brushes.Gray9}" />
            <Setter Property="Controls:ItemHelper.HoverSelectedBackgroundBrush" Value="{DynamicResource MahApps.Brushes.Gray9}" />
            <Setter Property="Controls:ItemHelper.SelectedBackgroundBrush" Value="Transparent" />
            <Setter Property="Controls:ItemHelper.SelectedForegroundBrush" Value="{DynamicResource MahApps.Brushes.AccentBase}" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <Grid Background="{TemplateBinding Background}" RenderOptions.ClearTypeHint="{TemplateBinding RenderOptions.ClearTypeHint}">
                            <Border x:Name="Border"
                                    Background="{TemplateBinding Background}"
                                    BorderBrush="{TemplateBinding BorderBrush}"
                                    BorderThickness="{TemplateBinding BorderThickness}"
                                    SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                            <Grid Margin="{TemplateBinding BorderThickness}">
                                <Grid HorizontalAlignment="Left"
                                      VerticalAlignment="Center"
                                      Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Controls:HamburgerMenu}}, Path=ShowSelectionIndicator, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}">
                                    <Rectangle x:Name="SelectionIndicator"
                                               Width="{DynamicResource HamburgerMenuSelectionIndicatorThemeWidth}"
                                               Height="{DynamicResource HamburgerMenuSelectionIndicatorThemeHeight}"
                                               Fill="{TemplateBinding Foreground}"
                                               Focusable="False"
                                               Opacity="0.0" />
                                </Grid>
                                <materialDesign:Ripple Padding="{TemplateBinding Padding}"
                                                       HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                       VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                                                       Content="{TemplateBinding Content}"
                                                       ContentTemplate="{TemplateBinding ContentTemplate}"
                                                       ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
                                                       Feedback="{TemplateBinding Foreground, Converter={StaticResource BrushRoundConverter}}"
                                                       Focusable="False"
                                                       SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                            </Grid>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsSelected" Value="True">
                                <Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Controls:ItemHelper.SelectedForegroundBrush), Mode=OneWay}" />
                                <Setter TargetName="Border" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:ItemHelper.SelectedBackgroundBrush), Mode=OneWay}" />
                                <Setter TargetName="SelectionIndicator" Property="Opacity" Value="1.0" />
                            </Trigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsSelected" Value="True" />
                                    <Condition Property="Selector.IsSelectionActive" Value="True" />
                                </MultiTrigger.Conditions>
                                <Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Controls:ItemHelper.ActiveSelectionForegroundBrush), Mode=OneWay}" />
                                <Setter TargetName="Border" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:ItemHelper.ActiveSelectionBackgroundBrush), Mode=OneWay}" />
                            </MultiTrigger>

                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsMouseOver" Value="True" />
                                    <Condition Property="IsSelected" Value="True" />
                                </MultiTrigger.Conditions>
                                <Setter TargetName="Border" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:ItemHelper.HoverSelectedBackgroundBrush), Mode=OneWay}" />
                            </MultiTrigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsMouseOver" Value="True" />
                                    <Condition Property="IsSelected" Value="False" />
                                </MultiTrigger.Conditions>
                                <Setter TargetName="Border" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Controls:ItemHelper.HoverBackgroundBrush), Mode=OneWay}" />
                            </MultiTrigger>

                            <Trigger Property="IsEnabled" Value="False">
                                <Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Controls:ItemHelper.DisabledForegroundBrush), Mode=OneWay}" />
                                <Setter TargetName="Border" Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Controls:ItemHelper.DisabledBackgroundBrush), Mode=OneWay}" />
                            </Trigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsEnabled" Value="False" />
                                    <Condition Property="IsSelected" Value="True" />
                                </MultiTrigger.Conditions>
                                <Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Controls:ItemHelper.DisabledSelectedForegroundBrush), Mode=OneWay}" />
                                <Setter TargetName="Border" Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Controls:ItemHelper.DisabledSelectedBackgroundBrush), Mode=OneWay}" />
                            </MultiTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <Style x:Key="MahApps.Styles.HamburgerMenu.Ripple"
               BasedOn="{StaticResource MahApps.Styles.HamburgerMenu}"
               TargetType="{x:Type Controls:HamburgerMenu}">
            <Setter Property="ItemContainerStyle" Value="{StaticResource MahApps.Styles.ListBoxItem.HamburgerMenuItem.Ripple}" />
            <Setter Property="OptionsItemContainerStyle" Value="{StaticResource MahApps.Styles.ListBoxItem.HamburgerMenuItem.Ripple}" />
            <Setter Property="PaneBackground" Value="{DynamicResource MahApps.Brushes.ThemeBackground}" />
            <Setter Property="PaneForeground" Value="{DynamicResource MahApps.Brushes.Text}" />
            <Setter Property="ShowSelectionIndicator" Value="True" />
        </Style>

    </ResourceDictionary>
</UserControl.Resources>

<Grid>
    <Border Grid.Column="0"
            Margin="10 10 0 10"
            BorderBrush="{DynamicResource MahApps.Brushes.Gray7}"
            BorderThickness="1">
        <Controls:HamburgerMenu x:Name="HamburgerMenuControl"
                                HamburgerWidth="48"
                                IsPaneOpen="True"
                                CanResizeOpenPane="True"
                                ItemInvoked="HamburgerMenuControl_OnItemInvoked"
                                ItemTemplateSelector="{StaticResource myDataTemplateSelector}"
                                SelectedItem="{Binding SelectedMenuItem}"
                                Style="{StaticResource MahApps.Styles.HamburgerMenu.Ripple}"
                                VerticalScrollBarOnLeftSide="False">

            <!--  Items  -->
            <Controls:HamburgerMenu.ItemsSource>
                <Controls:HamburgerMenuItemCollection>
                    <Controls:HamburgerMenuIconItem Icon="{iconPacks:FontAwesome Kind=CommentAltSolid}" Label="Chat">
                        <Controls:HamburgerMenuIconItem.Tag>
                            <views:ChatView />
                        </Controls:HamburgerMenuIconItem.Tag>
                    </Controls:HamburgerMenuIconItem>
                    <Controls:HamburgerMenuIconItem Icon="{iconPacks:FontAwesome Kind=PenSquareSolid}" Label="Compose">
                        <Controls:HamburgerMenuIconItem.Tag>
                            <views:ComposeMessageView />
                        </Controls:HamburgerMenuIconItem.Tag>
                    </Controls:HamburgerMenuIconItem>
                    <Controls:HamburgerMenuIconItem Icon="{iconPacks:Material Kind=InboxArrowDown}" Label="Inbox">
                        <Controls:HamburgerMenuIconItem.Tag>
                            <views:InboxView />
                        </Controls:HamburgerMenuIconItem.Tag>
                    </Controls:HamburgerMenuIconItem>
                </Controls:HamburgerMenuItemCollection>
            </Controls:HamburgerMenu.ItemsSource>

            <Controls:HamburgerMenu.ContentTemplate>
                <DataTemplate DataType="{x:Type Controls:HamburgerMenuIconItem}">
                    <Grid Margin="20 0 10 0">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        <TextBlock Grid.Row="0"
                                   Margin="0 15 0 5"
                                   Padding="0"
                                   FontFamily="{DynamicResource MahApps.Fonts.Family.Header}"
                                   FontSize="{DynamicResource MahApps.Font.Size.Header}"
                                   Text="{Binding Label}" />
                        <ScrollViewer Grid.Row="1"
                                      Focusable="False"
                                      HorizontalScrollBarVisibility="Disabled"
                                      VerticalScrollBarVisibility="Auto">
                            <ContentControl Content="{Binding Tag}" Focusable="False" />
                        </ScrollViewer>
                    </Grid>
                </DataTemplate>
            </Controls:HamburgerMenu.ContentTemplate>
        </Controls:HamburgerMenu>
    </Border>
</Grid>

...

后面的代码:

public sealed partial class MessagingMainView : UserControl
{
    public MessagingMainView()
    {
        this.InitializeComponent();

        HamburgerMenuControl.SelectedItem = ((HamburgerMenuItemCollection)HamburgerMenuControl.ItemsSource)[0];
    }

    private void HamburgerMenuControl_OnItemInvoked(object sender, HamburgerMenuItemInvokedEventArgs e)
    {
        HamburgerMenuControl.Content = e.InvokedItem;
    }
}

视图模型(调用基本消息视图模型类:

public sealed class MessagingMainViewModel : BaseMessageViewModel
{
    private HamburgerMenuIconItem _selectedMenuItem;

    public HamburgerMenuIconItem SelectedMenuItem
    {
        get => _selectedMenuItem;
        set => SetPropertyAndNotify(ref _selectedMenuItem, value, () => SelectedMenuItem);
    }

    public MessagingMainViewModel(
        IRegionManager regionManager,
        IEventAggregator eventAggregator,
        IUserService userService,
        IChatService chatService,
        IMessageService messageService,
        IDialogService dialogService,
        IMetroMessageDisplayService metroMessageDisplayService,
        INotifyIconService notifyIconService,
        ILogger<MessagingMainViewModel> logger) : base(regionManager, eventAggregator, userService, chatService, messageService, dialogService, metroMessageDisplayService, notifyIconService, logger)
    {

    }
}

BaseMessagViewModel继承自BaseViewModel类:

public class BaseMessageViewModel : BaseViewModel
{
...

public BaseMessageViewModel(
        IRegionManager regionManager,
        IEventAggregator eventAggregator,
        IUserService userService,
        IChatService chatService,
        IMessageService messageService,
        IDialogService dialogService,
        IMetroMessageDisplayService metroMessageDisplayService,
        INotifyIconService notifyIconService,
        ILogger<BaseMessageViewModel> logger): base(regionManager, eventAggregator, dialogService, metroMessageDisplayService, notifyIconService)
    {
    ...

BaseViewModel类:

public abstract class BaseViewModel : DisposableObject, INotifyPropertyChanged
{
...

public BaseViewModel(
    IRegionManager regionManager = null,
    IEventAggregator eventAggregator = null,
    IDialogService dialogService = null,
    IMetroMessageDisplayService metroMessageDisplayService = null,
    INotifyIconService notifyServce = null)
{
...
c# wpf mvvm constructor prism
1个回答
0
投票

我没有在任何地方(即仅在XAML中)后面的代码中未明确创建视图/视图模型的实例。

这是矛盾的-在xaml中创建视图模型意味着以与在后面的代码或其他任何地方的代码相同的方式创建视图模型。

如前所述,请不要这样做。也从xaml中删除对视图模型的构造函数的所有引用(例如<DataContext><MyViewViewModel/></DataContext>)。要获取xaml中的智能感知,请使用d:DataContext

© www.soinside.com 2019 - 2024. All rights reserved.