我可以在code中單獨設置邊距,但是如何在XAML中執行此操作我該怎麼做:如何僅在XAML中設置頂部邊距?
僞代碼:
<StackPanel Margin.Top="{Binding TopMargin}">
我可以在code中單獨設置邊距,但是如何在XAML中執行此操作我該怎麼做:如何僅在XAML中設置頂部邊距?
僞代碼:
<StackPanel Margin.Top="{Binding TopMargin}">
的關鍵是要認識到它設置在這樣的代碼:
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
只返回一個Thickness
,僅設置了Top
並留下所有其他值爲零。
當然,你可以寫你自己的控件不公開爲依賴屬性讓你的代碼乾淨了一點這些單個值:
<CustomBorder TopMargin="{Binding TopMargin}">
</CustomBorder>
你不能用綁定僅定義上邊距,因爲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>
考慮到他希望設置保證金的單個部分並保持其他現有值不變,該如何工作? – 2009-08-22 17:43:07
那麼,所有的屬性將被設置在初始化,但事後你只需要改變一個綁定的屬性... – 2009-08-22 17:54:59
順便說一句,你的解決方案有完全相同的限制;) – 2009-08-22 17:57:01
使用轉換器,以下示例代碼將轉換雙重綁定到一個厚度。它會將厚度的「頂部」設置爲綁定字段。您可以選擇使用ConverterParameter來確定您是否綁定到左側,頂部,右側或底部。
<StackPanel Margin="{Binding TopMargin, Converter={StaticResource MyThicknessConverter}">
。
public class ThicknessSingleValueConverter : IValueConverter
{
override Convert(...)
{
return new Thickness(0, (double)object, 0, 0);
}
//etc...
這不是你想要的?
<StackPanel Margin="0,10,0,0" />
第一個值是左邊距,然後是頂部,然後是右邊,最後是但不是最低。
我不確定你是否想將它綁定到某些東西,但如果不是,那就行了。
我想你可以使用屬性語法,從MSDN:
<object.Margin>
<Thickness Top="{Binding Top}"/>
</object.Margin>
比你不需要任何轉換器
但最不DependancyProperty - 迴轉爐
什麼將是不錯的是能夠通過指定類似下面的代碼示例這樣做。
<StackPanel Margin=",10,,">
不幸的是這種能力似乎並沒有默認WPF中存在,這是一個恥辱,因爲它需要開發商進行硬編碼已知的默認值的方式,後來使得它更難的皮膚或主題的應用程序。
我現在可以想到的最佳解決方案是使用轉換器,但是爲了介紹這一點,您必須生成的額外代碼量並不理想。
這裏是一個極好的解決方案:
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"
該代碼將根據您的資源創建邊距。
這屬於WPF修訂:
如果不使用任何附加屬性或邊距的綁定,則無法動態設置元素的位置,而無需編寫幾行代碼。
不要將此技術與其他人進行比較。
您的問題在#9列出。
也許我是「遲到派對」,但不喜歡任何提供的解決方案,在我看來,最簡單和最乾淨的解決方案是在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);
}
}
然後XAML很簡單:
<StackPanel Margin="{Binding Margin}">
厚度和邊距是與視圖相關的概念。因此,它們不屬於正確的視圖模型。 – aaronburro 2017-10-12 19:25:07
這裏是這樣做,而無需編寫轉換器或硬編碼邊距值的簡單方法。首先,定義在窗口(或其他控件)以下資源:
<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>
現在,你只需要改變一個地方:
現在,您可以按如下方式使用這些資源。
只是寫了一些附加屬性,應該可以很容易地從一個綁定或靜態的資源上設置單獨的頁邊距值:
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(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會使用除邊距由樣式給出的保證金,將與0被覆蓋
有樂趣!
簡單,有效,我不確定人們爲什麼嘗試並使其複雜化。一條線比20條線好得多,有些人認爲需要這條線。我很欣賞這個答案。 – Middletone 2012-05-01 03:30:43
你可以像這樣設置'var margin = sp2.Margin; margin.Left = 5; SP2。保證金=保證金;'這會使其他值保持不變。 – bugged87 2012-09-28 03:06:53
@ bugged87:OP想要在XAML中做到這一點。 – 2012-09-28 06:47:56