Binding only part of the margin property of WPF control

后端 未结 7 1332
忘掉有多难
忘掉有多难 2020-12-01 03:49

I have this:

...

I want to bind only the \"Top\" part of the TabContr

相关标签:
7条回答
  • 2020-12-01 03:50

    Actually Margin property of a control is of Thickness Type. So we can bind it to Property if type Thickness.

     public Thickness LeftMargin { get; set; }
    

    and You can set a part of a Thickness object too. Like -

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

    and in Xaml we can bind this property directly to margin property of any element..like this..

     <TextBlock Text="Some Text"  Margin="{Binding LeftMargin}"  />
    
    0 讨论(0)
  • 2020-12-01 03:51

    From your code, I figure that your menu and tabControl may overlap, so you want to use margin to separate them. I feel this practice like two Column CSS Layout.

    Back to the point, I think you can apply TranslateFransform to TabControl.RenderTransform. You can bind Y property.

    0 讨论(0)
  • 2020-12-01 03:55

    I have used this workaround for left margin only with StackPanel. Benefit is that you don't need any Converter.

    <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>
    

    preview

    0 讨论(0)
  • 2020-12-01 03:57

    To expand on Ioop's method of making a property to control margin instead of a converter if you aren't attaching to another WPF element:

    Create 4 standard properties and a readonly property, like 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
    

    Then you just have to add the XAML-

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

    Then on the code behind on the WPF window-

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

    From there you can use whatever control you desire to change all 4 margins separately and the Class is reusable for other controls.

    0 讨论(0)
  • 2020-12-01 04:02

    Have you tried using a converter like this?

    in 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
    

    Or in 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>
    

    Edit:
    Using a MultiConverter

    It is also possible to get all four values during run-time and use a MultiValueConverter. The Top-Property of the Thickness-Object is not a Dependency-Object, therefor you can't define a binding to it (unless your source is not a Dependency-Object).

    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>
    

    ... and 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;
        }
      }
    

    Edit(2) Reverse-Binding:
    I'm not sure if this will make you happy. In my humble opinion I would try to avoid this, but ok... If your source is a Dependency-Property, you can bind this to the Margin:

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

    But I've got some effects with this.
    The trick is, that you do not bind a part of the Margin of your TabControl to "something else", but bind "something else" to the Margin of your TabControl and specify Binding-Mode OneWayToSource.

    0 讨论(0)
  • 2020-12-01 04:03

    You could try something like this answer from another question.

    The solution uses an attached property that allows for XAML like the following:

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

    The attached property is also backed by a DependencyObject so data binding will work.

    0 讨论(0)
提交回复
热议问题