web-dev-qa-db-ja.com

WPFコントロールのmarginプロパティの一部のみをバインド

私はこれを持っています:

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

TabControlの"Top"部分のみをバインドしたいのですが、直観的には次のようにします。

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

どうすればいいのですか ?

46
Tar

このようなコンバーターを使用してみましたか?

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の使用

実行時に4つの値すべてを取得し、MultiValueConverterを使用することもできます。 Thickness-ObjectのTop-PropertyはDependency-Objectではないため、バインディングを定義することはできません(ソースが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>

...および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:
これがあなたを幸せにするかどうかはわかりません。私の謙虚な意見では、私はこれを避けようとしますが、OK ...あなたのソースが依存関係プロパティである場合、これをマージンにバインドできます:

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

しかし、これにはいくつかの効果があります。
トリックは、TabControlのMarginの一部を「他の何か」にバインドせず、TabControlのMarginに「他の何か」をバインドし、Binding-ModeOneWayToSource

50
Markus

実際、コントロールのMarginプロパティはThicknessタイプです。そのため、Thickness型の場合、プロパティにバインドできます。

 public Thickness LeftMargin { get; set; }

また、Thicknessオブジェクトの一部も設定できます。お気に入り -

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

Xamlでは、このプロパティを任意の要素のmarginプロパティに直接バインドできます。

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

this 別の質問からの回答のようなものを試すことができます。

ソリューションでは、次のようなXAMLを許可する添付プロパティを使用します。

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

添付プロパティもDependencyObjectによってサポートされているため、データバインディングが機能します。

9
bugged87

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>

プレビュー

3
adaraz

あなたのコードから、私はあなたのメニューとtabControlが重複するかもしれないので、それらを分離するためにマージンを使いたいと思っています。このプラクティスは2列のCSSレイアウトのように感じます。

ポイントに戻ると、TranslateFransformTabControl.RenderTransformに適用できると思います。 Yプロパティをバインドできます。

2
Gqqnbig

別の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は他のコントロールに再利用できます。

1
ARidder101