Является ли это WPF ProgressBar странным поведением рендера? - PullRequest
0 голосов
/ 05 декабря 2009

Надеюсь, кто-нибудь может помочь. У меня есть простой сценарий, в котором при нажатии флажков отображается индикатор выполнения в WPF . Флажки содержатся в UserControl, а индикатор выполнения находится в простом окне клиента WPF. На пользовательском элементе управления я использую два свойства зависимости: 1) существующее свойство Tag имеет значение, которое я хочу связать со значением индикатора выполнения, и 2) DP под названием CbCount, который представляет общее количество флажков.

Проблема: Когда приложение запускается, индикатор выполнения отображается как выполненный на 100%, хотя с помощью Snoop я вижу, что значение фактически равно 0. При нажатии на флажки все работает нормально, как и ожидалось.

Код: UserControl - в пространстве имен ProgBarChkBxs:

public partial class ucChkBoxes : UserControl
{
    #region CbCount

    public static readonly DependencyProperty CbCountProperty =
        DependencyProperty.Register("CbCount", typeof(double), typeof(ucChkBoxes),
            new FrameworkPropertyMetadata((double)0));

    /// <summary>
    /// Gets or sets the CbCount property.  This dependency property
    /// indicates the number of checkBoxes
    /// </summary>
    public double CbCount
    {
        get { return (double)GetValue(CbCountProperty); }
        private set { SetValue(CbCountProperty, value); }
    }

    #endregion

    double _totalCount = 0;
    double _numberChecked = 0;
    double DEFAULT = 0;

    public ucChkBoxes()
    {
        InitializeComponent();
        this.Tag = DEFAULT;
        this.Loaded += new RoutedEventHandler(ucChkBoxes_Loaded);
    }

    void ucChkBoxes_Loaded(object sender, RoutedEventArgs e)
    {
        if (this.ourContainer.Children.Count != 0)
        {
            _totalCount = this.ourContainer.Children.Count;
        }
        this.CbCount = (double)_totalCount;
    }

    private void CheckBox_Checked(object sender, RoutedEventArgs e)
    {
        if (e.OriginalSource.GetType() == typeof(CheckBox))
        {
            CheckBox cb = (CheckBox)e.OriginalSource;
            if (cb.IsChecked == true) { _numberChecked++; }
            if (cb.IsChecked != true) { _numberChecked--; }

            //simple POC progress metric
            this.Tag = (double)(_numberChecked / _totalCount * _totalCount);
        }
    }
}

XAML:

<UserControl x:Class="ProgBarChkBxs.ucChkBoxes"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="Auto" Width="Auto">
    <StackPanel>
        <TextBlock  Text="Please select options" ></TextBlock>
        <StackPanel Name="ourContainer"
                    CheckBox.Checked="CheckBox_Checked"
                    CheckBox.Unchecked="CheckBox_Checked">
            <CheckBox>Fruit Juice</CheckBox>
            <CheckBox>Coffee</CheckBox>
            <CheckBox>Toast</CheckBox>
            <CheckBox>Cereal</CheckBox>
            <CheckBox>Grapefruit</CheckBox>
        </StackPanel>
    </StackPanel>
</UserControl>

Клиент, который имеет только привязки данных, является простым окном - локальное пространство имен ниже относится к пространству имен проекта xmlns: local = "clr-namespace: ProgBarChkBxs", основная часть кода:

<StackPanel>
    <local:ucChkBoxes  x:Name="chkBoxes"/>
    <ProgressBar Name="pb" Background="Azure" Minimum="0" Height="30"
                 Value="{Binding ElementName=chkBoxes,Path=Tag }"
                 Maximum="{Binding ElementName=chkBoxes,Path=CbCount }"
    />
</StackPanel>

Действительно странная вещь, если в определении DP CbCount, если я изменю FrameworkPropertyMetadata на действительно маленькое значение, чтобы сказать (удвоить) 0,001, проблема исчезнет.

Я запускаю это на XP.

Вся помощь с благодарностью получена - спасибо.

Обновление: Я снова копался в этом, так как он грызет мою подошву (кто сказал, возьми жизнь!)

То, что я сделал:

1) Добавление ползунка, который также, как progressBar наследует от RangeBase, дает мне ожидаемое поведение.

2) Вращающийся отражатель. Я вижу, что статический ctor для ProgressBar сначала устанавливает значение по умолчанию равным 100, RangeBase.MaximumProperty.OverrideMetadata (typeof (ProgressBar), новый FrameworkPropertyMetadata (100.0)); Должен ли AffectMeasure? тогда как в слайдере: RangeBase.MaximumProperty.OverrideMetadata (typeof (Slider), новый FrameworkPropertyMetadata (10.0, FrameworkPropertyMetadataOptions.AffectsMeasure));

3) Итак, нам нужен еще один проход макета после того, как я установил ProgressBar.Value Возвращаясь к моему простому POC-приложению, если в загруженном обработчике progressBar в окне клиента я перетаскиваю макет при первом запуске:

this.Width += 1; //trigger another layout pass

Тогда, эй, просто это работает.

Так это ошибка?

Я до сих пор не до конца понимаю, как таким образом влияет значение progressBar, которое вычисляется из минимальных и максимальных значений, а не ползунок - значение по умолчанию Максимальное, похоже, оказывает влияние и выглядит так, как будто ProgressBar значение по умолчанию должно влиять на проход измерения. (отсутствует FrameworkPropertyMetadataOptions.AffectsMeasure.)

Может ли кто-нибудь помочь, подтвердить мои мысли или объяснить, что на самом деле здесь происходит?

1 Ответ

1 голос
/ 08 декабря 2009

Метод ucChkBoxes_Loaded вызывается после визуализации индикатора выполнения. Когда отображается индикатор выполнения, Tag и CbCount равны нулю, что означает, что индикатор выполнения будет иметь min = 0, max = 0 и значение = 0, что правильно отображается как 100%. Если вы аннулируете индикатор выполнения, например, окно изменения размера, оно будет отображаться как 0%, так как теперь Tag и CbCount были обновлены.

Чтобы исправить, не ждите, пока ucChkBoxes.Loaded () будет вызван для инициализации вашего элемента управления, сделайте это в конструкторе или при инициализации DP для CbCount, например.

public ucChkBoxes()
{
    InitializeComponent();
    this.Tag = DEFAULT;
    if (this.ourContainer.Children.Count != 0)
    {
        _totalCount = this.ourContainer.Children.Count;
    }
    this.CbCount = (double)_totalCount;
}
...