如何从 UserControl 访问 WPF 页面中的 public 变量?

How to access a public variable in a WPF Page from a UserControl?

我有一个托管 UserControl 的 WPF 页面。 UserControl 有一个 Button,它执行某些操作并最终想要更改绑定到 Page 上的 DataGrid 的 List。很遗憾,我无法访问此 List/DataGrid。页面似乎可以访问托管 UserControl 中的所有 public 变量,但 UserControl 无法访问页面中的任何变量...有人可以帮我吗?

这是我页面的 xaml:

<Page x:Class="SchrauberDB.View.Werkzeug_Window"
  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:SchrauberDB.Controls"
  xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
  Title="Werkzeug_Window"
  mc:Ignorable="d" 
  FontFamily="../Fonts/Poppins/#Poppins"

  d:DesignWidth="1400" d:DesignHeight="950"
  >

    <StackPanel
                Orientation="Horizontal"
                VerticalAlignment="Center"
                HorizontalAlignment="Right"
                Margin="0,0,0,0.2" Width="404"
                >

        <Button 
            Height="45" Width="150"  
            Margin="20,0,0,0"
            Background="{x:Null}" 
            Click="FilterMaske_Click"
            >

            <StackPanel Margin="0,0,0,0" HorizontalAlignment="Left" Width="90">

                <Image Height="30" Width="30" HorizontalAlignment="Left" Source="Assets\filter-outline_black.png" />
                <Label Content="Filter" HorizontalAlignment="Center" Margin="20,-30,0,0"  FontSize="14" Height="30"/>
            </StackPanel>
        </Button>

    </StackPanel>

    <DataGrid x:Name="DataGrid" 
              AlternatingRowBackground="#F8F8F8" Margin="40,60,40,45"
              Grid.Column="2" Grid.ColumnSpan="10"
              Grid.Row="1" Grid.RowSpan="12"
              RowHeight="47"
              ColumnHeaderHeight="47"
              Padding="0"
              FontSize="18"
              ColumnWidth="150"
              HorizontalScrollBarVisibility="Visible"
              AutoGenerateColumns ="False"
              >
        
        <DataGrid.Columns >
            <DataGridTextColumn x:Name="filter" Header="Filter" FontSize="18"   IsReadOnly="True" Binding="{Binding Path=filter}"></DataGridTextColumn>
            <DataGridTextColumn x:Name="bemiNr" Header="Bemi Nr" FontSize="18"   IsReadOnly="True" Binding="{Binding Path=bemiNr}"></DataGridTextColumn>
        </DataGrid.Columns>

    </DataGrid>

    <local:FilterWerkzeug x:Name="Filtermaske" Padding="10" Visibility="Collapsed"></local:FilterWerkzeug>
</Grid>

在页面的代码隐藏中,我有一个绑定到 DataGrid 的列表:

public List<DataModel.Werkzeug> werkzeuge = new List<DataModel.Werkzeug>();
//Some logic...
DataGrid.ItemsSource = werkzeuge;

在 UserControl 的代码隐藏中,我有一个最终想要更新列表 werkzeuge 的按钮

这是 UserControl 的 xaml:

<UserControl x:Class="SchrauberDB.Controls.FilterWerkzeug"
         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:SchrauberDB.Controls"
         mc:Ignorable="d" 
         d:DesignHeight="200" d:DesignWidth="1100"
         FontFamily="../Fonts/Poppins/#Poppins">

<Grid Background="#FEFFFF" >
    <StackPanel Grid.Row="0" Grid.Column="0">
        <TextBlock>filter</TextBlock>
        <ComboBox x:Name="cbFilter" Width="150"/>
    </StackPanel>

    <Button Height="45" Width="130" Margin="17.6,14.4,10,7" Click="Button_Click">
        <TextBlock  FontSize="14" FontWeight="Medium">
            Filter
        </TextBlock>
    </Button>
</Grid>
</UserControl>

这是一个非常简单的示例:

  • 页面数据上下文是具有 public 列表的 Model 对象
  • 页面显示列表
  • 页面显示一个用户控件
  • 此用户控件有一个按钮
  • 该按钮更新 Model
  • 中的列表

型号:

using System.Collections.ObjectModel;

namespace WpfApp1
{
    public class Model
    {
        public ObservableCollection<string> Strings { get; } = new();
    }
}

用户控件XAML:

<UserControl x:Class="WpfApp1.UserControl1"
             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:wpfApp1="clr-namespace:WpfApp1"
             mc:Ignorable="d"
             d:DataContext="{d:DesignInstance wpfApp1:Model}"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Button Content="Add" Click="ButtonBase_OnClick" />
    </Grid>
</UserControl>

用户控制码:

using System;
using System.Windows;

namespace WpfApp1
{
    public partial class UserControl1
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            var model = DataContext as Model ?? throw new InvalidOperationException();
            model.Strings.Add(DateTime.Now.ToString("O"));
        }
    }
}

页面XAML:

<Page x:Class="WpfApp1.Page1"
      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:WpfApp1"
      mc:Ignorable="d"
      d:DesignHeight="450" d:DesignWidth="800"
      Title="Page1"
      d:DataContext="{d:DesignInstance local:Model}">

    <Page.DataContext>
        <local:Model />
    </Page.DataContext>

    <StackPanel>
        <local:UserControl1 />
        <ItemsControl ItemsSource="{Binding Strings}" />
    </StackPanel>

</Page>

页面代码:

namespace WpfApp1
{
    public partial class Page1
    {
        public Page1()
        {
            InitializeComponent();
        }
    }
}

window XAML:

<NavigationWindow x:Class="WpfApp1.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"
                  mc:Ignorable="d"
                  Source="Page1.xaml">
</NavigationWindow>

window代码:

namespace WpfApp1
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

您可以在可视化树中找到父级 Page,然后直接访问 DataGrid

private void Button_Click(object sender, RoutedEventArgs e)
{
    Werkzeug_Window page = FindParent<Werkzeug_Window>(this);
    page.DataGrid = ...;
}

private static T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
{
    var parent = VisualTreeHelper.GetParent(dependencyObject);

    if (parent == null) return null;

    var parentT = parent as T;
    return parentT ?? FindParent<T>(parent);
}