C# 如何仅在 XAML 中设置上边距?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1316405/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 15:03:20  来源:igfitidea点击:

How to set a top margin only in XAML?

c#wpfxamlmargins

提问by Edward Tanguay

I can set margins individually in codebut how do I do it in XAML, e.g. how do I do this:

我可以在代码中单独设置边距,但如何在 XAML 中进行设置,例如我如何执行此操作:

PSEUDO-CODE:

伪代码:

<StackPanel Margin.Top="{Binding TopMargin}">

采纳答案by Kent Boogaart

The key is to realize that setting it in code like this:

关键是要意识到在代码中设置它是这样的:

sp2.Margin = new System.Windows.Thickness{ Left = 5 };

is equivalent to:

相当于:

sp2.Margin = new System.Windows.Thickness{ Left = 5, Top = 0, Right = 0, Bottom = 0 };

You can'tset just a single value in a Thicknessinstance through either code or XAML. If you don't set some of the values, they will be implicitly zero. Therefore, you can just do this to convert the accepted code sample in your other question to a XAML equivalent:

不能通过代码或 XAMLThickness实例中仅设置单个值。如果您不设置某些值,它们将隐式为零。因此,您只需执行此操作即可将其他问题中接受的代码示例转换为 XAML 等效项:

<StackPanel Margin="{Binding TopMargin, Converter={StaticResource MyConverter}}"/>

where MyConverterjust returns a Thicknessthat sets only the Topand leaves all other values as zero.

where MyConverterjust return aThickness只设置 theTop并将所有其他值保留为零。

Of course, you could write your own control that doesexpose these individual values as dependency properties to make your code a little cleaner:

当然,你可以写你自己的控件,公开为依赖属性,这些单独的值,使你的代码干净了一点:

<CustomBorder TopMargin="{Binding TopMargin}">
</CustomBorder>

A better option than a custom control would be to write an attached property and change the Thickness using the code above in the dependency property setter. The below code would be usable across ALL controls which have a Margin.

比自定义控件更好的选择是编写附加属性并使用依赖属性设置器中的上述代码更改厚度。以下代码可用于所有具有 Margin 的控件。

public static readonly DependencyProperty TopMarginProperty =
    DependencyProperty.RegisterAttached("TopMargin", typeof(int), typeof(FrameworkElement),
                                        new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender));
public static void SetTopMargin(FrameworkElement element, int value)
{
    // set top margin in element.Margin
}
public static int GetTopMargin(FrameworkElement element)
{
    // get top margin from element.Margin
}

If you couple this with a Behavior, you can get notification changes on the TopMargin property.

如果您将此与行为结合使用,您可以在 TopMargin 属性上获得通知更改。

回答by Thomas Levesque

You can't define just the Top margin with a binding, because Marginis of type Thicknesswhich isn't a dependency object. However you could use a MultiValueConverterthat would take 4 margin values to make 1 Thickness objects

您不能只定义带有绑定的顶部边距,因为Margin它的类型Thickness不是依赖对象。但是,您可以使用MultiValueConverter4 个边距值来制作 1 个厚度对象

Converter :

转换器:

public class ThicknessMultiConverter : IMultiValueConverter
{
    #region IMultiValueConverter Members

    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double left = System.Convert.ToDouble(values[0]);
        double top = System.Convert.ToDouble(values[1]);
        double right = System.Convert.ToDouble(values[2]);
        double bottom = System.Convert.ToDouble(values[3]);
        return new Thickness(left, top, right, bottom);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        Thickness thickness = (Thickness)value;
        return new object[]
        {
            thickness.Left,
            thickness.Top,
            thickness.Right,
            thickness.Bottom
        };
    }

    #endregion
}

XAML :

XAML:

<StackPanel>
    <StackPanel.Margin>
        <MultiBinding Converter="{StaticResource myThicknessConverter}">
            <Binding Path="LeftMargin"/>
            <Binding Path="TopMargin"/>
            <Binding Path="RightMargin"/>
            <Binding Path="BottomMargin"/>
        </MultiBinding>
    </StackPanel.Margin>
</StackPanel>

回答by NotDan

Use a converter, the sample code below will convert the double you are binding to to a thickness. It will set the "Top" of the thickness to the bound field. You could optionally use a ConverterParameter to determine if you are binding to left, top, right, or bottom.

