2009-08-22 31 views

Trả lời

32

Điều quan trọng là nhận ra rằng cài đặt nó trong mã như thế này:

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

tương đương với:

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

Bạn không có thể thiết lập chỉ là một giá trị duy nhất trong một phiên bản Thickness thông qua hoặc mã hoặc XAML. Nếu bạn không đặt một số giá trị, chúng sẽ hoàn toàn bằng không. Do đó, bạn chỉ có thể làm điều này để chuyển đổi các mẫu mã được chấp nhận trong câu hỏi khác của bạn đến một XAML tương đương:

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

nơi MyConverter chỉ trả về một Thickness mà chỉ đặt Top và lá tất cả các giá trị khác như bằng không.

Tất nhiên, bạn có thể viết kiểm soát của riêng bạn mà không phơi bày những giá trị cá nhân là tài sản phụ thuộc để làm cho mã của bạn một chút bụi:

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

Đơn giản, hiệu quả và tôi không chắc tại sao mọi người thử và làm phức tạp điều này. Một dòng là tốt hơn nhiều so với 20 hoặc để một số người nghĩ rằng nó mất. Tôi đánh giá cao câu trả lời này. – Middletone

+1

Bạn có thể đặt nó như thế này 'var margin = sp2.Margin; margin.Left = 5; sp2.Margin = margin; 'Điều này sẽ để nguyên các giá trị khác. – bugged87

+0

@ bugged87: OP muốn làm điều đó trong XAML. –

1

Bạn không thể xác định chỉ lề Top với một ràng buộc, vì Margin là loại Thickness mà không phải là một đối tượng phụ thuộc. Tuy nhiên bạn có thể sử dụng một MultiValueConverter rằng sẽ phải mất 4 giá trị lợi nhuận để làm 1 Độ dày vật

Chuyển đổi:

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

Làm thế nào công việc này xem xét anh ta muốn đặt một phần duy nhất của lề và để lại các giá trị hiện có khác còn nguyên vẹn? –

+0

Vâng, tất cả các thuộc tính sẽ được đặt lúc khởi tạo, nhưng sau đó bạn chỉ cần thay đổi một trong các thuộc tính bị ràng buộc ... –

+0

BTW, giải pháp của bạn có cùng giới hạn;) –

0

Sử dụng một bộ chuyển đổi, mã mẫu dưới đây sẽ chuyển đổi đôi bạn đang ràng buộc với độ dày. Nó sẽ thiết lập "Top" của độ dày cho trường bị ràng buộc. Bạn có thể tùy ý sử dụng một ConverterParameter để xác định xem bạn có ràng buộc trái, trên, phải hay dưới cùng.

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

.

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

    //etc... 
50

Đó không phải là những gì bạn đang tìm kiếm?

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

Giá trị đầu tiên là Lề trái, sau đó Đầu, sau đó Phải và cuối cùng nhưng không kém phần dưới cùng.

Tôi không chắc chắn nếu bạn muốn ràng buộc nó với một cái gì đó, nhưng nếu không, điều đó sẽ làm việc.

-1

Tôi nghĩ Bạn có thể sử dụng cú pháp tài sản, từ MSDN:

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

Thần bạn sẽ không cần bất kỳ chuyển đổi

Nhưng Top không phải là DependancyProperty - trở lại Chuyển đổi

+1

U sẽ nhận được "Không thể đặt thuộc tính chỉ đọc 'System.Windows.Thickness.Top' " – Grigory

+0

Ngoài ra, điều này sẽ vẫn ghi đè lên các giá trị khác với số không mặc định. Vì vậy, nếu đó không phải là hành vi mà bạn muốn, thì điều này sẽ không hoạt động ngay cả với một giá trị mã hóa cứng. – bugged87

+0

Vâng, tôi không nghĩ rằng đó là một giải pháp khả thi. – Gqqnbig

-3

gì sẽ được tốt đẹp là để có thể làm điều này bằng cách xác định một cái gì đó giống như ví dụ mã dưới đây.

<StackPanel Margin=",10,,"> 

Đáng tiếc là khả năng này dường như không tồn tại theo mặc định trong WPF và đó là một sự xấu hổ bởi vì nó đòi hỏi các nhà phát triển mã được biết đến các giá trị mặc định cứng trong một cách mà sau này làm cho nó khó khăn hơn để da hoặc chủ đề một ứng dụng.

