【问题标题】:Set a margin from a binding从装订中设置边距
【发布时间】:2012-12-30 21:19:11
【问题描述】:

我有一个绑定值,它返回一个 int,它表示我没有分配给元素左右边距的值。

这是我尝试过的,但它不会编译。

如果我设置整个边距,它会起作用,但我只想要左右。

Xaml:

<Image x:Name="_image" Source="mat.png" Margin="{Binding EditorRow.BondIndent},0,{Binding EditorRow.BondIndent},0" />

类:

public int BondIndent
{
    get { return _bondSequence * 5; }
}

【问题讨论】:

  • 返回一个Thickness 怎么样?
  • 默认,因为我可以控制从后面的类返回的内容。请您根据返回的厚度添加答案,我将标记为答案
  • 添加了一个答案。 HTH

标签: c# wpf xaml binding margin


【解决方案1】:

您可能需要为此使用ValueConverter。比如:

public class LeftRightThicknessConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is int)
        {
            int margin = (int)value;
            return Thickness(margin, 0, margin, 0);
        }
        return Thickness();
    }

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

然后您可以通过以下方式使用转换器:

<Grid>
    <Grid.Resources>
        <xxx:LeftRightThicknessConverter x:Key="LeftRightThicknessConverter" />
    </Grid.Resources>

    <Image Margin="{Binding SomePropertyPath, Converter={StaticResource LeftRightThicknessConverter}}" />
</Grid>

假设 xxx 是一个有效的 xml 命名空间。

【讨论】:

  • OP如何使用这个valueconverter?
  • 值转换器可以是静态的并存储在另一个程序集中吗?
  • 您可以在另一个程序集中定义转换器类。但是您需要一个可从 XAML 访问的实例。通常,您会在元素的资源(例如 UserControl 元素)中创建一个与上述示例类似的实例。您可以通过将xmlns:xxx="clr-namespace:MyOtherAssembly.TheNamespace;assembly=MyOtherAssembly" 添加到用户控件或模板控件的根节点来定义引用您的程序集(和特定名称空间)的xml 名称空间。替换 xxx 当然是一些合适的名字。
  • 建议使用as 运算符而不是is + cast
  • @odyss-jii 由于 OP 没有使用 MVVM,我认为没有理由解耦到这种程度。他的属性的性质假设视图的 DataContext 正在决定事物的外观......这意味着更好(更简单)的解决方案只是返回一个厚度。
【解决方案2】:

返回边距?

public Thickness Margin
{
    get { return new Thickness(BondIndent,0,BondIndent,0);}
}

然后改变:

<Image x:Name="_image" Source="mat.png" Margin="{Binding EditorRow.Margin}" />

