0

我正在使用 MV-VM 模式做一个 WPF 应用程序(如果相关,我正在使用 galasoft),但是当我通过 tabcontrol 导航时遇到问题。
我正在运行中添加标签。所有的绑定似乎都很顺利:在选项卡内或选项卡的标题中。我已经将我的 tabcontrol 绑定到一个可观察的列表。通过一个界面,我将几种类型的视图模型添加到此列表中,并且绑定似乎是正确的。
我的 XAML 代码如下所示:

<Grid>
    <Grid.Resources>
        <DataTemplate x:Key="itemTemplate">
            <TechnicalControls:ItemTab />
        </DataTemplate>
    </Grid.Resources>

    <TabControl Grid.Row="1" x:Name="MainTab" Grid.Column="1" 
            ItemsSource="{Binding TabViewModels}"
            SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}"

            ItemContainerStyleSelector="{StaticResource LastItemStyleSelector}"
            ItemTemplate="{StaticResource itemTemplate}"
            >

        <TabControl.Resources>
            <DataTemplate DataType="{x:Type VM:JobViewModel}" x:Shared="False" >
                <FunctionnalControls:Job />
            </DataTemplate>
            <DataTemplate DataType="{x:Type VM:ExcelJobViewModel}" x:Shared="False">
                <FunctionnalControls:ExcelJob />
            </DataTemplate>
            <DataTemplate DataType="{x:Type VM:MonitoringViewModel}" x:Shared="False">
                <FunctionnalControls:Monitoring />
            </DataTemplate>
            <DataTemplate DataType="{x:Type VM:ErrorViewModel}" x:Shared="False">
                <FunctionnalControls:Error />
            </DataTemplate>                

        </TabControl.Resources>
    </TabControl>
</Grid>

例如,如果我从 ExcelJob 转到另一个 ExcelJob 用户控件,新的用户控件未正确加载,但它发生了变化,然后它可以工作,例如,如果我通过监视,我可以将 ExcelJob 转到另一个 ExcelJob。

我已经看过这个,但它对我不起作用。
我也看过这个:它说我们不应该使用输入,因为你可以集中它们。我试图将用户控件上的 IsEnabled 属性设置为 false。当标签发生变化时,我做到了。它没有工作...

我能看到的唯一解决方案是通过另一个新的用户控件,每次更改选项卡时都没有其他用途,但这很丑陋,我很确定,微软考虑过这一点并想出了一个更好的解决方案。

如有必要,我可以放视图模型的代码。

编辑:澄清一下,当我单击具有相同控件的其他选项卡时,它不会向我显示新的用户控件,而是向我显示前一个。为了看到新的,我必须用另一个用户控件切换到另一个选项卡,然后回到我想看的那个。
我已经查看了调试,当我单击另一个选项卡时它没有调用视图模型

<UserControl x:Class="App.ExcelJob"
             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" 
             DataContext="{Binding Main.ExcelJobVM, Source={StaticResource Locator }}">
    <Grid >
        <Label>Futur Excel Job</Label>
        <TextBox Width="200" Height="60" Text="{Binding Header}"/>
    </Grid>
</UserControl>

所以 Main 返回 Mainviewmodel 和 Main.ExcelJobVM 返回用户控件的好 viewmodel。返回的实例基于选定的索引。
我唯一需要的是通过加载好的视图模型来强制重绘用户控件或调用更新数据上下文的方法。我试过了,到目前为止我失败了。我不确定我在做什么,因为我想使用 tabcontrol 的事件 SelectionChanged 但它会在后面的代码中,我不知道它是否仍然尊重 MVVM 模式。

4

1 回答 1

4

问题是您在 中进行了DataContext硬编码UserControl,而您UserControl的 是模板。

当您切换到使用相同的选项卡时Template,WPF 不会费心重绘模板,而只会更改DataContext模板后面的内容。但是在您的情况下,您在 中进行了DataContext硬编码UserControl,因此它没有使用 TabItem 中的现有数据上下文。

最好的解决方案是DataContext从您的 UserControl 中删除绑定,并让它从TabItem所选项目更改时继承。

例如:

WPF 说

用户已选择ExcelJobA显示。由于 DataTemplate,让我使用 ExcelJob UserControl 绘制它

<TabItem>
    <ContentPresenter DataContext="ExcelJobA">
        <local:ExcelJob DataContext="{Binding Main.ExcelJobVM, Source={StaticResource Locator }}" />
    </ContentPresenter>
</TabItem>

因此ExcelJob创建了一个 UserControl,默认情况下,DataContextExcelJobA将由 UserControl 继承。

当用户将选定的选项卡更改为 时ExcelJobB,WPF 会

嘿,用户已更改为ExcelJobB。由于 DataTemplate,让我使用ExcelJobUserControl 绘制它,但是等等!我已经显示了一个ExcelJobUserControl,所以让我将其后面的 DataContext 更改为ExcelJobB

<TabItem>
    <ContentPresenter DataContext="ExcelJobB">
        <local:ExcelJob DataContext="{Binding Main.ExcelJobVM, Source={StaticResource Locator }}" />
    </ContentPresenter>
</TabItem>

所以实际显示的ExcelJobUserControl 不会被重新创建或重绘,而只是它DataContext背后的变化。

但是DataContext,因为您已经对内部进行了硬编码UserControl,所以从所选项目中获得的实际数据上下文永远不会被使用,因为DataContext从内部指定的 a<Tag>始终优先于DataContext从视觉树的更上方继承的 a 。

您需要DataContext从您的内部删除绑定UserControl,并让它从您的 TabControl 中正常传递SelectedItem,它会正常工作。

<TabItem>
    <ContentPresenter DataContext="ExcelJobA">
        <local:ExcelJob /> <!-- DataContext inherited from the ContentPresenter -->
    </ContentPresenter> 
</TabItem>
于 2013-05-17T18:58:10.300 回答