为什么UserControl文本块在设计模式下振动

时间:2016-04-01 19:37:36

标签: c# wpf xaml user-controls

当我将usercontrol添加到窗口时,为什么文本会在设计模式下振动? Video of issue

<UserControl x:Class="AircraftGauges.InnerGauge"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:AircraftGauges"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="200"
             DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <UserControl.Resources>
        <local:CenterConverter x:Key="CenterConverter"/>
    </UserControl.Resources>
    <Canvas Width="200" Height="200" Background="White">
        <Path Stroke="Black" StrokeThickness="1" Data="M 40, 95 V 105 H 160 V 95 H 105 V 85 H 95 V 95 Z " Fill="Black"/>
        <TextBlock Name="CenterLabel" Text="{Binding PathData}" Foreground="Black" VerticalAlignment="Center"
                       Canvas.Left="100" Canvas.Top="112">
            <TextBlock.Margin>
                <MultiBinding Converter="{StaticResource CenterConverter}">
                    <Binding ElementName="CenterLabel" Path="ActualWidth"/>
                    <Binding ElementName="CenterLabel" Path="ActualHeight"/>
                </MultiBinding>
            </TextBlock.Margin>
        </TextBlock>
    </Canvas>
</UserControl>

Code Behind:InnerGauge.xaml.cs:

namespace AircraftGauges
{
    /// <summary>
    /// Interaction logic for InnerGauge.xaml
    /// </summary>
    public partial class InnerGauge : UserControl, INotifyPropertyChanged
    {
        private string _path;

        public event PropertyChangedEventHandler PropertyChanged;

        public InnerGauge()
        {
            InitializeComponent();

            SizeChanged += SizeChangedEventHandler;
        }

        private void SizeChangedEventHandler(object sender, SizeChangedEventArgs e)
        {
            UpdatePathData(e.NewSize.Width, e.NewSize.Height);
        }

        private void UpdatePathData(double w, double h)
        {
            var newPath = $"W {w} -- H {h}";

            if (String.CompareOrdinal(_path, newPath) != 0)
            {
                _path = newPath;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PathData)));
            }
        }

        public string PathData
        {
            get
            {
                return _path;
            }
        }
    }
}

CenterConverter.cs

namespace AircraftGauges
{
    public class CenterConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (values[0] == DependencyProperty.UnsetValue || values[1] == DependencyProperty.UnsetValue)
            {
                return DependencyProperty.UnsetValue;
            }

            var width = (double) values[0];
            var height = (double) values[1];

            return new Thickness(-width/2, -height/2, 0, 0);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

}

1 个答案:

答案 0 :(得分:1)

确实有趣的案例,原因是布局四舍五入。似乎wpf设计器默认将UseLayoutRounding设置为true,用于您在其中查看的窗口。但是,在运行时,对于窗口,UseLayoutRounding为false。什么布局舍入意味着像width \ height \ margin这样的东西在布局测量期间舍入到整个像素。在CenterConverter中,您可以根据文本块的高度和宽度计算文本块的边距。但是改变保证金会导致宽度变化,从而导致利润变化。由于布局四舍五入,这个过程永远不会结束。

您可以通过显式设置UseLayoutRounding = false(设计器将停止振动)或显式设置为true(将在运行时振动)来验证。通常,您需要修复CenterConverter以将其考虑在内。