【讨论】:

    【解决方案3】:

    您可以返回Thickness,而不是返回intMargin 实际上是:

    public Thickness BondIndent
    {
        get
        {
            int margin = _bondSequence * 5;
            return new Thickness(margin, 0, margin, 0);
        }
    }
    

    您的示例有效的原因是因为Thickness 具有采用 1、2 或 4 个参数的重载构造函数。当调用带有 1 个参数的构造函数时,所有边都被初始化为该值。 WPF 会根据绑定值自动将其转换为 Thickness

    在另一个主题上,BondIndent 现在最好称为BondMarginBondThickness

    【讨论】:

      【解决方案4】:

      刚刚写了一些附加属性,应该可以很容易地从绑定或静态资源中设置单独的 Margin 值:

      WPF:

      public class Margin
      {
          public static readonly DependencyProperty LeftProperty = DependencyProperty.RegisterAttached(
              "Left",
              typeof(double),
              typeof(Margin),
              new PropertyMetadata(0.0, LeftChanged));
      
          private static void LeftChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
          {
              var frameworkElement = d as FrameworkElement;
              if (frameworkElement != null)
              {
                  Thickness currentMargin = frameworkElement.Margin;
                  frameworkElement.Margin = new Thickness((double)e.NewValue, currentMargin.Top, currentMargin.Right, currentMargin.Bottom);
              }
          }
      
          public static void SetLeft(UIElement element, double value)
          {
              element.SetValue(LeftProperty, value);
          }
      
          public static double GetLeft(UIElement element)
          {
              return 0;
          }
      
          public static readonly DependencyProperty TopProperty = DependencyProperty.RegisterAttached(
              "Top",
              typeof(double),
              typeof(Margin),
              new PropertyMetadata(0.0, TopChanged));
      
          private static void TopChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
          {
              var frameworkElement = d as FrameworkElement;
              if (frameworkElement != null)
              {
                  Thickness currentMargin = frameworkElement.Margin;
                  frameworkElement.Margin = new Thickness(currentMargin.Left, (double)e.NewValue, currentMargin.Right, currentMargin.Bottom);
              }
          }
      
          public static void SetTop(UIElement element, double value)
          {
              element.SetValue(TopProperty, value);
          }
      
          public static double GetTop(UIElement element)
          {
              return 0;
          }
      
          public static readonly DependencyProperty RightProperty = DependencyProperty.RegisterAttached(
              "Right",
              typeof(double),
              typeof(Margin),
              new PropertyMetadata(0.0, RightChanged));
      
          private static void RightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
          {
              var frameworkElement = d as FrameworkElement;
              if (frameworkElement != null)
              {
                  Thickness currentMargin = frameworkElement.Margin;
                  frameworkElement.Margin = new Thickness(currentMargin.Left, currentMargin.Top, (double)e.NewValue, currentMargin.Bottom);
              }
          }
      
          public static void SetRight(UIElement element, double value)
          {
              element.SetValue(RightProperty, value);
          }
      
          public static double GetRight(UIElement element)
          {
              return 0;
          }
      
          public static readonly DependencyProperty BottomProperty = DependencyProperty.RegisterAttached(
              "Bottom",
              typeof(double),
              typeof(Margin),
              new PropertyMetadata(0.0, BottomChanged));
      
          private static void BottomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
          {
              var frameworkElement = d as FrameworkElement;
              if (frameworkElement != null)
              {
                  Thickness currentMargin = frameworkElement.Margin;
                  frameworkElement.Margin = new Thickness(currentMargin.Left, currentMargin.Top, currentMargin.Right, (double)e.NewValue);
              }
          }
      
          public static void SetBottom(UIElement element, double value)
          {
              element.SetValue(BottomProperty, value);
          }
      
          public static double GetBottom(UIElement element)
          {
              return 0;
          }
      }
      

      UWP:

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

      好消息是它们不会覆盖 Margin 上的其他值,因此您也可以将它们组合起来。

      【讨论】:

      • setter 和 getter 不会被直接调用。您必须将 PropertyCallback 添加到 DependencyProperty。我真的不敢相信,你测试了它:)
      • @Nicolas msdn.microsoft.com/en-us/library/ms749011(v=vs.110).aspx 向下滚动到“自定义附加属性”->“如何创建附加属性”。它们使用 getter 和 setter 方法的命名约定,您不需要在 DependencyProperty 上提供属性回调。我们一直在我们的代码中使用它;它确实有效。
      • Blend 和 Visual Studio Designer 使用这些功能,但 WPF 不使用。这些方法只是通过后面的代码获取/设置属性很有趣......但是您在示例中的 XAML 中设置了这些属性(而不是后面的代码)。因为 WPF 正在管理信息,所以除了设置和获取信息之外,您不应将逻辑放入这些方法中。
      • @Nicolas Ahh,WPF 的工作方式有点不同。添加了一个可以在那里工作的附加属性的版本。
      猜你喜欢
      • 2011-12-17
      • 1970-01-01
      • 2021-09-09
      • 2019-04-07
      • 2012-02-24
      • 2018-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多