【问题标题】:How to link a viewmodel to a usercontrol inside a tabcontrol using PRISM, Mef, DI?如何使用 PRISM、Mef、DI 将视图模型链接到选项卡控件内的用户控件?
【发布时间】:2020-11-06 16:57:59
【问题描述】:

我正在编写一个顶部带有 MS Office 样式选项卡功能区的应用程序。该选项卡控件放置在由 Mef 设置的 shell 中的一个区域中。

shell.xaml 中的代码:

...
<ContentControl Name="TabRegion" prism:RegionManager.RegionName="TabRegion"/>
...

TabRegionView.xaml 中的代码:

<UserControl x:Class="Ensor.Studio.View.TabRegionView"
             etc...>
    <TabControl Margin="5" BorderThickness="0" Background="White" ItemsSource="{Binding Path=Tabs}">
        <TabControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Title}"/>
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.ContentTemplate>
            <DataTemplate>
                <ContentControl Content="{Binding Content}"/>
            </DataTemplate>
        </TabControl.ContentTemplate>         
    </TabControl>
</UserControl>

标签内容中的代码:ProjectTabView.xaml

<UserControl x:Class="Ensor.Studio.View.Tabs.ProjectTabView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:ap="clr-namespace:Ensor.Studio.ViewModel.CustomControls"
             xmlns:vm="clr-namespace:Ensor.Studio.ViewModel.Tabs"
             mc:Ignorable="d" 
             d:DesignHeight="110" d:DesignWidth="800">

    <StackPanel Orientation="Horizontal">
        <Button Name="button_ProjectBrowse" Command="{Binding ProjectBrowseCommand}" 
                     Style="{StaticResource BigTabButton}" Margin="5,10                  
                     ap:ButtonProperties.Image="pack:.../ButtonIcons/open.png" 
                     Content="Browse"/>
        <Rectangle Margin="5,10" Stroke="Silver"/>
...

当我运行该应用程序时,此选项卡控件呈现正常,但用户控件未与正确的视图模型链接...当 shell 初始化时,输出中会弹出以下错误:

System.Windows.Data Error: 40 : BindingExpression path error: 'ProjectBrowseCommand' property not found on 'object' ''TabRegionViewModel' (HashCode=37840511)'. BindingExpression:Path=ProjectBrowseCommand; DataItem='TabRegionViewModel' (HashCode=37840511); target element is 'Button' (Name='button_ProjectBrowse'); target property is 'Command' (type 'ICommand')

这意味着视图在 TabRegionViewModel 中查找了一个 ProjectBrowseCommand,它是整个选项卡控件的视图模型,而实际上它应该在 ProjectTabViewModel 中查找。

但是应用程序一直在运行,所以当我单击第一个选项卡时,会显示该选项卡的内容并弹出以下错误:

System.Windows.Data Error: 40 : BindingExpression path error: 'ProjectBrowseCommand' property not found on 'object' ''ProjectTabView' (Name='')'. BindingExpression:Path=ProjectBrowseCommand; DataItem='ProjectTabView' (Name=''); target element is 'Button' (Name='button_ProjectBrowse'); target property is 'Command' (type 'ICommand')

这意味着这一次它在特定选项卡的视图的后端代码中寻找一个 ProjectBrowseCommand。

我实际上想要做的是将 ProjectTab 中的用户控件链接到 ProjectTabViewModel。这是一个具有多个依赖项的类,所以我宁愿不使用 DataContext = new ProjectTabViewModel(...);

所以我的问题是,为什么视图在错误的类中查找它的绑定。以及如何通过依赖注入将其连接到 ProjectTabViewModel?

【问题讨论】:

    标签: c# wpf xaml prism


    【解决方案1】:

    我要做的是将 ItemsSource 绑定到 ViewModel 属性,例如ObservableCollection&lt;object&gt;object也可以是所有标签ViewModel的基类)。

    然后使用 DataTemplate 告诉 WPF 如何表示不同的 ViewModel:

    比如喜欢这样的:

    
    public class ViewModel
    {
        public ObservableCollection<object> Tabs { get; } = new ObservableCollection<object>();
    
        public ViewModel()
        {
            Tabs.Add(new FirstViewModel());
        }
    }
    
    
    <TabControl ItemsSource="{Binding Path=Tabs}"></TabControl>
    

    资源:

    <DataTemplate DataType="{x:Type viewModels:FirstViewModel} ">
        <views:FirstView/>
    </DataTemplate>
    

    更新

    使用依赖注入:

    
    public class ViewModel
    {
        public ObservableCollection<TabViewModelBase> Tabs { get; } = new ObservableCollection<object>();
    
        public ViewModel(IEnumerable<TabViewModelBase> tabs)
        {
            Tabs.Add(tabs);
        }
    }
    
    public class FirstViewModel : TabViewModelBase
    {
        
    }
    

    我假设您知道如何在应用程序的根目录中配置容器。

    【讨论】:

    • 视图模型优先总是首选,视图优先很少见(尽管必不可少)
    • 谢谢@Michael!我会试一试。我仍然需要弄清楚如何在 new FirstViewModel(... a few dependencies ...) 上使用依赖注入,对此有何想法?
    • @BenVandenBergh 关键字是factory - 在涉及依赖注入的应用程序中,无论如何您都不想使用new。看看这里,例如:stackoverflow.com/questions/57115301/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-08
    • 2011-02-19
    • 2011-06-22
    • 1970-01-01
    相关资源
    最近更新 更多