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

发布于 2024-08-02 19:40:24 字数 245 浏览 3 评论 0原文

我可以在 代码 中单独设置边距,但我该怎么做它在 XAML 中,例如我该怎么做:

伪代码:

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

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

PSEUDO-CODE:

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

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

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

发布评论

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

评论(12

小…楫夜泊 2024-08-09 19:40:24

这不是您要找的吗?

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

第一个值是左边距,然后是顶部,然后是右边,最后但并非最不重要的底部。

我不确定你是否想将它绑定到某些东西,但如果不是,那就可以了。

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.

攒眉千度 2024-08-09 19:40:24

关键是要认识到,在如下代码中设置它:

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

相当于:

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

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

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

其中 MyConverter 仅返回仅设置 Top 的 Thickness 并将所有其他值保留为零。

当然,您可以编写自己的控件,将这些单独的值公开为依赖属性,以使您的代码更加简洁:

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

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

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
}

如果将此与行为结合起来,您可以在 TopMargin 属性上收到更改通知。

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't set just a single value in a Thickness instance 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:

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

where MyConverter just returns a Thickness that sets only the Top and leaves all other values as zero.

Of course, you could write your own control that does expose 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.

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.

泅渡 2024-08-09 19:40:24

这属于 WPF/XAML 戒律:

  1. 我是 WPF/XAML,您的 UI 框架,您最终将在为 Windows 编写应用程序时使用我。
  2. 你不能有其他技术 - 我不会跨平台,但我会尝试使用 Silverlight UWP,因为 Hololens 有一天会变得巨大。 “Xamarin.Forms”?从来没有听说过!
  3. 在使用 WPF/XAML 时,您将不可避免地重复地徒劳地使用主的名字。
  4. 记住安息日:每 7 天...或者编码的小时或分钟,我会让你休息一下去 StackOverflow 和 2000things
  5. 尊敬你的父母:Windows Forms。
  6. 如果您要采用 MVVM,您还应该实现 INPCINCC,但是很高兴!你有一个选择:你可以使用它,或者你可以愤怒地使用它。
  7. 您不得与其他应用程序和框架互操作犯奸淫
  8. 你不应该觊觎你邻居的 UI 框架。
  9. 如果不编写几行代码隐藏,您将无法使用附加属性或边距的绑定来动态设置元素的位置。
  10. XAML 中永远不应该有简单的 bool Visibility 属性。我是 WPF/XAML。

你的罪被列在#9。

This belongs to the WPF/XAML commandments:

  1. I am WPF/XAML, thy UI framework, and you will use me when coding apps for Windows - eventually.
  2. Thou shalt have no other technologies - I will not be cross-platform but I'll try to with Silverlight UWP, because Hololens is going to be huge some day. "Xamarin.Forms"? Never heard of it!
  3. Thou shalt inevitably take the name of the Lord in vain, repeatedly, when using WPF/XAML.
  4. Remember the sabbath day: every 7 days... or hours or minutes of coding I will make you take a break to go to StackOverflow and 2000things.
  5. Honor thy father and mother: Windows Forms.
  6. Should thou shalt adopt MVVM, thou shalt also implement INPC and INCC, but rejoice! Thou hast a choice: you can use it or you can use it with anger.
  7. Thou shalt not commit adultery interop with other apps and frameworks.
  8. Thou shalt not covet thy neighbour's UI framework.
  9. Thou shalt 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. Thou shalt never have a simple bool Visibility property in XAML. I am WPF/XAML.

Your sin is listed at #9.

白云悠悠 2024-08-09 19:40:24

刚刚编写了一些附加属性,这些属性应该可以轻松地从绑定或静态资源设置单独的 Margin 值:

public class Margin
{
    public static readonly DependencyProperty LeftProperty = DependencyProperty.RegisterAttached(
        "Left",
        typeof(double),
        typeof(Margin),
        new PropertyMetadata(0.0));

    public static void SetLeft(UIElement element, double value)
    {
        var frameworkElement = element as FrameworkElement;
        if (frameworkElement != null)
        {
            Thickness currentMargin = frameworkElement.Margin;

            frameworkElement.Margin = new Thickness(value, currentMargin.Top, currentMargin.Right, currentMargin.Bottom);
        }
    }

    public static double GetLeft(UIElement element)
    {
        return 0;
    }

    public static readonly DependencyProperty TopProperty = DependencyProperty.RegisterAttached(
        "Top",
        typeof(double),
        typeof(Margin),
        new PropertyMetadata(0.0));

    public static void SetTop(UIElement element, double value)
    {
        var frameworkElement = element as FrameworkElement;
        if (frameworkElement != null)
        {
            Thickness currentMargin = frameworkElement.Margin;

            frameworkElement.Margin = new Thickness(currentMargin.Left, value, currentMargin.Right, currentMargin.Bottom);
        }
    }

    public static double GetTop(UIElement element)
    {
        return 0;
    }

