C# 绑定UserControls的元素

C# 绑定UserControls的元素,c#,wpf,binding,user-controls,C#,Wpf,Binding,User Controls,我创建了一个名为SimpleText的UserControls,并在MainWindow.xaml中引用了它。我的SimpleText中只有一个文本框(称为tbox)。在我的主窗口中有另一个文本框(称为tbox2)。我想要实现的是在这两个文本框之间有一个双向绑定 我在stackoverflow中读到,要在内部更改某些内容,必须在UserControls的代码中声明一个属性(如果不需要,请更正我): 然后我可以从MainWindow.xaml访问MyText,但只能给它“静态”值: windowx

我创建了一个名为SimpleText的UserControls,并在MainWindow.xaml中引用了它。我的SimpleText中只有一个文本框(称为tbox)。在我的主窗口中有另一个文本框(称为tbox2)。我想要实现的是在这两个文本框之间有一个双向绑定

我在stackoverflow中读到,要在内部更改某些内容,必须在UserControls的代码中声明一个属性(如果不需要,请更正我):

然后我可以从MainWindow.xaml访问MyText,但只能给它“静态”值:

windowx:Class=“WpfApplication11.MainWindow”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local=“clr命名空间:WpfApplication11”
Title=“MainWindow”Height=“350”Width=“525”>
这样说给了我一个错误:

无法在“SimpleText”类型的“MyText”属性上设置“Binding”。只能对DependencyObject的DependencyProperty设置“绑定”

但遗憾的是,我在这里非常新手,我不知道如何使我的文本成为一个独立的属性。谢谢

ripped from http://www.andrewdenhertog.com/c/create-dependencyproperty-dependencyobject-5-minutes/

public int Age
    {
        get { return (int)GetValue(AgeProperty); } //do NOT modify anything in here
        set { SetValue(AgeProperty, value); } //...or here
    }

    // Using a DependencyProperty as the backing store for Age.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty AgeProperty =
        DependencyProperty.Register(
        "Age",  //Must be the same name as the property created above
        typeof(int), //Must be the same type as the property created above
        typeof(Person), //Must be the same as the owner class
        new UIPropertyMetadata(
            0,  //default value, must be of the same type as the property
            new PropertyChangedCallback((s, e) =>  //A callback that gets executed when the property changed
            {
                var source = s as Person;
                s.DOB_Year = DateTime.Now.Year - s.Age; 
            })));
对于您的情况,它将如下所示(请注意frameworkpropertymetadataoptions.bindstwoway默认值)。我并没有实际测试这个,所以不确定语法是否正确,但这是一般的想法

public string MyText
{
    get { return (string)GetValue(MyTextProperty); } //do NOT modify anything in here
    set { SetValue(MyTextProperty, value); }
}

public static readonly DependencyProperty MyTextProperty = DependencyProperty.Register("MyText", typeof(string), typeof(SimpleText), new FrameworkPropertyMetadata(null,
                              FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                              MyTextPropertyChangedCallback));

private static void MyTextPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var source = d as SimpleText;
    source.MyText = e.NewValue.ToString();
}
更新

我试着用这个简单的例子重新创建,并注意到了你在评论中提到的同样的事情。提供了一些更深入的解释。在文章的底部,它描述了如何从父控件继承用户控件的数据上下文。您在编译时不会看到错误,但如果您这样做,您会在输出控制台中注意到数据绑定错误。修复方法是调整用户控件内的数据上下文,这可以通过两种方法完成,但最简单的方法可能是在构造函数中,将xaml(网格或堆栈面板或其他)中顶级UI元素上的数据上下文设置为自身

public SimpleText()
{
    InitializeComponent();
    grid.DataContext = this;
}

我已经试过了,但是尽管编译器没有抛出错误,绑定还是不起作用。ThanksI最终可以通过添加DataContext引用和我缺少的另一件事来设置绑定:将UserControl XAML textbox中的绑定到MyText属性。现在,我有一个奇怪的行为:如果我在主窗口文本框(tbox2)中写入,它会自动更新,但如果我在用户控制文本框(tbox)中写入,我必须单击另一个文本框才能进行更改。这与INotifyPropertyChanged有关吗?好的,这是我最后一个问题的解决方案:Text=“{Binding ElementName=miControl,Path=MyText,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}”。我认为默认的方法是在控件失去焦点时进行更新(这就是为什么当我单击另一个文本框时,值被更新)。是的。默认行为是在焦点更改时更新。你说得对。
public string MyText
{
    get { return (string)GetValue(MyTextProperty); } //do NOT modify anything in here
    set { SetValue(MyTextProperty, value); }
}

public static readonly DependencyProperty MyTextProperty = DependencyProperty.Register("MyText", typeof(string), typeof(SimpleText), new FrameworkPropertyMetadata(null,
                              FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                              MyTextPropertyChangedCallback));

private static void MyTextPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var source = d as SimpleText;
    source.MyText = e.NewValue.ToString();
}
public SimpleText()
{
    InitializeComponent();
    grid.DataContext = this;
}