也是个很奇葩的问题了,有一个多值转换器IMultiValueConverter在ItemsControl里当成IValueConverter使用,编译不报错,可正常运行,但就是会阻塞ui。代码如下
xaml
1 2 3 4 5 6 7 8 9 10 11 12
| <ItemsControl ItemsSource="{Binding Items}"> <ItemsControl.ItemTemplate> <DataTemplate> <Border> <Grid> <TextBox Text="{Binding Rate, Converter={StaticResource DataTransferRateUnitValuesConverter}}" /> </Grid> </Border> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
|
csharp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| public class DataTransferRateUnitValuesConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (parameter != null && parameter.ToString() == "bps" && values.Length == 1 && values[0] is double rate1) { return $"{DataUnitHelper.GetTransferRate(rate1)}"; } if (values.Length == 2 && values[0] is string channelname && values[1] is double rate) { if (channelname.StartsWith("pps", StringComparison.CurrentCultureIgnoreCase)) { return $"{rate:0.###} pps"; } else { return $"{DataUnitHelper.GetTransferRate(rate)}"; } }
return "0 bps"; }
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
public class DataUnitHelper { private static readonly ulong TbLength = Convert.ToUInt64(Math.Pow(1024, 4)); private static readonly ulong GbLength = Convert.ToUInt64(Math.Pow(1024, 3)); private static readonly ulong MbLength = Convert.ToUInt64(Math.Pow(1024, 2)); private static readonly ulong KbLength = 1024;
private static readonly ulong TbpsLength = Convert.ToUInt64(Math.Pow(10, 12)); private static readonly ulong GbpsLength = Convert.ToUInt64(Math.Pow(10, 9)); private static readonly ulong MbpsLength = Convert.ToUInt64(Math.Pow(10, 6)); private static readonly ulong KbpsLength = Convert.ToUInt64(Math.Pow(10, 3));
public static string GetLength(ulong length) { if (length >= TbLength) { return (length * 1.0 / TbLength).ToString("0.###") + " TB"; }
if (length >= GbLength) { return (length * 1.0 / (GbLength)).ToString("0.###") + " GB"; }
if (length >= MbLength) { return (length * 1.0 / (MbLength)).ToString("0.###") + " MB"; }
if (length >= KbLength) { return (length * 1.0 / KbLength).ToString("0.###") + " KB"; }
return length + " B"; }
public static string GetTransferRate(double rate) { if (rate >= TbpsLength) { return (rate * 1.0 / TbpsLength).ToString("0.###") + " Tbps"; }
if (rate >= GbpsLength) { return (rate * 1.0 / (GbpsLength)).ToString("0.###") + " Gbps"; }
if (rate >= MbpsLength) { return (rate * 1.0 / (MbpsLength)).ToString("0.###") + " Mbps"; }
if (rate >= KbpsLength) { return (rate * 1.0 / KbpsLength).ToString("0.###") + " Kbps"; }
return rate.ToString("0.###") + " bps"; } }
|
经查阅资料,原来wpf做了自动兼容容错:把IMultiValueConverter当成 IValueConverter用,wpf不会崩溃,只会默默返回 DependencyProperty.UnsetValue
故而ui阻塞过程:
用错转换器 → WPF 引擎进入无限兼容 / 重试逻辑 → ui线程死循环阻塞
当然,改过来就行了。
我是因为这个转换器原本是IValueConverter,由于需求变化,改成了IMultiValueConverter,但妙就秒在这个转换器很多地方在用,因为不会显式的提醒编译报错,故而遗漏这个,这里也是很奇怪,其他的地方没有ItemsControl包裹确实是会提醒报错地方的,悲啊,最后定位到这个转换器全局查找才找到的。