    public static readonly DependencyProperty RightProperty = DependencyProperty.RegisterAttached(
        "Right",
        typeof(double),
        typeof(Margin),
        new PropertyMetadata(0.0));

    public static void SetRight(UIElement element, double value)
    {
        var frameworkElement = element as FrameworkElement;
        if (frameworkElement != null)
        {
            Thickness currentMargin = frameworkElement.Margin;

            frameworkElement.Margin = new Thickness(currentMargin.Left, currentMargin.Top, value, currentMargin.Bottom);
        }
    }

    public static double GetRight(UIElement element)
    {
        return 0;
    }

    public static readonly DependencyProperty BottomProperty = DependencyProperty.RegisterAttached(
        "Bottom",
        typeof(double),
        typeof(Margin),
        new PropertyMetadata(0.0));

    public static void SetBottom(UIElement element, double value)
    {
        var frameworkElement = element as FrameworkElement;
        if (frameworkElement != null)
        {
            Thickness currentMargin = frameworkElement.Margin;

            frameworkElement.Margin = new Thickness(currentMargin.Left, currentMargin.Top, currentMargin.Right, value);
        }
    }

    public static double GetBottom(UIElement element)
    {
        return 0;
    }
}

用法:

<TextBlock Text="Test"
    app:Margin.Top="{Binding MyValue}"
    app:Margin.Right="{StaticResource MyResource}"
    app:Margin.Bottom="20" />

在 UWP 中测试,但这应该适用于任何基于 XAML 的框架。好处是它们不会覆盖边距上的其他值,因此您也可以将它们组合起来。

Just wrote some attached properties that should make it easy to set an individual Margin value from a binding or static resource:

public class Margin
{
    public static readonly DependencyProperty LeftProperty = DependencyProperty.RegisterAttached(
        "Left",
        typeof(double),
        typeof(Margin),
        new PropertyMetadata(0.0));

    public static void SetLeft(UIElement element, double value)
    {
        var frameworkElement = element as FrameworkElement;
        if (frameworkElement != null)
        {
            Thickness currentMargin = frameworkElement.Margin;

            frameworkElement.Margin = new Thickness(value, currentMargin.Top, currentMargin.Right, currentMargin.Bottom);
        }
    }

    public static double GetLeft(UIElement element)
    {
        return 0;
    }

    public static readonly DependencyProperty TopProperty = DependencyProperty.RegisterAttached(
        "Top",
        typeof(double),
        typeof(Margin),
        new PropertyMetadata(0.0));

    public static void SetTop(UIElement element, double value)
    {
        var frameworkElement = element as FrameworkElement;
        if (frameworkElement != null)
        {
            Thickness currentMargin = frameworkElement.Margin;

            frameworkElement.Margin = new Thickness(currentMargin.Left, value, currentMargin.Right, currentMargin.Bottom);
        }
    }

    public static double GetTop(UIElement element)
    {
        return 0;
    }

    public static readonly DependencyProperty RightProperty = DependencyProperty.RegisterAttached(
        "Right",
        typeof(double),
        typeof(Margin),
        new PropertyMetadata(0.0));

    public static void SetRight(UIElement element, double value)
    {
        var frameworkElement = element as FrameworkElement;
        if (frameworkElement != null)
        {
            Thickness currentMargin = frameworkElement.Margin;

            frameworkElement.Margin = new Thickness(currentMargin.Left, currentMargin.Top, value, currentMargin.Bottom);
        }
    }

    public static double GetRight(UIElement element)
    {
        return 0;
    }

    public static readonly DependencyProperty BottomProperty = DependencyProperty.RegisterAttached(
        "Bottom",
        typeof(double),
        typeof(Margin),
        new PropertyMetadata(0.0));

    public static void SetBottom(UIElement element, double value)
    {
        var frameworkElement = element as FrameworkElement;
        if (frameworkElement != null)
        {
            Thickness currentMargin = frameworkElement.Margin;

            frameworkElement.Margin = new Thickness(currentMargin.Left, currentMargin.Top, currentMargin.Right, value);
        }
    }

    public static double GetBottom(UIElement element)
    {
        return 0;
    }
}

Usage:

<TextBlock Text="Test"
    app:Margin.Top="{Binding MyValue}"
    app:Margin.Right="{StaticResource MyResource}"
    app:Margin.Bottom="20" />

Tested in UWP but this should work for any XAML-based framework. The nice thing is they won't override the other values on the Margin, so you can combine them as well.

ゝ偶尔ゞ 2024-08-09 19:40:24

您不能仅使用绑定定义上边距,因为 Margin 的类型为 Thickness,它不是依赖项对象。但是,您可以使用 MultiValueConverter ,它需要 4 个边距值来生成 1 个 Thickness 对象

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 :

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

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

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 :

