5

ウィンドウのサイズとコンポーネントの場所は、使用するメインの UserControl サイズとその他のマイナー サイズ設定に基づいているため、初期化時に動的に計算する必要がある WPF アプリケーションを開発しています。そのため、当面は、これらの定数値を次のように Windows コードに配置しました。

public const Double MarginInner = 6D;
public const Double MarginOuter = 10D;
public const Double StrokeThickness = 3D;

public static readonly Double TableHeight = (StrokeThickness * 2D) + (MarginInner * 3D) + (MyUC.RealHeight * 2.5D);
public static readonly Double TableLeft = (MarginOuter * 3D) + MyUC.RealHeight + MarginInner;
public static readonly Double TableTop = MarginOuter + MyUC.RealHeight + MarginInner;
public static readonly Double TableWidth = (StrokeThickness * 2D) + (MyUC.RealWidth * 6D) + (MarginInner * 7D);
public static readonly Double LayoutHeight = (TableTop * 2D) + TableHeight;
public static readonly Double LayoutWidth = TableLeft + TableWidth + MarginOuter;

次に、次のように XAML 内でそれらを使用します。

<Window x:Class="MyNS.MainWindow" ResizeMode="NoResize" SizeToContent="WidthAndHeight">
    <Canvas x:Name="m_Layout" Height="{x:Static ns:MainWindow.LayoutHeight}" Width="{x:Static ns:MainWindow.LayoutWidth}">

ええと... 言うことはありません。それは機能します...しかし、見るのはすっごく醜いので、これに対するより良い解決策があるかどうか疑問に思っていました。わかりません...おそらく、設定ファイル、バインディング、インラインXAML計算など...見た目を良くする何か.

4

3 に答える 3

5

私は通常、すべての静的なアプリケーション設定を、次のような汎用的なものと呼ばれる単一の静的またはシングルトン クラスに入れますApplicationSettings(またはMainWindowSettings、値が によってのみ使用される場合MainWindow)

値をユーザーが構成できるようにする場合、値は app.config に入り、静的クラスのコンストラクターに読み込まれます。そうでない場合は、静的クラスにハードコーディングして、後で簡単に見つけたり変更したりできるようにします。

public static class ApplicationSettings
{
    public static Double MarginInner { get; private set; }
    public static Double MarginOuter { get; private set; }
    public static Double StrokeThickness { get; private set; }

    static ApplicationSettings()
    {
        MarginInner = 6D;
        MarginOuter = 10D;
        StrokeThickness = 3D;
    }
}

XAML で計算された値の場合、私は通常、私が作成したMathConverterを使用します。これにより、数式を使用してバインドを記述し、使用する値を渡すことができます。

私がブログに投稿したバージョンは のみですが、IValueConverterに拡張するのは非常に簡単なIMultiValueConverterので、複数のバインドされた値を受け入れることができます。

<Setter Property="Height">
   <Setter.Value>
      <MultiBinding Converter="{StaticResource MathMultiConverter}"
                    ConverterParameter="(@VALUE1 * 2D) + (@VALUE2 * 3D) + (@VALUE3 * 2.5D)">
         <Binding RelativeSource="{x:Static ns:ApplicationSettings.StrokeThickness }" />
         <Binding RelativeSource="{x:Static ns:ApplicationSettings.MarginInner}" />
         <Binding ElementName="MyUc" Path="ActualHeight" />
      </MultiBinding>
   </Setter.Value>
</Setter>

通常、この乱雑な XAML はすべて Style に隠して、メインの XAML コードを乱雑にせず、必要な場所にスタイルを適用するだけです。

これは、私が使用するコンバーターコードのコピーですIMultiValueConvter

// Does a math equation on a series of bound values. 
// Use @VALUEN in your mathEquation as a substitute for bound values, where N is the 0-based index of the bound value
// Operator order is parenthesis first, then Left-To-Right (no operator precedence)
public class MathMultiConverter : IMultiValueConverter
{
    public object  Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        // Remove spaces
        var mathEquation = parameter as string;
        mathEquation = mathEquation.Replace(" ", "");

        // Loop through values to substitute placeholders for values
        // Using a backwards loop to avoid replacing something like @VALUE10 with @VALUE1
        for (var i = (values.Length - 1); i >= 0; i--)
            mathEquation = mathEquation.Replace(string.Format("@VALUE{0}", i), values[i].ToString());

        // Return result of equation
        return MathConverterHelpers.RunEquation(ref mathEquation);
    }

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

public static class MathConverterHelpers
{
    private static readonly char[] _allOperators = new[] { '+', '-', '*', '/', '%', '(', ')' };

