繁体   English   中英

如何在窗口的 DataContext 中将 DataContext 绑定到 ViewModel?

[英]How to Bind a DataContext to ViewModel inside window's DataContext?

我目前的视图如下所示:

    <Window>
        <DockPanel>
            <Menu>
                ...
            </Menu>
            <StackPanel>
                <Grid>
                    ...
                </Grid>
                <Separator>
                <Grid>
                    <Frame Source="ADifferentView.xaml" DataContext="{Binding ADifferentViewModel}">
                    <Frame...>
                    <Frame...>
                </Grid>
            </StackPanel>
        </DockPanel>
    </Window>

ViewModel 声明为:

public ResultsViewModel ADifferentViewModel{ get; set; }

并在构造函数中初始化。

ADifferentViewModel 是 Window 的 ViewModel 中的一个变量(已正确链接并正常工作)。 但是,框架与该变量的绑定似乎没有链接。

我的直觉表明这是由于需要获取 Window 的上下文。 我试过了:

DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=ADifferentViewModel}"

DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}, Path=ADifferentViewModel}"

然而,这些都不起作用。 我还尝试将 Window 更改为 DockPanel、StackPanel 和 Grid,但均无济于事。

任何建议将不胜感激,希望这足够清楚。 请询问您是否需要任何详细信息

由于某种原因,似乎Frame的 DataContext 没有落入其内容中。但是,您可以从FrameLoadCompleted事件中受益,像这样手动分配DataContext

  1. .xaml
<Frame 
   x:Name="MyFrame"
   LoadCompleted="MyFrame_OnLoadCompleted"
   Source="ADifferentView.xaml" DataContext="{Binding ADifferentViewModel}"/>
  1. .xaml.cs
private void MyFrame_OnLoadCompleted(object sender, NavigationEventArgs e)
{
  if (MyFrame.Content is FrameworkElement content)
        content.DataContext = MyFrame.DataContext;
}

您的解释和演示代码不足以回答您的问题。 我将向您展示一些绑定示例。
我希望这足以让您了解问题的原因。

例一。
设置 DataContext 并使用 TextBox 检查其值。

using System.Windows;

namespace Core2022.SO.HarryAdams
{
    public partial class DataContextBindingWindow : Window
    {
        private readonly MainViewModel viewModel;
        public DataContextBindingWindow()
        {
            InitializeComponent();
            viewModel = new MainViewModel();
            viewModel.ADifferentViewModel = new ResultsViewModel();
            viewModel.ADifferentViewModel.Number = 12345678;
            DataContext = viewModel;
        }
    }

    public class ResultsViewModel
    {
        public int Number { get; set; }
    }

    public class MainViewModel
    {
        public ResultsViewModel? ADifferentViewModel { get; set; }
    }
}
<Window x:Class="Core2022.SO.HarryAdams.DataContextBindingWindow"
        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:Core2022.SO.HarryAdams"
        mc:Ignorable="d"
        Title="DataContextBindingWindow" Height="450" Width="800">
    <StackPanel>
        <Frame x:Name="frame" Height="100" DataContext="{Binding ADifferentViewModel}"/>
        <TextBlock Text="{Binding DataContext.Number, ElementName=frame}"/>
    </StackPanel>
</Window>

在此示例中,您可以看到 DataContext 正确绑定并显示正确的值。

第二个例子。
由于 DataContext 绑定工作正常,我假设您的意思是 DataContext 不是 Frame,而是 Page «ADifferentView»。

<Page x:Class="Core2022.SO.HarryAdams.ADifferentView"
      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:Core2022.SO.HarryAdams"
      mc:Ignorable="d" 
      d:DesignHeight="450" d:DesignWidth="800"
      Title="ADifferentView">

    <Grid Background="LightSkyBlue">
        <TextBlock Text="{Binding Number}"/>
    </Grid>
</Page>
        <Frame x:Name="frame" Height="100" DataContext="{Binding ADifferentViewModel}"
               Source="/SO/HarryAdams/ADifferentView.xaml"/>

