简体   繁体   English

如何在WPF UserControl中参数化绑定?

[英]How to parametrize binding in wpf UserControl?

I have a wpf Window ( MyWindow ) with its DataContext set to the MyViewModel view model class: 我有一个wpf窗口( MyWindow ),其DataContext设置为MyViewModel视图模型类:

MyWindow.xaml MyWindow.xaml

<Window x:Class="MyProject.MyWindow"
      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">

      <MyUserControl Text="{Binding MyText, Mode=TwoWay}" />
</Window>

MyWindow.xaml.cs MyWindow.xaml.cs

public class MyWindow : Window
{
    MyWindow()
    {
       InitializeComponent();
       DataContext = new MyViewModel();
    }
}

MyViewModel.cs MyViewModel.cs

// MyViewModel implements IPropertyChanged
public class MyViewModel : INotifyPropertyChanged
{
    public string MyText { get { ... } set { ... } }

    ...
}

I would like to pass the binding of the MyText property from MyWindow to the following UserControl ( MyUserControl ): 我想将MyText属性的绑定从MyWindow传递给以下UserControl( MyUserControl ):

MyUserControl.xaml MyUserControl.xaml

<UserControl x:Class="MyProject.MyUserControl"
             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">
    <StackPanel>
        <TextBox
            Name="MainTextBox"
            Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True}"  
        />
    </StackPanel>
</UserControl>

MyUserControl.xaml.cs MyUserControl.xaml.cs

public partial class MyUserControl : UserControl
    {
        public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
            "Text",
            typeof(string),
            typeof(MyUserControl),
            new UIPropertyMetadata(TextPropertyChangedHandler)
        );

        public static void TextPropertyChangedHandler(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var MyUserControl = sender as MyUserControl;

            MyUserControl.Text = (string)e.NewValue;
        }

        public string Text
        {
            get
            {
                return (string)GetValue(TextProperty);
            }
            set
            {
                SetValue(TextProperty, value);
            }
        }


        public MyUserControl()
        {
            InitializeComponent();
        }
    }

I would like to get the content typed in the Textbox under MyUserControl into MyViewModel.MyText . 我想将在MyUserControl下的Textbox键入的内容放入MyViewModel.MyText How can this be achieved? 如何做到这一点?

I tried to bind MyText to the Text property in MyUserControl and then subsequently binding Text in TextBox to Text from MyUserControl but this does not work. 我试图绑定MyTextText的属性MyUserControl并随后绑定TextTextBoxTextMyUserControl但这不起作用。

get rid of TextPropertyChangedHandler . 摆脱TextPropertyChangedHandler

DP needs only BindsTwoWayByDefault flag, without callback DP仅需要BindsTwoWayByDefault标志,而无需回调

public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
    "Text",
    typeof(string),
    typeof(MyUserControl),
    new FrameworkPropertyMetadata(null,
        FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)
);

TextBox.Text should bind to MyUserControl.Text TextBox.Text应该绑定到MyUserControl.Text

<UserControl x:Class="MyProject.MyUserControl" x:Name="self"
             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">
    <StackPanel>
        <TextBox Text="{Binding Text, Mode=TwoWay, ElementName=self}"  />
    </StackPanel>
</UserControl>

validation properties should go to binding in Window: 验证属性应转到Window中的绑定:

<MyUserControl Text="{Binding MyText, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" />

I finally managed to bind to the property in the view model from the UserControl programatically. 我终于设法以编程方式从UserControl绑定到视图模型中的属性。

The MyUserControl is used as follows: MyUserControl的用法如下:

<UserControls:MyUserControl TargetPropertyName="TestId"/>

I just pass the name of the property of the View Model that I wish to bind to inside the user control. 我只是将希望绑定到的View模型的属性名称传递给用户控件。

Then inside the user control I make sure to programatically bind the property by name on the MainTextBox (here in the BindTextPropertyToTargetPropertyNameOnce ): 然后,在用户控件中,我确保以编程方式通过MainTextBox上的名称绑定属性(在此处为BindTextPropertyToTargetPropertyNameOnce ):

public partial class MyUserControl : UserControl
    {
        public static readonly DependencyProperty TargetPropertyNameProperty = DependencyProperty.Register(
            "TargetPropertyName",
            typeof(string),
            typeof(MyUserControl),
            new UIPropertyMetadata(TargetPropertyNamePropertyChangedHandler)
        );

        public static void TargetPropertyNamePropertyChangedHandler(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var MyUserControl = sender as MyUserControl;

            MyUserControl.TargetPropertyName = (string)e.NewValue;
        }

        public string TargetPropertyName
        {
            get
            {
                return (string)GetValue(TargetPropertyNameProperty);
            }
            set
            {
                SetValue(TargetPropertyNameProperty, value);
                BindTextPropertyToTargetPropertyNameOnce()
            }
        }

        public MyUserControl()
        {
            InitializeComponent();
        }

        private bool _firstRun = true;

        private void BindTextPropertyToTargetPropertyNameOnce()
        {
            if (_firstRun)
            {
                _firstRun = false;
                var binding = new Binding(TargetPropertyName)
                {
                    Mode = BindingMode.TwoWay,
                    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
                    ValidatesOnDataErrors = true,
                    NotifyOnValidationError = true
                };

                MainTextBox.SetBinding(TextBox.TextProperty, binding);
            }
        }
    }

But still I consider this to be a workaround, there must be a better solution. 但是我仍然认为这是一种解决方法,必须有更好的解决方案。

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

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