如何从 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);
}
我有一个托管 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);
}