web-dev-qa-db-fra.com

Liaison à une propriété de dépendance personnalisée - à nouveau

OK je sais. Cela a été demandé un million de fois, mais je ne comprends toujours pas. Désolé.

La tâche: implémenter la propriété de dépendance la plus simple de tous les temps, qui peut être utilisée dans xaml comme ça:

<uc:MyUserControl1 MyTextProperty="{Binding Text}"/>

Je pense que this réponse est assez proche. Pour une meilleure lisibilité, je copie tout mon code ici (principalement à partir de cette réponse ci-dessus).

<UserControl x:Class="Test.UserControls.MyUserControl1"
             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" 
             DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
        <!-- Text is being bound to outward representative property;
             Note the DataContext of the UserControl -->
        <TextBox Text="{Binding MyTextProperty}"/>
    </Grid>
</UserControl>

et

public partial class MyUserControl1 : UserControl
{
    // The dependency property which will be accessible on the UserControl
    public static readonly DependencyProperty MyTextPropertyProperty =
        DependencyProperty.Register("MyTextProperty", typeof(string), typeof(MyUserControl1), new UIPropertyMetadata(String.Empty));
    public string MyTextProperty
    {
        get { return (string)GetValue(MyTextPropertyProperty); }
        set { SetValue(MyTextPropertyProperty, value); }
    }

    public MyUserControl1()
    {
        InitializeComponent();
    }
}

Et voici mon MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml" xmlns:uc="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel Orientation="Vertical">
        <uc:MyUserControl1 MyTextProperty="my text goes here"/>
        <Button Click="ButtonBase_OnClick" Content="click"/>
    </StackPanel>
</Window>

Jusqu'à présent, tout fonctionne. Cependant, je trouve cela tout à fait inutile. Ce dont j'ai besoin c'est

<uc:MyUserControl1 MyTextProperty="{Binding Text}"/>

et pouvoir changer cela en définissant un DataContext (comme vous le faites habituellement dans MVVM)

Je remplace donc la ligne comme ci-dessus et ajoute mon code derrière comme suit:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();
        Text = "Initial Text";
        DataContext = this;
    }
    private string _Text;
    public string Text
    {
        get { return _Text; }
        set
        {
            if (value != _Text)
            {
                _Text = value;
                NotifyPropertyChanged("Text");
            }
        }
    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        Text = "clicked";
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

Ni le "Texte initial" ni le "cliqué" ne sont affichés ... jamais. Ma question est donc de savoir comment mettre en œuvre un département. propriété à utiliser correctement avec

<uc:MyUserControl1 MyTextProperty="{Binding Text}"/>

? Merci pour votre aide.

23
Martin Booka Weser

La propriété Text est située sur le DataContext du MainWindow et non du UserControl.

Alors changez cette ligne <uc:MyUserControl1 MyTextProperty="{Binding Text}"/> dans ceci:

<uc:MyUserControl1 MyTextProperty="{Binding Text, ElementName=MyMainWindow}"/>

Ce qui indiquera à la liaison que vous parlez de l'élément texte situé dans votre fenêtre principale. Bien sûr, puisque dans cet exemple j'ai utilisé ElementName, vous allez vouloir nom votre fenêtre MyMainWindow ...

Alors ajoutez ceci à votre MainWindow:

<Window  Name="MyMainWindow" ..... />

Si vous préférez ne pas nommer votre fenêtre, vous pouvez utiliser la liaison RelativeSource FindAncestor comme ceci:

<wpfApplication6:MyUserControl1 MyTextProperty="{Binding Text, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"/>

Dans les deux cas, vous demandez de trouver la propriété nommée 'Text' dans le DataContext de la fenêtre.

28
Blachshma