سؤال

لدي مربع نص نص الملكية لديها Twoway متعددة مع addatesourcetrigger ضبط ل PropertyChanged. الأول ربط هو خاصية التبعية (قيمة) التي لديها PropertyChangedCallback الوظيفة التي تدور حول القيمة إلى مكان عشري واحد.

الغرض من مربع النص هو تنفيذ التقريب كنوع المستخدم بدلاً من أن يفقد مربع النص التركيز ، وبالتالي السبب addatesourcetrigger تم تعيينه على PropertyChanged.

المشكلة التي أواجهها هي أنه في حالة إدخال النص ، لا يؤدي ذلك قيمة التغيير ، و نص الممتلكات و قيمة كن خارج المزامنة. فقط إذا تسببت عملية التقريب قيمة للتغيير نص الحصول على تحديث أثناء الطيران. على سبيل المثال ، إذا نص و قيمة كلاهما 123.4 وأنواع المستخدمين 1 بعد هذا ، قيمة يتم تقريبه إلى نفس القيمة (123.4) ، ولكن نص يظهر 123.41. ومع ذلك ، إذا تم كتابة 9 بعد ذلك بعد 4 ، قيمة يدور حتى 123.5. وبسبب هذا التغيير الفعلي ، نص ثم يتم تحديثه إلى نفسه (123.5).

هل هناك أي طريقة لإجبار مربع نص على التحديث من مصدره حتى عندما لم يتغير المصدر منذ آخر مشغل؟ لقد حاولت استخدام BindingExpressionBase.UpdateTarget() لكن هذا يعمل فقط عندما addatesourcetrigger تم تعيينه على صريح, ، والتي لا يمكن استخدامها ك قيمة لم يعد يتم تحديثه قبل وقت مناسب حيث updateTarget يمكن أن يسمى (مثل أ إدخال النص معالج). لقد جربت أساليب أخرى مثل تحديث صريح نص القيمة من الحد قيمة, ، إجبار التغيير الفعلي على قيمة مؤقتًا لاستدعاء تحديث ، لكن هؤلاء "الاختراقات" إما لا تعمل أو تسبب مشاكل أخرى.

أي مساعدة سيكون موضع تقدير كبير.

الكود أدناه.

مقتطف XAML

<TextBox>
  <TextBox.Text>
    <MultiBinding Converter="{local:NumberFormatConverter}"
                  UpdateSourceTrigger="Explicit"
                  Mode="TwoWay">
      <Binding Path="Value"
               RelativeSource="{RelativeSource AncestorType={x:Type Window}}"
               Mode="TwoWay" />
    </MultiBinding>
  </TextBox.Text>
</TextBox>

C# مقتطف

public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register(
        "Value", typeof(decimal), typeof(MainWindow),
        new FrameworkPropertyMetadata(0m,
        new PropertyChangedCallback(OnValueChanged)));

private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
    obj.SetValue(ValueProperty, Math.Round((decimal)args.NewValue, 1));
}

فئة المحول المطلوبة

public class NumberFormatConverter : MarkupExtension, IMultiValueConverter
{
    public static NumberFormatConverter Instance { private set; get; }

    static NumberFormatConverter()
    {
        Instance = new NumberFormatConverter();
    }

    public override object ProvideValue(IServiceProvider serviceProvider_)
    {
        return Instance;
    }

    #region Implementation of IMultiValueConverter

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return values[0].ToString();
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        var result = 0m;
        if (value != null)
        {
            decimal.TryParse(value.ToString(), out result);
        }
        return new object[] { result };
    }

    #endregion
}
هل كانت مفيدة؟

المحلول

لقد قمت بحفر القليل على الإنترنت ، واتضح أن هذا قد تم كسره في WPF 4. شخص لديه مشكلة شبه متطورة بالنسبة لي نشرت هنا:http://www.go4answers.com/example/textbox-shows- القديم-value-being-coerced-137799.aspx

"الإجابة 8" تنص على أن هذا تم كسره في WPF 4 ويقترح حلًا ، وهو الاستخدام فعليًا UpdateSourceTrigger="Explicit" ولكن للتعامل مع الحدث المعدل والاتصال bindingexpression.updatesource () لفرض التغييرات في مربع النص المراد انعكاسه في القيمة الأساسية كما لو UpdateSourceTrigger="PropertyChanged", ، وفقا لهذا المنصب:إجبار مربع نص WPF لم يعد يعمل في .NET 4.0

لقد قمت بتطبيق هذا ، لكن لو وها كانت هناك آثار جانبية أخرى ، على وجه الخصوص أن كل ضغط مفتاح تسبب في القفز على المذبحة إلى بداية مربع النص بسبب تحديث المصدر ورفع أ PropertyChanged حدث. وأيضًا ، سيتم القضاء على أي أصفار رائدة أو زائدة أو أماكن عشرية تم إدخالها بقصد الدخول إلى مزيد من الأرقام. لذلك ، هناك حالة بسيطة للتحقق من القيمة العشرية المحلية لمربع النص مقابل القيمة الأساسية التي تم حلها.

معالج الأحداث التالي هو كل ما هو مطلوب:

private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    var tb = (TextBox)e.Source;
    MultiBindingExpression binding = BindingOperations.GetMultiBindingExpression(tb, TextBox.TextProperty);

    decimal result = 0m;
    decimal.TryParse(tb.Text, out result);

    if ((decimal)GetValue(ValueProperty) != result && binding != null)
    {
        int caretIndex = tb.CaretIndex;
        binding.UpdateSource();
        tb.CaretIndex = caretIndex;
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top