web-dev-qa-db-fra.com

Liaison d'une partie seulement de la propriété margin du contrôle WPF

J'ai ceci:

<TabControl Margin="0,24,0,0">...</TabControl>

Je veux uniquement lier le "Top" partie de TabControl, que je ferais intuitivement de cette façon:

<TabControl Margin="0,{Binding ElementName=TheMenu, Path=Height},0,0">
 ...
</TabControl>

Comment fait-on ça ?

46
Tar

Avez-vous essayé d'utiliser un convertisseur comme celui-ci?

dans VB.Net

Public Class MarginConverter
  Implements IValueConverter

  Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
    Return New Thickness(0, CDbl(value), 0, 0)
  End Function

  Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
    Return Nothing
  End Function
End Class

Ou en C #

public class MarginConverter : IValueConverter
{

    public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return new Thickness(0, System.Convert.ToDouble(value), 0, 0);
    }

    public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}

XAML

<Window.Resources>
    <local:MarginConverter x:Key="marginConverter"></local:MarginConverter>
</Window.Resources>
<Grid>
    <StackPanel>
        <Slider Name="Slider1"></Slider>
        <TabControl Name="TabControl" Margin="{Binding ElementName=Slider1, Path=Value, Converter={StaticResource marginConverter}}">
            <Button>Some content</Button>
        </TabControl>
    </StackPanel>
</Grid>

Modifier:
Utilisation d'un multi-convertisseur

Il est également possible d'obtenir les quatre valeurs pendant l'exécution et d'utiliser un MultiValueConverter. La propriété Top de l'objet Thickness n'est pas un objet de dépendance , vous ne pouvez donc pas lui définir de liaison (sauf si votre source n'est pas un objet de dépendance).

XAML

<Window.Resources>
    <local:MarginConverter x:Key="marginConverter"></local:MarginConverter>
    <local:MultiMarginConverter x:Key="multiMarginConverter"></local:MultiMarginConverter>
</Window.Resources>
<Grid>
    <StackPanel>
        <Slider Name="Slider1"></Slider>
        <Slider Name="Slider2"></Slider>
        <Slider Name="Slider3"></Slider>
        <Slider Name="Slider4"></Slider>
        <TabControl Name="TabControl">
            <TabControl.Margin>
                <MultiBinding Converter="{StaticResource multiMarginConverter}">
                    <Binding ElementName="Slider1" Path="Value"></Binding>
                    <Binding ElementName="Slider2" Path="Value"></Binding>
                    <Binding ElementName="Slider3" Path="Value"></Binding>
                    <Binding ElementName="Slider4" Path="Value"></Binding>
                </MultiBinding>
            </TabControl.Margin>
            <Button>Some content</Button>
        </TabControl>
    </StackPanel>
</Grid>

... et c #

  class MultiMarginConverter : IMultiValueConverter
  {
    public object Convert(object[] values, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      return new Thickness(System.Convert.ToDouble(values[0]),
                           System.Convert.ToDouble(values[1]),
                           System.Convert.ToDouble(values[2]),
                           System.Convert.ToDouble(values[3]));
    }

    public object[] ConvertBack(object value, System.Type[] targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      return null;
    }
  }

Modifier (2) Reliure inversée:
Je ne sais pas si cela vous rendra heureux. À mon humble avis, j'essaierais d'éviter cela, mais ok ... Si votre source est une propriété de dépendance, vous pouvez la lier à la marge:

<Slider Name="Slider5" Minimum="-99" Maximum="0" Value="{Binding ElementName=TabControl, Path=Margin.Top, Mode=OneWayToSource}"></Slider>

Mais j'ai des effets avec ça.
L'astuce est que vous ne liez pas une partie de la marge de votre TabControl à "quelque chose d'autre", mais que vous liez "autre chose" à la marge de votre TabControl et spécifiez le mode de liaison OneWayToSource .

50
Markus

En fait, la propriété Margin d'un contrôle est de type Thickness. Nous pouvons donc le lier à la propriété si vous tapez l'épaisseur.

 public Thickness LeftMargin { get; set; }

et Vous pouvez également définir une partie d'un objet Épaisseur. Comme -

 LeftMargin = new Thickness(20,0,0,0);

et dans Xaml nous pouvons lier cette propriété directement à la propriété margin de n'importe quel élément .. comme ceci ..

 <TextBlock Text="Some Text"  Margin="{Binding LeftMargin}"  />
