简体   繁体   English

在WPF用户控件中公开一个字段以供外部使用

[英]expose a field in wpf user control for external use

I am very new to wpf and I would like to create a simple user control that consists of a textblock and a textbox so that I can reuse it. 我是wpf的新手,我想创建一个由文本块和文本框组成的简单用户控件,以便我可以重用它。 However, I do not really know how to bind the content of the textblock so that it can be set from outside and expose the textbox so that it could be bound to other field from the outside calling xaml. 但是,我真的不知道如何绑定文本块的内容,以便可以从外部设置它并公开文本框,以便可以从外部调用xaml将其绑定到其他字段。

The following is the code for my user control 以下是我的用户控件的代码

<UserControl x:Class="WPFLib.UserControlLibs.TextBoxUsrCtrl"
                         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:WPFLib.UserControlLibs"
                         mc:Ignorable="d"
                         d:DesignHeight="20"
                         d:DesignWidth="300">
    <StackPanel Orientation='Horizontal'
                            Width='{Binding ActualWidth, ElementName=parentElementName}'
                            Height='{Binding ActualWidth, ElementName=parentElementName}'>
        <Grid HorizontalAlignment='Stretch'>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width='1*' />
                <ColumnDefinition Width='1*' />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <TextBlock Text='{Binding Text, ElementName=parentElementName}'
                                 Background='Aqua'
                                 Grid.Column='0'
                                 Grid.Row='0' />
            <TextBox x:Name='UserTxBox'
                             Grid.Column='1'
                             Grid.Row='0'
                             Background='Red'
                             HorizontalAlignment='Stretch'
                             Text='this is a test to see how it works' />
        </Grid>
    </StackPanel>
</UserControl>

How do I expose the Text from the TextBlock and TextBox so that it could be set and retrieved from the calling xaml? 如何从TextBlock和TextBox中公开文本,以便可以设置它并从调用xaml中检索它?

For example 例如

        <Window x:Class="TestWPF.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"
                        xmlns:local="clr-namespace:TestWPF"
                          xmlns:controls='clr-namespace:WPFLib.UserControlLibs'
    `                   mc:Ignorable="d"
                        Title="MainWindow"
                        Height="350"
                        Width="525"
                        WindowState='Maximized'
                        FontSize='18'>
            <StackPanel>                                    
<controls:TextBoxUsrCtrl Width='500' HorizontalAlignment='Left' **Text='NEED TO SET THE TEXT BLOCK HERE'**/>
            </StackPanel>
        </Window>

You should give it two dependency properties, one for each of the two text properties you want to expose (this is a horrible amount of boilerplate; I use Visual Studio's snippet feature to generate it all). 您应该为它提供两个依赖项属性,对于要公开的两个文本属性,每个属性都应具有一个属性(这真是令人难以置信;我使用Visual Studio的代码段功能来生成所有这些属性)。 Then in the UserControl XAML, you bind control properties to those. 然后在UserControl XAML中,将控件属性绑定到那些控件。

public partial class TextBoxUsrCtrl : UserControl
{
    public TextBoxUsrCtrl()
    {
        InitializeComponent();
    }

    #region Text Property
    public String Text
    {
        get { return (String)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register(nameof(Text), typeof(String), typeof(TextBoxUsrCtrl),
            new FrameworkPropertyMetadata(null) {
                //  It's read-write, so make it bind both ways by default
                BindsTwoWayByDefault = true
            });
    #endregion Text Property

    #region DisplayText Property
    public String DisplayText
    {
        get { return (String)GetValue(DisplayTextProperty); }
        set { SetValue(DisplayTextProperty, value); }
    }

    public static readonly DependencyProperty DisplayTextProperty =
        DependencyProperty.Register(nameof(DisplayText), typeof(String), typeof(TextBoxUsrCtrl),
            new PropertyMetadata(null));
    #endregion DisplayText Property
}

XAML. XAML。 I simplified this so the layout works as I think you intended. 我对此进行了简化,因此布局可以按照您的预期工作。

Note how the bindings use RelativeSource={RelativeSource AncestorType=UserControl} to bind to the dependency properties we defined above on the UserControl . 请注意,绑定如何使用RelativeSource={RelativeSource AncestorType=UserControl}绑定到我们在UserControl上定义的依赖项属性。 By default, Binding will bind to properties of UserControl.DataContext , but we're not using that. 默认情况下, Binding将绑定到UserControl.DataContext属性,但是我们没有使用它。 The reason is that if we set UserControl.DataContext here, that will break the viewmodel property bindings in the final XAML fragment at the end of this answer. 原因是,如果在此处设置UserControl.DataContext ,则会在此答案的最后破坏最终XAML片段中的viewmodel属性绑定。 Those bindings will look for those properties on our control . 这些绑定将在控件上寻找那些属性。 There are workarounds but it gets ugly. 有一些解决方法,但它变得丑陋。 The way I've done it here is best because it never breaks anybody's assumptions about DataContext inheritance. 我在这里完成此操作的方式是最好的,因为它永远不会破坏任何人对DataContext继承的假设。

<UserControl 
    x:Class="WPFLib.UserControlLibs.TextBoxUsrCtrl"
    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:WPFLib.UserControlLibs"
    mc:Ignorable="d"
    d:DesignHeight="20"
    d:DesignWidth="300"
    >
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width='*' />
            <ColumnDefinition Width='*' />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBlock 
            Text='{Binding DisplayText, RelativeSource={RelativeSource AncestorType=UserControl}}'
            Background='Aqua'
            Grid.Column='0'
            Grid.Row='0' 
            />
        <TextBox 
            x:Name='UserTxBox'
            Grid.Column='1'
            Grid.Row='0'
            Background='Red'
            HorizontalAlignment='Stretch'
            Text='{Binding Text, RelativeSource={RelativeSource AncestorType=UserControl}}'
            />
    </Grid>
</UserControl>

Usage in window, bound to viewmodel properties: 在窗口中的用法,绑定到viewmodel属性:

    <local:TextBoxUsrCtrl
        Text="{Binding TestText}"
        DisplayText="{Binding ShowThisText}"
        />

Lastly, I'm not sure what you were getting at with ElementName=parentElementName . 最后,我不确定您使用ElementName=parentElementName得到什么。 If that's meant to be a reference to a parent control, you can't do that, and it wouldn't be a good idea if you could. 如果这是对父控件的引用,则不能这样做,如果可以的话,也不是一个好主意。 You wouldn't want a UserControl constrained by a requirement that a parent control must have a particular name. 您不希望UserControl受到父控件必须具有特定名称的要求的约束。 The answer to that requirement is simply that controls in XAML are only responsible for sizing themselves if they have a fixed size. 该要求的答案很简单,即XAML中的控件仅在大小固定的情况下才负责调整自身大小。 If they should size to the parent, the parent is always the one responsible for that. 如果他们要适合父母,那么父母永远是负责任的人。 So if you want to size two instances of TextBoxUsrCtrl to two different parents, that's fine. 因此,如果您想将TextBoxUsrCtrl两个实例的大小TextBoxUsrCtrl为两个不同的父级,那就很好。 Each parent sizes its own children as it pleases. 每个父母都可以根据自己的意愿给自己的孩子定尺寸。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM