動機:
混合語法
<Label FontSize="50">Hello</Label>
可以轉換成純屬性語法,
<Label Text="Hello" FontSize="50"/>
或純元素語法
<Label>
<Label.Text>Hello</Label.Text>
<Label.FontSize>50</Label.FontSize>
</Label>
問題:
我們也可以轉換<x:Double x:Key="fontsize">50</x:Double> 成純屬性語法和純元素語法嗎?
在我的嘗試中,我找不到與50.
uj5u.com熱心網友回復:
要通過屬性或標簽設定值,型別必須具有帶有公共設定器的屬性。您只能為這些屬性賦值。
但是要將型別創建為內容中的值,該型別必須具有來自 String 的轉換器。
例子:
[TypeConverter(typeof(SomeStructConverter))]
public struct SomeStruct
{
private int X;
private int Y;
public override string ToString() => $"({X}, {Y})";
public static SomeStruct Parse(string text)
{
if (text is null)
throw new ArgumentNullException(nameof(text));
var split = text.Split(" \t\r\n,()".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
if (split.Length != 1 && split.Length != 2)
throw new ArgumentException(nameof(text));
int y, x = int.Parse(split[0]);
if (split.Length == 2)
y = int.Parse(split[1]);
else
y = x;
return new SomeStruct() { X = y, Y = x };
}
public static bool TryParse(string text, out SomeStruct some)
{
try
{
some = Parse(text);
return true;
}
catch (Exception)
{
some = new SomeStruct();
return false;
}
}
public static implicit operator SomeStruct(int number)
{
return new SomeStruct() { X = number, Y = number };
}
public static implicit operator int(SomeStruct some)
{
if (some.X != some.Y)
throw new InvalidCastException("X and Y must be the equals.");
return some.X;
}
}
public class SomeStructConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
if (sourceType == typeof(string) || sourceType == typeof(int) || sourceType == typeof(SomeStruct))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType)
{
if (destinationType == typeof(string) || destinationType == typeof(int) || destinationType == typeof(SomeStruct))
return true;
return base.CanConvertTo(context, destinationType);
}
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
Type sourceType = value.GetType();
if (sourceType == typeof(SomeStruct))
return value;
if (sourceType == typeof(int))
return (SomeStruct)(int)value;
if (sourceType == typeof(string))
return SomeStruct.Parse((string)value);
return base.ConvertFrom(context, culture, value);
}
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
{
if (value is not null)
{
if (destinationType == typeof(SomeStruct))
return value;
if (destinationType == typeof(int))
{
return (int)(SomeStruct)value;
}
if (destinationType == typeof(string))
return value.ToString();
}
return base.ConvertTo(context, culture, value, destinationType);
}
public override bool IsValid(ITypeDescriptorContext? context, object? value)
{
if (value != null)
{
Type sourceType = value.GetType();
if (sourceType == typeof(SomeStruct) || sourceType == typeof(int))
return true;
if (sourceType == typeof(string))
return SomeStruct.TryParse((string)value, out _);
}
return base.IsValid(context, value);
}
}
<local:SomeStruct x:Key="some">123 -456</local:SomeStruct>
Double 型別(與其他數字型別一樣)沒有屬性。因此,不可能通過數字的屬性或標簽來設定值。
uj5u.com熱心網友回復:
您已經接受了一個答案,但如果您想要一些不那么羅嗦的東西,您可以嘗試MarkupExtension提供雙精度或其他強型別值的
public class ValExtension<T> : MarkupExtension where T : struct
{
protected ValExtension(T val) => Value = val;
private object Value { get; }
public override object ProvideValue(IServiceProvider sp) { return Value; }
}
public class DoubleValExtension : ValExtension<double>
{
public DoubleValExtension(double v) : base(v) {}
}
我發現這在我不想依賴某些隱式型別轉換的任何地方都很有用,比如ConverterParameter在系結中的值轉換器中。由于ConverterParameter只是一個物件,因此僅在其中輸入“0.3”不會導致實際轉換器獲得雙倍。
例如,假設我有一個轉換器,它采用一個Category列舉和一個可選的 double 引數來調整計算值。我可以使用標記擴展來強制 XAML 傳遞一個裝箱的雙精度。
Opacity="{Binding SelectedItem.Category,
Converter={StaticResource ConvertCategoryToOpacity},
ConverterParameter={local:DoubleVal 0.3}
如果我嘗試這樣做,轉換器只會得到一個未轉換的字串。
Opacity="{Binding SelectedItem.Category,
Converter={StaticResource ConvertCategoryToOpacity},
ConverterParameter='0.3'}"
在某些情況下這可能很好,但如果我的轉換器指望檢查引數的型別,那就不行了。
您也可以從其他 POD 型別的泛型派生。
public class IntValExtension : ValExtension<int> { public IntValExtension(int v) : base(v) {} }
public class BoolValExtension : ValExtension<bool> { public BoolValExtension(bool v) : base(v) {} }
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/528301.html
