如何在静态事件上调整WPF元素的大小?

时间:2011-07-08 10:47:04

标签: c# wpf events layout

我有一个GUI,其元素应以毫米为单位显示特定大小 为此,我有一个(全局)静态类PPMM(=每毫米像素数),double? Factorevent FactorChanged都是静态的。 Factor的设置者调用FactorChanged事件处理程序 GUI中的元素是UserControls和FactorChanged事件的钩子(在构造函数中)以更新其像素大小或ScaleTransforms。

在布局GUI时,我不想为每个要以毫米为单位的对象创建UserControl。
相反,我想以

的方式使用某些东西
<elem Margin="0, {?:getPixelsFromMillimeters(
    desiredSize:{x:Const 20mm},
    fallback:{x:Const 80px})}" />

mm size 和后备像素大小应该是可绑定的。

我考虑过绑定到Factor并在转换器的IValueConverter中使用所需 mm size parameter。但是我无法绑定到变量 mm size 值。

我可以绑定到 mm size 并使用转换器,但随后更改Factor将不会更新该度量。

我也没有设法在静态类中创建DependencyProperty(GetValue并且SetValue在那里不可用),但那将是一个不同的SO问题......

有什么方法可以实现我的目标?

我还有没有回复的详细信息?如果是,请发表评论。

1 个答案:

答案 0 :(得分:0)

我从stukselbax的评论中得出了一个有效的答案......

简而言之:某些WPF大小或其他度量属性多重绑定到静态DependencyProperty 因子和一些静态双精度作为参数(大小以mm为单位,后退大小以像素为单位)通过IMultiValueConverter。静态因子来自单身人士。其他类可以订阅的单例中还有一个事件 FactorChanged

创建一个用作单例实例的类:

public class PPMMSingleton : DependencyObject
{
    public double? Factor
    {
        get { return (double?)GetValue(FactorProperty); }
        set { SetValue(FactorProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Factor.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FactorProperty =
        DependencyProperty.Register("Factor", typeof(double?), typeof(PPMMSingleton),
            new FrameworkPropertyMetadata(null,
                FrameworkPropertyMetadataOptions.AffectsMeasure |
                FrameworkPropertyMetadataOptions.AffectsRender |
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault |
                FrameworkPropertyMetadataOptions.Inherits,
                new PropertyChangedCallback(OnFactorChanged),
                new CoerceValueCallback(CoerceFactor)));

    private static object CoerceFactor(DependencyObject element, object value)
    {
        return value;
    }

    public static void OnFactorChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        PPMMSingleton ppmm = (PPMMSingleton)sender;

        ppmmEventArgs e =
            new ppmmEventArgs(
                (double?)args.OldValue,
                (double?)args.NewValue);
        ppmm.OnFactorChanged(e);
    }

    private void OnFactorChanged(ppmmEventArgs e)
    {
        if (FactorChanged != null)
            FactorChanged(e);
    }

    public event ppmmEventHandler FactorChanged;
}

为FactorChanged创建委托和EventArgs:

public delegate void ppmmEventHandler(ppmmEventArgs e);

public class ppmmEventArgs : EventArgs
{
    public ppmmEventArgs(double? oldFactor, double? newFactor)
    {
        OldFactor = oldFactor;
        NewFactor = newFactor;
    }

    public double? OldFactor { get; private set; }
    public double? NewFactor { get; private set; }
}

创建一个静态类来托管这个单例:

public static class PPMM
{
    public static double? Factor
    {
        get { return Singleton.Factor; }
        set
        {
            Singleton.Factor = value;
        }
    }

    private static PPMMSingleton _singleton = null;
    public static PPMMSingleton Singleton
    {
        get
        {
            if (_singleton == null)
                _singleton = new PPMMSingleton();
            return _singleton;
        }
    }

    public static event ppmmEventHandler FactorChanged
    {
        add { Singleton.FactorChanged += value; }
        remove { Singleton.FactorChanged -= value; }
    }
}

创建一个IMultiValueConverter,它采用因子,以毫米为单位的大小和可选的大小(以像素为单位)作为后备:

public class FactorAndMillimeterToPixelConverter : IMultiValueConverter
{
    #region IMultiValueConverter Member

    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if ((values.Length < 2)
            || !(values[0] is double?))
            return Binding.DoNothing;

        double? factor = (double?)values[0];

        switch(values.Length)
        {
            case 2:
                if(!(values[1] is double))
                    return Binding.DoNothing;
                // values[0]: Factor, values[1]: SizeMM
                // if Factor is null, no fallback provided -> donothing
                if (!factor.HasValue)
                    return Binding.DoNothing;
                // else return calculated width
                return factor.Value * (double)values[1];

            case 3:
                if (!(values[1] is double) || !(values[2] is double))
                    return Binding.DoNothing;
                // values[0]: Factor, values[1]: SizeMM, values[2]: SizePixelsFallback
                // if Factor is null, but fallback provided -> return fallback
                if (!factor.HasValue)
                    return (double)values[2];
                // else return calculated width
                return factor.Value * (double)values[1];

            default:
                // value.Length > 3
                return Binding.DoNothing;
        }
    }

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

    #endregion
}

将转换器中的资源放入XAML:

        <mynamespace:FactorAndMillimeterToPixelConverter x:Key="fm2pconv" />

MultiBind到XAML中的静态Factor依赖项属性和mm的大小以及像素的后备大小(两者都是静态双精度):

    <Border>
        <Border.Width>
            <MultiBinding Converter="{StaticResource fm2pconv}">
                <MultiBinding.Bindings>
                    <Binding Path="Factor" Source="{x:Static tc:PPMM.Singleton}" />
                    <Binding>
                        <Binding.Source>
                            <sys:Double>50</sys:Double>
                        </Binding.Source>
                    </Binding>
                    <Binding>
                        <Binding.Source>
                            <sys:Double>400</sys:Double>
                        </Binding.Source>
                    </Binding>
                </MultiBinding.Bindings>
            </MultiBinding>
        </Border.Width>
        <TextBlock
            Text="Wenn Factor gesetzt ist, ist dieser Kasten 50mm breit. Ansonsten ist er 400px breit. Seine Width wird beeinflusst."
            TextWrapping="WrapWithOverflow"
            >
        </TextBlock>
    </Border>

还可以将mm的大小绑定到依赖项属性(假设设置了正确的DataContext):

        <Border.Width>
            <MultiBinding Converter="{StaticResource fm2pconv}">
                <MultiBinding.Bindings>
                    <Binding Path="Factor" Source="{x:Static tc:PPMM.Singleton}" />
                    <Binding Path="WidthInMMInCodeBehind" />
                    <Binding Path="FallbackWidthInPixelsInCodeBehind" />
                </MultiBinding.Bindings>
            </MultiBinding>
        </Border.Width>

瞧!