Hope someone can help. I have a simple scenario where clicking checkboxes is driving a progress bar in WPF. The checkboxes are contained in a UserControl and the Progress bar is in a simple WPF client window. On the user control I am using two dependency properties: 1) the existing Tag property has the value I wish to bind to the progress bar value and 2) a DP called CbCount which represents the total number of checkboxes.
The problem: When the application runs the progress bar's progress shows as being 100% complete even though via Snoop I can see the value is in fact 0. Clicking on the checkboxes everything works fine as expected.
Code: UserControl - within namespace 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>
The Client which just has the databindings is a simple window - the local namespace below refers to the project namespace xmlns:local="clr-namespace:ProgBarChkBxs", the meat of the code is:
<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>
The really weird thing is if within the DP definition of the CbCount if I change the FrameworkPropertyMetadata to a really small value to say (double)0.001 the problem goes away.
I am running this on XP.
All help gratefully received - thanks.
Update: I have been digging into this again as it gnaws at my sole (who said get a life!)
Things I did:
1) Adding a slider which also like progressBar inherits from RangeBase gives me the expected behaviour.
2) Spinning up reflector I can see the static ctor for ProgressBar sets the default value first to 100, RangeBase.MaximumProperty.OverrideMetadata(typeof(ProgressBar), new FrameworkPropertyMetadata(100.0)); Should AffectMeasure? whereas in the slider: RangeBase.MaximumProperty.OverrideMetadata(typeof(Slider), new FrameworkPropertyMetadata(10.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
3) So we need another layout pass after a I set the ProgressBar.Value Going back to my simple POC application if within a the progressBar loaded handler in the client window I jig the layout on the first run through:
this.Width += 1; //trigger another layout pass
Then, hey, presto it works.
So is this a bug?
I still do not fully understand though how the progressBar value which is calculated from Minimum and Maximum values is affected in this way and not the Slider - the default value of Maximum appears to be having an effect and it looks as if the ProgressBar default should affect the measure pass. (missing FrameworkPropertyMetadataOptions.AffectsMeasure
.)
Can anyone help, either confirm my thinking or explain what is really happening here?