使用转换器,下面的示例代码会将您绑定的双精度转换为厚度。它将厚度的“顶部”设置为绑定字段。您可以选择使用 ConverterParameter 来确定您是绑定到左侧、顶部、右侧还是底部。

<StackPanel Margin="{Binding TopMargin, Converter={StaticResource MyThicknessConverter}">

.

.

public class ThicknessSingleValueConverter : IValueConverter
{
    override Convert(...)
    {
         return new Thickness(0, (double)object, 0, 0);
    }

    //etc...

回答by Carlo

Isn't this what you're looking for?

这不是你要找的吗?

<StackPanel Margin="0,10,0,0" />

The first value is Left margin, then Top, then Right, and last but not least Bottom.

第一个值是左边距,然后是顶部,然后是右侧,最后是底部。

I'm not sure if you want to bind it to something, but if not, that'll work.

我不确定你是否想把它绑定到某个东西上,但如果没有,那就行了。

回答by Amittai Shapira

I thought You could use the property syntax, from MSDN:

我认为您可以使用MSDN 中的属性语法:

      <object.Margin>
        <Thickness Top="{Binding Top}"/>
      </object.Margin>

Than you won't need any converter

比你不需要任何转换器

But the Top is not DependancyProperty - back to converter

但 Top 不是 DependancyProperty - 回到转换器

回答by jpierson

What would be nice is to be able to do this by specifying something like the code example below.

能够通过指定类似于下面的代码示例的内容来做到这一点会很好。

<StackPanel Margin=",10,,">

Unfortunately this capability doesn't seem to exist by default in WPF and it's a shame because it requires developers to hard code known default values in a way that later makes it more difficult to skin or theme an application.

不幸的是,默认情况下,WPF 中似乎不存在此功能,这是一种耻辱,因为它要求开发人员以某种方式对已知的默认值进行硬编码,从而使应用程序的外观或主题变得更加困难。

The best solution that I can think of at this point is using a converter, but the amount of extra code you have to produce to introduce this is not ideal.

目前我能想到的最佳解决方案是使用转换器,但您必须生成大量额外代码来引入这一点并不理想。

回答by sambeau

Here's a nifty solution:

这是一个漂亮的解决方案:

        public class Nifty
    {
        private static double _tiny;
        private static double _small;
        private static double _medium;
        private static double _large;
        private static double _huge;
        private static bool _resourcesLoaded;

        #region Margins

        public static readonly DependencyProperty MarginProperty =
            DependencyProperty.RegisterAttached("Margin", typeof(string), typeof(Nifty),
                new PropertyMetadata(string.Empty,
                    new PropertyChangedCallback(OnMarginChanged)));

        public static Control GetMargin(DependencyObject d)
        {
            return (Control)d.GetValue(MarginProperty);
        }

        public static void SetMargin(DependencyObject d, string value)
        {
            d.SetValue(MarginProperty, value);
        }

        private static void OnMarginChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FrameworkElement ctrl = d as FrameworkElement;
            if (ctrl == null)
                return;

            string Margin = (string)d.GetValue(MarginProperty);

            ctrl.Margin = ConvertToThickness(Margin);
        }

        private static Thickness ConvertToThickness(string Margin)
        {
            var result = new Thickness();

            if (!_resourcesLoaded)
            {
                _tiny = (double)Application.Current.FindResource("TinySpace");
                _small = (double)Application.Current.FindResource("SmallSpace");
                _medium = (double)Application.Current.FindResource("MediumSpace");
                _large = (double)Application.Current.FindResource("LargeSpace");
                _huge = (double)Application.Current.FindResource("HugeSpace");

                _resourcesLoaded = true;
            }

            result.Left = CharToThickness(Margin[0]);
            result.Top = CharToThickness(Margin[1]);
            result.Bottom = CharToThickness(Margin[2]);
            result.Right = CharToThickness(Margin[3]);

            return result;
        }


        private static double CharToThickness(char p)
        {
            switch (p)
            {
                case 't':
                case 'T':
                    return _tiny;
                case 's':
                case 'S':
                    return _small;
                case 'm':
                case 'M':
                    return _medium;
                case 'l':
                case 'L':
                    return _large;
                case 'h':
                case 'H':
                    return _huge;
                default:
                    return 0.0;
            }
        }

        #endregion

    }

If you add this code to your namespace and define the following sizes:

如果将此代码添加到命名空间并定义以下大小:

    <system:Double x:Key="TinySpace">2</system:Double>