<StackPanel>
    <StackPanel.Margin>
        <MultiBinding Converter="{StaticResource myThicknessConverter}">
            <Binding Path="LeftMargin"/>
            <Binding Path="TopMargin"/>
            <Binding Path="RightMargin"/>
            <Binding Path="BottomMargin"/>
        </MultiBinding>
    </StackPanel.Margin>
</StackPanel>
久光 2024-08-09 19:40:24

我想你可以使用属性语法,来自 MSDN< /a>:

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

比你不需要任何转换器

但顶部不是 DependancyProperty - 回到转换器

I thought You could use the property syntax, from 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

逆蝶 2024-08-09 19:40:24

这是一种简单的方法,无需编写转换器或硬编码边距值即可实现此目的。首先,在 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>

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

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

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

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

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.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 system is defined as 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.

浮萍、无处依 2024-08-09 19:40:24

我使用绑定到 Margin (RelativeSource Self) 的 ValueConverter 并解析 ConverterParameter,给出为“top:123;left:456”。

转换器仅覆盖参数指定的边距。

public class MarginConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is Thickness)) return new Thickness();

        Thickness retMargin = (Thickness) value;
        List<string> singleMargins = (parameter as string)?.Split(';').ToList() ?? new List<string>();

        singleMargins.ForEach(m => {
                                  switch (m.Split(':').ToList()[0].ToLower().Trim()) {
                                      case "left":
                                          retMargin.Left = double.Parse(m.Split(':').ToList()[1].Trim());
                                          break;
                                      case "top":
                                          retMargin.Top = double.Parse(m.Split(':').ToList()[1].Trim());
                                          break;
                                      case "right":
                                          retMargin.Right = double.Parse(m.Split(':').ToList()[1].Trim());
                                          break;
                                      case "bottom":
                                          retMargin.Bottom = double.Parse(m.Split(':').ToList()[1].Trim());
                                          break;
                                  }
                              }
            );
        return retMargin;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

xaml

<TextBlock Margin="{Binding RelativeSource={RelativeSource Self}, 
                    Path=Margin, 
                    Converter={StaticResource MarginConverter}, 
                    ConverterParameter='top:0'}" 
Style="{StaticResource Header}" 
Text="My Header" />

TextBlock 将使用 Style 给定的边距(顶部边距除外),该边距将被 0 覆盖。

玩得开心!

I use a ValueConverter bound to Margin (RelativeSource Self) and Parse the ConverterParameter, given as "top:123;left:456".

The Converter only overwrites Margins given by Parameter.

public class MarginConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is Thickness)) return new Thickness();

        Thickness retMargin = (Thickness) value;
        List<string> singleMargins = (parameter as string)?.Split(';').ToList() ?? new List<string>();

        singleMargins.ForEach(m => {
                                  switch (m.Split(':').ToList()[0].ToLower().Trim()) {
                                      case "left":
                                          retMargin.Left = double.Parse(m.Split(':').ToList()[1].Trim());
                                          break;
                                      case "top":
                                          retMargin.Top = double.Parse(m.Split(':').ToList()[1].Trim());
                                          break;
                                      case "right":
                                          retMargin.Right = double.Parse(m.Split(':').ToList()[1].Trim());
                                          break;
                                      case "bottom":
                                          retMargin.Bottom = double.Parse(m.Split(':').ToList()[1].Trim());
                                          break;
                                  }
                              }
            );
        return retMargin;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

xaml

<TextBlock Margin="{Binding RelativeSource={RelativeSource Self}, 
                    Path=Margin, 
                    Converter={StaticResource MarginConverter}, 
                    ConverterParameter='top:0'}" 
Style="{StaticResource Header}" 
Text="My Header" />

TextBlock would use the Margin given by Style except the Margin-Top, that will be overwritten with 0.

Have fun with it!

完美的未来在梦里 2024-08-09 19:40:24

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

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

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

    //etc...

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.

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

.

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

    //etc...
末が日狂欢 2024-08-09 19:40:24

这是一个巧妙的解决方案:

        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

    }

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

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

然后您可以创建 Tiny、Small、Medium、Large 和 Large 大小。像这样的巨大利润:

local:Nifty.Margin="H000"

local:Nifty.Margin="_S_S"

然后代码将根据您的资源创建利润。

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:

local:Nifty.Margin="H000"

or

local:Nifty.Margin="_S_S"

The code will then create margins based on your resources.

森罗 2024-08-09 19:40:24

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

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);
  }
}

然后 XAML 就很简单了:

<StackPanel Margin="{Binding Margin}">

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:

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:

<StackPanel Margin="{Binding Margin}">
像极了他 2024-08-09 19:40:24

如果能够通过指定类似下面的代码示例的内容来完成此操作,那就太好了。

<StackPanel Margin=",10,,">

不幸的是,默认情况下,WPF 中似乎不存在此功能,这很遗憾,因为它要求开发人员对已知的默认值进行硬编码,而这种方式稍后会使应用程序的皮肤或主题化变得更加困难。

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

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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文