    private static readonly List<string> _grouping = new List<string> { "(", ")" };
    private static readonly List<string> _operators = new List<string> { "+", "-", "*", "/", "%" };


    public static double RunEquation(ref string mathEquation)
    {
        // Validate values and get list of numbers in equation
        var numbers = new List<double>();
        double tmp;

        foreach (string s in mathEquation.Split(_allOperators))
        {
            if (s != string.Empty)
            {
                if (double.TryParse(s, out tmp))
                {
                    numbers.Add(tmp);
                }
                else
                {
                    // Handle Error - Some non-numeric, operator, or grouping character found in string
                    throw new InvalidCastException();
                }
            }
        }

        // Begin parsing method
        EvaluateMathString(ref mathEquation, ref numbers, 0);

        // After parsing the numbers list should only have one value - the total
        return numbers[0];
    }

    // Evaluates a mathematical string and keeps track of the results in a List<double> of numbers
    private static void EvaluateMathString(ref string mathEquation, ref List<double> numbers, int index)
    {
        // Loop through each mathemtaical token in the equation
        string token = GetNextToken(mathEquation);

        while (token != string.Empty)
        {
            // Remove token from mathEquation
            mathEquation = mathEquation.Remove(0, token.Length);

            // If token is a grouping character, it affects program flow
            if (_grouping.Contains(token))
            {
                switch (token)
                {
                    case "(":
                        EvaluateMathString(ref mathEquation, ref numbers, index);
                        break;

                    case ")":
                        return;
                }
            }

            // If token is an operator, do requested operation
            if (_operators.Contains(token))
            {
                // If next token after operator is a parenthesis, call method recursively
                string nextToken = GetNextToken(mathEquation);
                if (nextToken == "(")
                {
                    EvaluateMathString(ref mathEquation, ref numbers, index + 1);
                }

                // Verify that enough numbers exist in the List<double> to complete the operation
                // and that the next token is either the number expected, or it was a ( meaning 
                // that this was called recursively and that the number changed
                if (numbers.Count > (index + 1) &&
                    (double.Parse(nextToken) == numbers[index + 1] || nextToken == "("))
                {
                    switch (token)
                    {
                        case "+":
                            numbers[index] = numbers[index] + numbers[index + 1];
                            break;
                        case "-":
                            numbers[index] = numbers[index] - numbers[index + 1];
                            break;
                        case "*":
                            numbers[index] = numbers[index] * numbers[index + 1];
                            break;
                        case "/":
                            numbers[index] = numbers[index] / numbers[index + 1];
                            break;
                        case "%":
                            numbers[index] = numbers[index] % numbers[index + 1];
                            break;
                    }
                    numbers.RemoveAt(index + 1);
                }
                else
                {
                    // Handle Error - Next token is not the expected number
                    throw new FormatException("Next token is not the expected number");
                }
            }

            token = GetNextToken(mathEquation);
        }
    }

    // Gets the next mathematical token in the equation
    private static string GetNextToken(string mathEquation)
    {
        // If we're at the end of the equation, return string.empty
        if (mathEquation == string.Empty)
        {
            return string.Empty;
        }

        // Get next operator or numeric value in equation and return it
        string tmp = "";
        foreach (char c in mathEquation)
        {
            if (_allOperators.Contains(c))
            {
                return (tmp == "" ? c.ToString() : tmp);
            }
            else
            {
                tmp += c;
            }
        }

        return tmp;
    }
}

しかし、正直なところ、これらの値が単一のフォームでのみ使用される場合はLoaded、ビューの背後にあるコードのイベントに値を設定するだけです:)

于 2013-03-27T15:45:21.890 に答える
2

それらの静的なものを app.config に入れてください。

app.config を使用するには、まず への参照が必要System.Configurationです。

次に、次のことができます(型キャストが含まれる場合があります):

 ConfigurationManager.AppSettings["MarginInner"];

取得するには:

<configuration>
    <appsettings>
        <add key="MarginInner" value="6D" />
    </appsettings>
</configuration>

次に、次のような動的計算を保持するための静的クラスを作成します。

public class CalculationHelper
{
    //your dynamic properties in here
}
于 2013-03-27T14:38:43.837 に答える
1

mattytommo の答えは、あなたが持っている定数値 (余白とストロークの太さ) のみに対応し、計算フィールドには対応していません。

Matty が言ったことに関連して、app.config ファイルから定数値を取得し、必要な適切な計算も行う設定クラスを追加して、XAML で適切なプロパティを参照できるようにします。

すなわち

{ Settings.MainWindow.LayoutWidth }

編集 :

私の投稿の間に彼が編集したように、マティも同じように見えました;)

于 2013-03-27T14:43:46.260 に答える