Как параметризовать привязку в wpf UserControl? - PullRequest
0 голосов
/ 25 мая 2018

У меня есть окно wpf (MyWindow) с DataContext, установленным для класса модели MyViewModel:

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

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

MyViewModel.cs

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

    ...
}

Я хотел бы передать привязку свойства MyText из MyWindow в следующий UserControl (MyUserControl):

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

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();
        }
    }

Я хотел бы получить содержимое, набранное в Textbox в MyUserControl в MyViewModel.MyText. Как этого достичь?

Я пытался связать MyText со свойством Text в MyUserControl, а затем впоследствии связывать Text в TextBox с Textс MyUserControl но это не работает.

Ответы [ 2 ]

0 голосов
/ 28 мая 2018

Наконец-то мне удалось привязать свойство в модели представления из UserControl программно.

MyUserControl используется следующим образом:

<UserControls:MyUserControl TargetPropertyName="TestId"/>

Я просто передаю имясвойство модели представления, которое я хочу привязать внутри пользовательского элемента управления.

Затем внутри пользовательского элемента управления я обязательно программно связываю свойство по имени на 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);
            }
        }
    }

Но все же я считаю, что это обходной путь, должно быть лучшее решение.

0 голосов
/ 25 мая 2018

избавиться от TextPropertyChangedHandler.

DP нужен только флаг BindsTwoWayByDefault, без обратного вызова

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

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>

свойства проверки должны перейти к привязке в Window:

<MyUserControl Text="{Binding MyText, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" />
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...