<system:Double x:Key="SmallSpace">5</system:Double>
<system:Double x:Key="MediumSpace">10</system:Double>
<system:Double x:Key="LargeSpace">20</system:Double>
<system:Double x:Key="HugeSpace">20</system:Double>

You can then create Tiny, Small, Medium, Large & Huge margins like this:

然后,您可以像这样创建 Tiny、Small、Medium、Large 和 Huge 边距:

local:Nifty.Margin="H000"

or

或者

local:Nifty.Margin="_S_S"

The code will then create margins based on your resources.

然后代码将根据您的资源创建边距。

回答by G.Y

This belongs to the WPF amendments:

这属于WPF修正案:

  1. I am WPF and you will use me when coding for windows apps - eventually.
  2. Don't use other technologies - I will not be cross-platform but I'll try to with SL.
  3. If you intend to use me - be sure you know what you doing.
  4. Every 7 days or hours or minutes of coding I will make you take a break to go to SO.
  5. Respect windows forms.
  6. MVVM -> INPC, INCC -> you can either use it or you can use it with anger - your choice!
  7. Don't interop other apps.
  8. You shall pay for blend as well.
  9. Thou shall not be able to set a position of an element dynamically using binding of an either attached property or margin without writing few lines of code behind.

  10. Don't compare this technology to others.

  1. 我是 WPF,您将在为 Windows 应用程序编码时使用我 - 最终。
  2. 不要使用其他技术 - 我不会跨平台,但我会尝试使用 SL。
  3. 如果你打算使用我 - 确保你知道你在做什么。
  4. 每 7 天或每小时或几分钟编码,我会让你休息一下去 SO。
  5. 尊重窗体。
  6. MVVM -> INPC, INCC -> 你可以使用它,也可以愤怒地使用它——你的选择!
  7. 不要互操作其他应用程序。
  8. 您也应支付混合费用。
  9. 如果不写几行代码,您将无法使用附加属性或边距的绑定动态设置元素的位置。

  10. 不要将这项技术与其他技术进行比较。

Your problem is listed at #9.

您的问题列在#9。

回答by Antonio Bakula

Maybe I am "late to the party", but didn't like any of provided solutions, and it seems to me that simplest and cleanest solution is define Thickness property in ViewModel (or anything that you are binding) and then Bind that property. Something like this:

也许我“迟到了”,但不喜欢任何提供的解决方案,在我看来,最简单、最干净的解决方案是在 ViewModel(或您绑定的任何内容)中定义厚度属性,然后绑定该属性。像这样的东西:

public class ItemViewModel
{
  public Thickness Margin { get; private set }

  public ItemViewModel(ModelClass model)
  {
    /// You can calculate needed margin here, 
    /// probably depending on some value from the Model
    this.Margin = new Thickness(0,model.TopMargin,0,0);
  }
}

And then XAML is simple:

然后 XAML 很简单:

<StackPanel Margin="{Binding Margin}">

回答by redcurry

Here's a simple way of doing this without writing converters or hard-coding margin values. First, define the following in your Window (or other control) resources:

这是一种无需编写转换器或硬编码边距值的简单方法。首先,在您的 Window(或其他控件)资源中定义以下内容:

<Window.Resources>
    <!-- Define the default amount of space -->
    <system:Double x:Key="Space">10.0</system:Double>

    <!-- Border space around a control -->
    <Thickness
        x:Key="BorderSpace"
        Left="{StaticResource Space}"
        Top="{StaticResource Space}"
        Right="{StaticResource Space}"
        Bottom="{StaticResource Space}"
        />

    <!-- Space between controls that are positioned vertically -->
    <Thickness
        x:Key="TopSpace"
        Top="{StaticResource Space}"
        />
</Window.Resources>

Note that systemis defined as xmlns:system="clr-namespace:System;assembly=mscorlib".

请注意,system定义为xmlns:system="clr-namespace:System;assembly=mscorlib"

Now you can use these resources as follows:

现在您可以按如下方式使用这些资源:

<Grid
    Margin="{StaticResource BorderSpace}"
    >
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <Button
        Grid.Row="0"
        Content="Button 1"
        />

    <Button
        Grid.Row="1"
        Content="Button 2"
        Margin="{StaticResource TopSpace}"
        />
</Grid>

Now if you want to change the default space between controls, you only need to change it in one place.

现在,如果要更改控件之间的默认空间,只需在一处更改即可。