如何从 UserControl 访问 WPF 页面中的公共变量?
Posted
技术标签:
【中文标题】如何从 UserControl 访问 WPF 页面中的公共变量?【英文标题】:How to access a public variable in a WPF Page from a UserControl? 【发布时间】:2021-12-06 16:46:57 【问题描述】:我有一个承载用户控件的 WPF 页面。 UserControl 有一个按钮,它可以做一些事情并最终想要更改绑定到页面上 DataGrid 的列表。不幸的是,我无法访问此列表/数据网格。似乎页面可以访问托管用户控件中的所有公共变量,但用户控件无法访问页面中的任何变量...有人可以帮我吗?
这是我页面的 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>
【问题讨论】:
【参考方案1】:这是一个非常简单的例子:
页面数据上下文是一个带有公共列表的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();
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>
窗口代码:
namespace WpfApp1
public partial class MainWindow
public MainWindow()
InitializeComponent();
【讨论】:
你有MVVM的M和V,为什么不加VM呢? 是的,你是对的。我将实现视图模型。谢谢 我会得到一个 InvalidOperationException:“由于对象的当前状态,该操作无效”。这是为什么呢? @Antelito 这是因为我检查了数据上下文确实是一个模型,如果我没有,你会得到一个 NullReferenceException 。在您的项目中复制我的代码时,您肯定忘记了一些东西,我发布的示例运行良好。【参考方案2】:您可以在可视化树中找到父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);
【讨论】:
以上是关于如何从 UserControl 访问 WPF 页面中的公共变量?的主要内容,如果未能解决你的问题,请参考以下文章
如何从UserControl访问父级的DataContext