Как изменить размер элемента WPF на статическом событии? - PullRequest
0 голосов
/ 08 июля 2011

У меня есть графический интерфейс с элементами, которые должны отображаться с определенным размером в миллиметрах.
Для этой цели у меня есть (глобальный) статический класс PPMM (= пикселей на миллиметр) с double? Factor иevent FactorChanged, оба статические.Установщик Factor вызывает обработчик события FactorChanged.
Элементами в GUI являются UserControls и перехват (в конструкторе) для события FactorChanged для обновления их размеров в пикселях или ScaleTransforms.

При компоновке графического интерфейса я не хочу создавать UserControls для каждого объекта, размер которого должен быть в миллиметрах.
Скорее, я хотел бы использовать что-то вроде

<elem Margin="0, {?:getPixelsFromMillimeters(
    desiredSize:{x:Const 20mm},
    fallback:{x:Const 80px})}" />

размер мм и запасной размер пикселя должен быть привязываемым.

Я думал о привязке к Factor и использовании IValueConverter с желаемым размером мм в parameter преобразователя.Но тогда я не могу привязаться к переменной мм .

Я могу привязаться к мм и использовать конвертер, но затем изменить Factorне будет обновлять меру.

Мне также не удалось создать DependencyProperty в статическом классе (GetValue и SetValue там не доступны), но это был бы другой вопрос SO...

Какими правильными способами добиться того, что я пытаюсь сделать?

Есть детали, которые я оставил без ответа?Если да, пожалуйста, оставьте комментарий.

1 Ответ

0 голосов
/ 11 июля 2011

Я сам пришел с рабочим ответом из комментариев stukselbax ...

Короче говоря: Некоторый размер WPF или другое свойство меры мультисвязывается со статическим DependencyProperty Factor и некоторым статическим значениям удваивается как параметры (размер в мм, запасной размер в пикселях) через 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;
}

Создание делегата и EventArgs дляFactorChanged:

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 для свойства зависимости статического фактора и размера в мм и размера отступа в пикселях (какstatic doubles) в XAML:

    <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>

Можно также привязать размер в мм к свойству зависимости (при условии, что установлен правильный 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>

Voilà!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...