25
loop

Vous pouvez essayer quelque chose comme this réponse à une autre question.

La solution utilise une propriété jointe qui permet le XAML comme suit:

<Button ap:MoreProps.MarginRight="10" />

La propriété jointe est également soutenue par un DependencyObject afin que la liaison de données fonctionne.

9
bugged87

J'ai utilisé cette solution de contournement pour la marge gauche uniquement avec StackPanel. L'avantage est que vous n'avez besoin d'aucun convertisseur.

<DockPanel VerticalAlignment="Top">
  <TextBlock Name="tbkFulltextCaption"
             Text="Static Caption:"
             DockPanel.Dock="Left" />
  <StackPanel Orientation="Horizontal"
              DockPanel.Dock="Bottom">
      <FrameworkElement Name="feLeftMargin"
                        Width="{Binding Width, ElementName=tbkFulltextCaption, Mode=OneWay}" />
      <TextBlock Text="(some text with margin of tbkFulltextCaption.Width)"
                 Name="tbkUnderNonsense" 
                 FontSize="8"                                       
                 Foreground="Gray">
      </TextBlock>
  </StackPanel>
  <TextBox Name="tbFulltextSearch" />
</DockPanel>

aperç

3
adaraz

D'après votre code, je pense que votre menu et tabControl peuvent se chevaucher, vous voulez donc utiliser la marge pour les séparer. Je ressens cette pratique comme une disposition CSS à deux colonnes.

Pour en revenir au point, je pense que vous pouvez appliquer TranslateFransform à TabControl.RenderTransform. Vous pouvez lier la propriété Y.

2
Gqqnbig

Pour développer la méthode de Ioop de création d'une propriété pour contrôler la marge au lieu d'un convertisseur si vous n'êtes pas attaché à un autre élément WPF:

Créez 4 propriétés standard et une propriété en lecture seule, comme so-

Public Class CustomMargin
    Implements INotifyPropertyChanged

    Private _Left As Double
    Private _Right As Double
    Private _Up As Double
    Private _Down As Double

    Public Sub New()
      _Up = 0
      _Down = 0
      _Left = 0
      _Right = 0
    End Sub

    Public Sub New(Vertical as Double, Horizontal as Double)
      _Up = Vertical
      _Down = Vertical
      _Left = Horizontal
      _Right = Horizontal
    End Sub

    Public Sub New(Left as Double, Up as Double, Right as Double, Down as Double)
      _Up = Up
      _Down = Down
      _Left = Left
      _Right = Right
    End Sub

    Public Property Left As Double
        Get
            Return _Left
        End Get
        Set(value As Double)
            _Left = value
            OnPropertyChanged(New PropertyChangedEventArgs("MyMargin"))
        End Set
    End Property

    Public Property Right As Double
        Get
            Return _Right
        End Get
        Set(value As Double)
            _Right = value
            OnPropertyChanged(New PropertyChangedEventArgs("MyMargin"))
        End Set
    End Property

    Public Property Up As Double
        Get
            Return _Up
        End Get
        Set(value As Double)
            _Up = value
            OnPropertyChanged(New PropertyChangedEventArgs("MyMargin"))
        End Set
    End Property

    Public Property Down As Double
        Get
            Return _Down
        End Get
        Set(value As Double)
            _Down = value
            OnPropertyChanged(New PropertyChangedEventArgs("MyMargin"))
        End Set
    End Property

    Public ReadOnly Property MyMargin As Thickness
        Get
            Return New Thickness(Left, Up, Right, Down)
        End Get
    End Property

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

    Public Sub OnPropertyChanged(ByVal e As PropertyChangedEventArgs)
        If Not PropertyChangedEvent Is Nothing Then
            RaiseEvent PropertyChanged(Me, e)
        End If
    End Sub
End Class

Ensuite, il vous suffit d'ajouter le XAML-

<Label x:Name="MyLabel" Margin="{Binding Path=MyMargin, FallbackValue=0 0 0 0, Mode=OneWay}"/>

Ensuite, sur le code derrière sur la fenêtre WPF-

Private _NewMargin as New CustomMargin

Public Sub New()
  InitializeComponent()
  MyLabel.DataContext = _NewMargin
End Sub

À partir de là, vous pouvez utiliser le contrôle de votre choix pour modifier les 4 marges séparément et le Class est réutilisable pour d'autres contrôles.

1
ARidder101