仅绑定WPF控件的部分margin属性

发布于 2024-11-13 06:57:05 字数 299 浏览 3 评论 0原文

我有这个:

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

我只想绑定 TabControl 的 "Top" 部分,直观上我会这样做:

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

我该怎么做?

I have this:

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

I want to bind only the "Top" part of the TabControl, which intuitively I would do it this way:

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

How do I do it ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

梦忆晨望 2024-11-20 06:57:05

您尝试过使用这样的转换器吗?

在 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

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

编辑:
使用 MultiConverter

还可以在运行时获取所有四个值并使用 MultiValueConverter。 厚度对象的顶级属性不是依赖对象,因此您无法定义对其的绑定(除非您的源不是依赖对象)。

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>

...和 ​​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;
    }
  }

编辑(2)反向绑定:
我不确定这是否会让你高兴。以我的拙见,我会尽力避免这种情况,但是好吧...如果您的源是依赖属性,您可以将其绑定到边距:

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

但我对此有一些影响。
诀窍是,您不要将 TabControl 的 Margin 的一部分绑定到“其他内容”,而是将“其他内容”绑定到 TabControl 的 Margin 并指定 Binding-Mode OneWayToSource

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.

生寂 2024-11-20 06:57:05

实际上,控件的 Margin 属性是 Thickness 类型。因此,如果类型为 Thickness,我们可以将其绑定到 Property。

 public Thickness LeftMargin { get; set; }

您也可以设置厚度对象的一部分。就像 -

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

Xaml 中,我们可以将此属性直接绑定到任何元素的 margin 属性..就像这样..

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

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}"  />
揪着可爱 2024-11-20 06:57:05

您可以尝试类似 这个来自另一个问题的答案。

该解决方案使用允许 XAML 的附加属性,如下所示:

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

附加属性也由 DependencyObject 支持,因此数据绑定将起作用。

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.

撩人痒 2024-11-20 06:57:05

我仅在 StackPanel 中使用此解决方法来处理左边距。好处是你不需要任何转换器。

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

预览

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

永言不败 2024-11-20 06:57:05

从您的代码中,我认为您的菜单和 tabControl 可能重叠,因此您想使用边距将它们分开。我感觉这种做法就像两列CSS布局。

回到正题,我认为您可以将 TranslateFransform 应用于 TabControl.RenderTransform。您可以绑定 Y 属性。

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.

无力看清 2024-11-20 06:57:05

如果您不附加到另一个 WPF 元素,则要扩展 Ioop 的方法来控制边距而不是转换器,

创建 4 个标准属性和一个只读属性,如下所示 -

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

然后您只需添加 XAML -

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

然后在 WPF 窗口后面的代码上

Private _NewMargin as New CustomMargin

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

- 从那里您可以使用任何您想要的控件来分别更改所有 4 个边距,并且 Class 可重用于其他控件。

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.

兮子 2024-11-20 06:57:05

好吧,它很旧,但我一直在寻找更好的方法:

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

Ok it is old, but I was searching for a nicer way:

<TabControl>
    <TabControl.Margin>
        <Thickness Top="{Binding ElementName=TheMenu, Path=Height}" />
     </TabControl.Margin>
</TabControl>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文