【问题标题】:Binding child DataContext from within DataTrigger从 DataTrigger 中绑定子 DataContext
【发布时间】:2017-04-22 05:31:44
【问题描述】:

我一直在尝试开发一个 RadioButtons 栏(样式为 ToggleButtons),用于选择在 ContentControl 中显示哪些内容。我已经能够使用 DataTrigger 根据选中的 RadioButton 在 ContentControl 中显示正确的视图,但我也试图将视图模型从父 DataContext 绑定到子 DataContext 中,但没有成功。最小样本如下:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <StackPanel Orientation="Horizontal" VerticalAlignment="Top" >
            <RadioButton Name="rbShowChild" Content="Show Child" Style="{StaticResource {x:Type ToggleButton}}" />
        </StackPanel>

        <ContentControl Grid.Row="1">
            <ContentControl.Style>
                <Style TargetType="{x:Type ContentControl}">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsChecked, ElementName=rbShowChild}" Value="True">
                            <Setter Property="Content">
                                <Setter.Value>
                                    <local:ChildView DataContext="{Binding ChildViewModel, PresentationTraceSources.TraceLevel=High}"/>
                                </Setter.Value>
                            </Setter>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ContentControl.Style>
        </ContentControl>
    </Grid>
</Window>

与 ChildViewModel 的绑定似乎是未按预期工作的部分。为了完整起见,这里是相关的 ChildView。

<UserControl x:Class="WpfApplication1.ChildView"
             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:local="clr-namespace:WpfApplication1"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <StackPanel>
            <TextBlock Text="Child" />
            <TextBlock Text="{Binding Text}" />
        </StackPanel>
    </Grid>
</UserControl>

还有 ViewModel:

namespace WpfApplication1
{
    public class ChildViewModel
    {
        public string Text { get; set; }

        public ChildViewModel()
        {
            Text = "It works!";
        }
    }

    public class MainWindowViewModel
    {
        public ChildViewModel ChildViewModel { get; set; }

        public MainWindowViewModel()
        {
            ChildViewModel = new ChildViewModel();
        }
    }
}

并且MainWindow DataContext设置如下:

        var window = new MainWindow()
        {
            DataContext = new MainWindowViewModel()
        };
        window.Show();

输出窗口(PresentationTraceSources.TraceLevel=High)显示如下:

System.Windows.Data Error: 3 : Cannot find element that provides DataContext. BindingExpression:Path=ChildViewModel; DataItem=null; target element is 'ChildView' (Name=''); target property is 'DataContext' (type 'Object')

这让我认为 MainWindow.DataContext 不是用于解析触发器中“{Binding ChildViewModel}”表达式的 DataContext,但我在触发器上找不到任何 DataContext 属性,我也没有能够在我的搜索中找到任何建议答案的内容。

我非常感谢任何解决此问题的建议。

【问题讨论】:

    标签: wpf mvvm


    【解决方案1】:

    更新:看起来问题在于您如何设置数据上下文。

    在XAML中设置窗口的DataContext,然后将ContentControl的数据上下文设置为ChildViewModel。然后设置实际显示的Content(AKA ChildView)ValueContentControl 是这个视图的宿主,所以它应该是 DataContext 供应商。我自己有点不确定具体的机制,但我知道下面的代码确实有效。

    注意您的 XML 命名空间可能与下面的代码不同。相应调整。

    <Window.DataContext>
        <!-- Data Context added here OR in code-behind initialize-->
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
    
        <StackPanel Orientation="Horizontal" VerticalAlignment="Top" >
            <RadioButton Name="rbShowChild" Content="Show Child" Style="{StaticResource {x:Type ToggleButton}}" />
        </StackPanel>
    
        <!-- Bind the ContentControls Data context-->
        <ContentControl DataContext="{Binding ChildViewModel}" Grid.Row="1">
            <ContentControl.Style>
                <Style TargetType="{x:Type ContentControl}">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsChecked, ElementName=rbShowChild}" Value="True">
                            <Setter Property="Content">
                                <Setter.Value>
                                    <!-- Just simply set the view content here, no binding.-->
                                    <local:ChildView />
                                </Setter.Value>
                            </Setter>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ContentControl.Style>
        </ContentControl>
    </Grid>
    

    这样做,我已经在一个项目中很好地运行了您的应用程序。

    【讨论】:

    • 感谢您的回复,Toskr。我尝试了这两种方法,但我认为它不能解决我的问题。 MainWindow DataContext 似乎工作正常,即使在原始项目中也是如此。未设置的是 ChildView DataContext。当您说这些更改后它对您有效时,您是否看到绑定的文本字符串“它有效!”当您单击应该从子视图中显示的按钮时,还是只单击字符串“Child”(未绑定,而只是在 XAML 中)?触发器正在显示子视图,只是子 DataContext 没有设置。
    • 我看到显示的字符串“It works”。也许发布有关您如何以及在何处设置数据上下文的信息。
    • 创建MainWindow并设置其DataContext的原始代码在App.OnStartup()中。我还将您建议的更改添加到 MainWindow 构造函数和 XAML 中。我不确定为什么它对你有用,但对我没有用。
    • 另外,如果我将 添加到我的主窗口中,它会显示“它有效!”那里很好,这再次意味着我的 MainWindow DataContext 设置正确。从 App.OnStartup 设置 MainWindow DataContext 时它是否对您有用,并且没有在您建议的任何一个地方再次设置它?
    • 早上我不会在我的电脑前,所以我会深入挖掘。然而,这感觉可能是其中一种情况,您可能会忽略一些导致事情无法按预期工作的小错误。我会建议仔细检查并仔细查看。比如你在后面的子视图代码中做过什么吗?有什么可能在运行时打破对孩子的绑定吗?可能是您忘记删除的内容?
    猜你喜欢
    • 2016-10-28
    • 2019-04-29
    • 2013-10-19
    • 1970-01-01
    • 2018-08-29
    • 2013-06-04
    • 2014-07-30
    • 2010-12-03
    • 2016-07-11
    相关资源
    最近更新 更多