tags:

views:

151

answers:

1

I want to create a program which calculates how long it will take to repeat a process a certain number of times. I've scaled this down a lot for this example.

So, I have some textboxes which are bound to properties in a class:

Count: <TextBox x:Name="txtCount" Text="{Binding Count, Mode=TwoWay}" Width="50"/>
Days: <TextBox x:Name="txtDays" Text="{Binding Days, Mode=TwoWay}" Width="50"/>

and a textblock which is multibound like so:

<TextBlock x:Name="tbkTotal">
    <TextBlock.Text>
        <MultiBinding StringFormat="Days: {0}, Count: {1}">
            <Binding Path="Days" /> /* This isn't updating */
            <Binding Path="Count" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

My DataContext is set in the Window1.xaml.cs file.

public Window1()
        {
            InitializeComponent();
            Sample sample = new Sample();
            this.DataContext = sample;
        }

I can update the multibound textblock with the Count property just fine, but the Days property always shows 0, even though the Days input accurately reflects changes. I believe that this is because my accessors are different for Days - namely, the Set method. This class is in a different file.

public class Sample : INotifyPropertyChanged
    {
        private int _count;
        private TimeSpan _span;

        public int Count 
        { 
            get { return _count; } 
            set 
            { 
                _count = value;
                NotifyPropertyChanged("Count"); /* Doesn't seem to be needed, actually */
            } 
        }

        public TimeSpan Span { get { return _span; } }

/* The idea is to provide a property for Days, Hours, Minutes, etc. as conveniences to the inputter */

        public double Days
        {
            get { return _span.Days; }
            set
            {
                TimeSpan ts = new TimeSpan();
                double val = value > 0 ? value : 0;
                ts = TimeSpan.FromDays(val);
                _span.Add(ts); /* !! This turned out to be the problem, lol - see SixLetterVariables' answer below. */
                NotifyPropertyChanged("Span"); /* Here I can only get it to work if I notify that Span has changed - doesn't seem to be aware that the value behind Days has changed. */
            }
        }

        private void NotifyPropertyChanged(string property)
        {
            if (null != this.PropertyChanged)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
        public Sample()
        {
            _count = 0;
            _span = new TimeSpan();
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
+1  A: 

Firstly TimeSpan is an immutable struct, so you'll need to store the result of any operations otherwise it effectively is a no-op. Also, you'll need to call OnPropertyChanged for both Span and Days being changed:

public double Days
{
    get { return _span.Days; }
    set
    {
        double val = value > 0 ? value : 0;

        // TimeSpan is an immutable struct, must store the result of any
        // operations on it
        _span = TimeSpan.FromDays(val);

        this.OnPropertyChanged("Days");
        this.OnPropertyChanged("Span");
    }
}

// This is preferred way for handling property changes
private event PropertyChangedEventHandler propertyChanged;
public event PropertyChangedEventHandler PropertyChanged
{
    add { this.propertyChanged += value; }
    remove { this.propertyChanged -= value; }
}

protected virtual void OnPropertyChanged(string propertyName)
{
    PropertyChangedEventHandler handler = this.propertyChanged;
    if (null != handler)
    {
        handler(this, new PropertyChangedEventArgs(propertyName));
    }
}
sixlettervariables
I thought that too, but it makes no difference.
Superstringcheese
Fixed the code, you need to save `_span`. `TimeSpan.Add` does not modify the `TimeSpan` but instead returns a new one.
sixlettervariables
You nailed it. What a nub I am. Thanks so much :)
Superstringcheese
Also, you probably just want `_span = TimeSpan.FromDays(val)`, but I'm not sure as to your intent. As the code currently stands all updates to `Days` results in adding the new value to the old value.
sixlettervariables
Yes, you're right. There would be a lot more to this, with the ability to seed fluctuations into the cycles, etc. I was simply trying to pare it down for brevity while giving a reasonable representation of the Set method; probably could have been clearer. Thanks again.
Superstringcheese