在此示例中,页面文本框收到一个锚定错误。 原因是 Page 用于表示 Frame.Content 属性。 由于此属性中未设置任何内容,因此页面数据上下文没有绑定 object。

同时,即使将 FindAncestor 类型显式绑定到 Frame 或 Window 也不能解决问题:

<Page x:Class="Core2022.SO.HarryAdams.ADifferentView"
      DataContext="{Binding DataContext,
                            RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Frame}}}"

第三个例子。
在导航事件中将 Page DataContext 绑定到 object。

    <StackPanel>
        <Frame x:Name="frame" Height="100" DataContext="{Binding ADifferentViewModel}"
               Source="/SO/HarryAdams/ADifferentView.xaml"
               Navigated="OnNavigated"/>
        <TextBlock Text="{Binding DataContext.Number, ElementName=frame}"/>
    </StackPanel>
    <x:Code>
        <![CDATA[
        private void OnNavigated(object sender, NavigationEventArgs e)
        {
            FrameworkElement element = (FrameworkElement)sender;
            FrameworkElement child = (FrameworkElement)e.Content;

            child.SetBinding(DataContextProperty, new Binding("DataContext") { Source = element});
        }
        ]]>
    </x:Code>
</Window>

第四个例子。
此示例对于 WPF 页面更为典型。
他们要么创建自己的 DataContext,要么从 App 获取。

    <Application.Resources>
        <harryadams:MainViewModel x:Key="mainVM">
            <harryadams:MainViewModel.ADifferentViewModel>
                <harryadams:ResultsViewModel Number="1234567"/>
            </harryadams:MainViewModel.ADifferentViewModel>
        </harryadams:MainViewModel>
    </Application.Resources>
<Page x:Class="Core2022.SO.HarryAdams.ADifferentView"
      DataContext="{Binding ADifferentViewModel, Source={StaticResource mainVM}}"

第五例。
这个例子是比较典型的 WPF+MVVM 页面。 在这种情况下,锚点 object 在 Frame Content 中传递,页面类型在 DataTemplate 中指定:

    <StackPanel>
        <Frame x:Name="frame" Height="100" Content="{Binding ADifferentViewModel}">
            <Frame.ContentTemplate>
                <DataTemplate>
                    <local:ADifferentView/>
                </DataTemplate>
            </Frame.ContentTemplate>
        </Frame>
        <TextBlock Text="{Binding Content.Number, ElementName=frame}"/>
    </StackPanel>
</Window>

您还可以使用默认数据模板:

    <Window.Resources>
        <DataTemplate DataType="{x:Type local:ResultsViewModel}">
            <local:ADifferentView/>
        </DataTemplate>
    </Window.Resources>
    <StackPanel>
        <Frame x:Name="frame" Height="100" Content="{Binding ADifferentViewModel}"/>
        <TextBlock Text="{Binding Content.Number, ElementName=frame}"/>
    </StackPanel>
</Window>

第六个例子。
Frame+Page 经常用在错误的地方。
在绝大多数情况下,应改用 UserControl。 在这种情况下,对于大多数元素,所有绑定和传递 DataContext 开始以典型方式工作。

<UserControl x:Class="Core2022.SO.HarryAdams.ADifferentView"
      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:Core2022.SO.HarryAdams"
      mc:Ignorable="d" 
      d:DesignHeight="450" d:DesignWidth="800">
    <Grid Background="LightSkyBlue">
        <TextBlock Text="{Binding Number}"/>
    </Grid>
</UserControl>
<Window x:Class="Core2022.SO.HarryAdams.DataContextBindingWindow"
        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:Core2022.SO.HarryAdams"
        mc:Ignorable="d"
        Title="DataContextBindingWindow" Height="450" Width="800">
    <StackPanel>
        <local:ADifferentView x:Name="frame" Height="100" DataContext="{Binding ADifferentViewModel}"/>
        <TextBlock Text="{Binding DataContext.Number, ElementName=frame}"/>
    </StackPanel>
</Window>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM