C# 从WPF中的主窗口访问UserControl中的对象
我有这个简单的XAML,如何从C# 从WPF中的主窗口访问UserControl中的对象,c#,wpf,xaml,C#,Wpf,Xaml,我有这个简单的XAML,如何从主窗口更改TextBlock中UserControl1的Text属性 <Window x:Class="RefactorXAML.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:refa
主窗口更改TextBlock
中UserControl1
的Text
属性
<Window x:Class="RefactorXAML.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:refactorXaml="clr-namespace:RefactorXAML"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
</Grid.RowDefinitions>
<Grid>
<refactorXaml:UserControl1></refactorXaml:UserControl1>
</Grid>
<Grid Grid.Row="1">
<Button>Change Text</Button>
</Grid>
</Grid>
</Window>
<UserControl x:Class="RefactorXAML.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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<TextBlock x:Name="MyTextblock">StackOverflow</TextBlock>
</UserControl>
更改文本
堆栈溢出
为用户控件设置名称:
<refactorXaml:UserControl1 x:Name="MyUserControl1" />
或者短得多:
var text = MyUserControl1.FindName("MyTextblock") as TextBlock;
if (text != null)
text.Background = Brushes.Red;
如果您讨厌MVVM
,可以添加公共属性。但是MVVM将使更新源和目标变得容易。在这种情况下,您可以使用dependencProperty
无MVVM
这是你的UC的外观
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public string TextBlockContent { get; set; }
}
您的主窗口是XAML
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:refactorXaml="clr-namespace:WpfApplication3"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
</Grid.RowDefinitions>
<Grid>
<refactorXaml:UserControl1 Name="MyUserControl1"></refactorXaml:UserControl1>
</Grid>
<Grid Grid.Row="1">
<Button Click="ButtonBase_OnClick">Change Text</Button>
</Grid>
</Grid>
</Window>
WPF中的控件通常意味着某种“黑匣子”。你不应该(通常也不应该)关心里面发生了什么。相反,如果希望允许通信,可以定义该控件的用户可以与之通信的公共接口
在WPF中,此公共接口通常使用。您也可以对许多事情使用普通(CLR)属性,但通常您希望允许数据绑定之类的事情,然后需要依赖性属性。定义依赖属性比定义普通属性要复杂一些,因为它们需要额外完成一些工作。在VisualStudio中,有一个propdp
代码段,它可以帮助您在几个简单的步骤中添加所有样板代码
因此,对于您的用户控件,我们有一个字符串属性,我们希望将其公开给外部。因此,在该用户控件的代码隐藏中,我们将该属性定义为依赖属性:
public partial class ExampleUserControl : UserControl
{
public static readonly DependencyProperty SomeTextProperty =
DependencyProperty.Register("SomeText", typeof(string), typeof(ExampleUserControl), new PropertyMetadata("default value"));
public string SomeText
{
get { return (string)GetValue(SomeTextProperty); }
set { SetValue(SomeTextProperty, value); }
}
// this is the same old stuff
public ExampleUserControl()
{
InitializeComponent();
}
}
这就是我们要声明属性并使其可供组件用户使用所需的全部操作。现在我们只需要添加功能。由于不涉及一些额外的逻辑,但是您只想将值委托给其他组件的属性(TextBlocks的Text
property),因此我们可以使用数据绑定。这在大多数情况下都适用:
<UserControl x:Class="SomeNamespace.ExampleUserControl" …
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<StackPanel>
<TextBlock Text="{Binding SomeText}" />
</StackPanel>
</UserControl>
由于它是一个依赖属性,我们还可以使用数据绑定从其他地方获取值(例如,使用MVVM时的视图模型):
最后,我们有了一个可重用组件,它与所使用的应用程序完全分离。应用程序不需要知道该组件的实现,组件也不需要知道它将在何处使用。不幸的是,我讨厌MVVM:(MVVM实际上与此无关。当您创建用户控件时,您创建的是一个独立的组件。该组件具有一些接口,您可以使用不同的方式使用这些接口。一种是使用数据绑定,另一种是使用代码(例如,在代码隐藏中).Data binding非常有用,即使您不使用MVVM。(使用Data binding并不意味着您正在使用MVVM。Data binding是允许MVVM的核心部分,但Data binding以前就已经存在,并且在没有MVVM的情况下被广泛使用).@poke感谢poke的澄清,我知道我在抵制所有这些新概念,但最终我会放弃。我记得我很难理解OOP的新概念,现在没有它我什么都做不了。@Vahid别担心,慢慢来。我知道一开始真的很困惑,尤其是自从你倾向于一次发现所有的东西,这给了你一堵需要克服的巨大的新东西墙。但是一旦你通过了它,你就会看到更干净的代码、分离关注点和提高速度的所有好处,你会想知道为什么你之前拒绝这样做:)这是真的,当我拒绝学习OOP时,我收到了同样的建议,现在我想知道我是如何使用OOP完成所有这些的。所以诀窍是首先在代码隐藏中创建一个用户控件的实例。对吗?@Vahid:不,用户控件的实例是在XAML中创建的,你只需在控件中的代码隐藏中获得它。稍后,尝试to使用FindName()查找控件
函数。这不是一个很好的解决方案……没有分离关注点,而且您正在向家长泄露实现细节。@poke:我同意,OP说他讨厌MVVM,所以我展示了最简单的解决方案。我刚刚发现,如果我在主窗口中创建UserControl1
代码的实例,我可以请不要更改它的任何属性。但正如@poke所说,这违反了关注点分离规则。我现在很难理解所有这些。但我知道这是正确的方法。谢谢,但是什么是TextBlockContent
?这是您定义的新属性吗?我想正确地更改文本ty?很遗憾,这个答案缺少CLR属性TextBlockContent
和用户控件的文本块之间的连接。@是的,我猜是这样的。
public partial class ExampleUserControl : UserControl
{
public static readonly DependencyProperty SomeTextProperty =
DependencyProperty.Register("SomeText", typeof(string), typeof(ExampleUserControl), new PropertyMetadata("default value"));
public string SomeText
{
get { return (string)GetValue(SomeTextProperty); }
set { SetValue(SomeTextProperty, value); }
}
// this is the same old stuff
public ExampleUserControl()
{
InitializeComponent();
}
}
<UserControl x:Class="SomeNamespace.ExampleUserControl" …
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<StackPanel>
<TextBlock Text="{Binding SomeText}" />
</StackPanel>
</UserControl>
<my:ExampleUserControl SomeText="Foo" />
<my:ExampleUserControl SomeText="{Binding SomeTextProperty}" />
<my:ExampleUserControl x:Name="myControl" SomeText="Foo" />
<Button Click="ChangeText_Click" Content="Change text" />
private void ChangeText_Click (object sender, RoutedEventArgs e)
{
myControl.SomeText = "Bar";
}