Giải pháp tốt nhất mà tôi có thể nghĩ đến tại thời điểm này là sử dụng trình chuyển đổi, nhưng số lượng mã phụ bạn phải sản xuất để giới thiệu điều này không phải là lý tưởng.

0

Dưới đây là một giải pháp tiện lợi:

 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 

    } 

Nếu bạn thêm mã này vào không gian tên của bạn và xác định các kích thước sau:

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

Sau đó bạn có thể tạo Tiny, Small, Medium, Large & lớn lề như sau:

local:Nifty.Margin="H000" 

hoặc

local:Nifty.Margin="_S_S" 

Sau đó, mã sẽ tạo lề dựa trên tài nguyên của bạn.

18

này thuộc về những sửa đổi WPF:

  1. Tôi WPF và bạn sẽ sử dụng cho tôi khi mã hóa cho các cửa sổ ứng dụng - cuối cùng.
  2. Không sử dụng các công nghệ khác - Tôi sẽ không đa nền tảng nhưng tôi sẽ cố gắng với SL.
  3. Nếu bạn định sử dụng tôi - hãy chắc chắn bạn biết bạn đang làm gì.
  4. Cứ sau 7 ngày hoặc hàng giờ hoặc phút mã hóa, tôi sẽ làm bạn nghỉ ngơi để đến SO.
  5. Tôn trọng các biểu mẫu cửa sổ.
  6. MVVM -> INPC, INCC -> bạn có thể sử dụng nó hoặc bạn có thể sử dụng nó với sự tức giận - sự lựa chọn của bạn!
  7. Không tương tác với các ứng dụng khác.
  8. Bạn cũng phải trả tiền cho sự pha trộn.
  9. Bạn sẽ không thể đặt vị trí của phần tử động bằng cách sử dụng liên kết của thuộc tính hoặc lề được đính kèm mà không cần viết vài dòng mã phía sau.

  10. Đừng so sánh công nghệ này với người khác.

Sự cố của bạn được liệt kê ở # 9.

0

Có lẽ tôi là "muộn bên", nhưng không thích bất kỳ giải pháp được cung cấp nào, và dường như giải pháp đơn giản nhất và sạch nhất đó là xác định thuộc tính Độ dày trong ViewModel (hoặc bất kỳ thứ gì bạn ràng buộc) và sau đó Liên kết thuộc tính đó. Một cái gì đó như thế này:

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

Và sau đó XAML rất đơn giản:

<StackPanel Margin="{Binding Margin}"> 
+0

Độ dày và lề là các khái niệm liên quan đến xem. Như vậy, chúng không thuộc về một mô hình xem thích hợp. – aaronburro

0

Đây là một cách đơn giản để làm điều này mà không cần viết bộ chuyển đổi hoặc giá trị biên độ cứng mã hóa. Thứ nhất, xác định như sau trong cửa sổ của bạn (hoặc điều khiển khác) nguồn:

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

Lưu ý rằng system được định nghĩa là xmlns:system="clr-namespace:System;assembly=mscorlib".

Bây giờ bạn có thể sử dụng các nguồn lực này như sau:

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

Bây giờ nếu bạn muốn thay đổi không gian mặc định giữa điều khiển, bạn chỉ cần thay đổi nó ở một nơi.

0

Chỉ cần viết một số tài sản gắn liền mà nên làm cho nó dễ dàng để thiết lập một giá trị Margin cá nhân từ một nguồn lực ràng buộc hoặc tĩnh:

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

Cách sử dụng:

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

Tested trong UWP nhưng điều này nên làm việc cho bất kỳ khung dựa trên XAML nào. Điều tốt đẹp là họ sẽ không ghi đè lên các giá trị khác trên Margin, vì vậy bạn có thể kết hợp chúng.

0

Tôi sử dụng một ValueConverter liên kết với Margin (RelativeSource Self) và Parse the ConverterParameter, được cho là "top: 123; left: 456".

Trình chuyển đổi chỉ ghi đè các Lề được cung cấp bởi Thông số.

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 sẽ sử dụng Margin do Phong cách trừ margin-top, mà sẽ được ghi đè bằng 0.

Hãy vui vẻ với nó!

Các vấn đề liên quan