Подтвердить что ты не робот

Как установить верхнюю границу только в XAML?

Я могу устанавливать поля отдельно в код, но как это сделать в XAML, например. как это сделать:

псевдокод:

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

Ответ 1

Ключ должен понять, что он устанавливает его в коде следующим образом:

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 просто возвращает a Thickness, который устанавливает только Top и оставляет все остальные значения равными нулю.

Конечно, вы можете написать свой собственный элемент управления, который выставляет эти отдельные значения в качестве свойств зависимостей, чтобы сделать ваш код немного чище:

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

Ответ 2

Разве это не то, что вы ищете?

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

Первое значение - левое поле, затем верхнее, затем правое и последнее, но не менее. Bottom.

Я не уверен, что вы хотите связать его с чем-то, но если нет, это сработает.

Ответ 3

Это относится к поправкам WPF:

  • Я WPF, и вы будете использовать меня при кодировании для приложений Windows - в конце концов.
  • Не используйте другие технологии - я не буду кросс-платформенным, но я постараюсь с SL.
  • Если вы намерены использовать меня - убедитесь, что знаете, что делаете.
  • Каждые 7 дней или часов или минут кодирования я заставлю вас сделать перерыв, чтобы перейти к SO.
  • Уважать формы окон.
  • MVVM → INPC, INCC → вы можете использовать его или можете использовать его с гневом - ваш выбор!
  • Не взаимодействуйте с другими приложениями.
  • Вы также должны заплатить за смесь.
  • Вы не сможете динамически устанавливать позицию элемента, используя привязку либо прикрепленного свойства, либо поля, не записывая несколько строк кода.

  • Не сравнивайте эту технологию с другими.

Ваша проблема указана в # 9.

Ответ 4

Вы не можете определить только верхнее поле с привязкой, потому что Margin имеет тип Thickness, который не является объектом зависимостей. Однако вы можете использовать MultiValueConverter, который будет принимать 4 значения полей, чтобы сделать 1 объект Толщина

Конвертер:

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>

Ответ 5

Используйте конвертер, пример кода ниже преобразует двойной, который вы связываете с толщиной. Он установит "Top" толщины в связанное поле. Вы можете по желанию использовать ConverterParameter, чтобы определить, привязаны ли вы к левому, верхнему, правому или нижнему.

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

.

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

    //etc...

Ответ 6

Здесь отличное решение:

        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>

Затем вы можете создавать Крошечные, Малые, Средние, Большие и Огромные поля, такие как:

local:Nifty.Margin="H000"

или

local:Nifty.Margin="_S_S"

Затем код будет создавать поля на основе ваших ресурсов.

Ответ 7

Может быть, я "опоздал на вечеринку", но не понравился ни одному из предоставленных решений, и мне кажется, что самым простым и чистым решением является определение свойства Thickness в ViewModel (или все, что вы связываете), а затем Bind это свойство. Что-то вроде этого:

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

Ответ 8

Вот простой способ сделать это, не записывая конвертеры или значения маркера жесткого кодирования. Во-первых, определите следующие ресурсы в вашем окне (или другом контроле):

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

Теперь, если вы хотите изменить пространство по умолчанию между элементами управления, вам нужно только изменить его в одном месте.

Ответ 9

Просто написал некоторые прикрепленные свойства, которые должны облегчить установку индивидуального значения 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. Приятно, что они не будут переопределять другие значения в Margin, поэтому вы также можете комбинировать их.

Ответ 10

Я использую ValueConverter, привязанный к Margin (RelativeSource Self) и Parse the 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 будет использовать маржу, заданную стилем, кроме Margin-Top, которая будет перезаписана 0.

Получайте удовольствие от этого!

Ответ 11

Я думал, что вы можете использовать синтаксис свойств, от MSDN:

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

Чем вам не нужен конвертер

Но Top не DependancyProperty - обратно в конвертер

Ответ 12

Что было бы неплохо, так это сделать, указав что-то вроде примера кода ниже.

<StackPanel Margin=",10,,">

К сожалению, эта возможность, по-видимому, не существует по умолчанию в WPF, и это позор, потому что для этого требуется, чтобы разработчики жестко кодировали известные значения по умолчанию таким образом, что впоследствии стало более сложным для кожи или темы приложения.

Лучшее решение, о котором я могу думать на данный момент, это использовать конвертер, но количество дополнительного кода, который вы должны создать, чтобы представить это, не является идеальным.