簡體   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