0

Tried a lot of stuff, still doesn't work. Binding on the two TextBlocks don't work. Used INotifyPropertyChanged interface much like this code to no avail.

Code:

MainWindow.xaml:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ClockWatcher" xmlns:System="clr-namespace:System;assembly=mscorlib"
        x:Name="clockWatcherWindow"
        x:Class="ClockWatcher.MainWindow"
        Title="Clock Watcher" Height="554" Width="949"
    KeyDown="KeysDown" Focusable="True" Closing="SaveSession"
    DataContext="{Binding SM, RelativeSource={RelativeSource Self}}">
    <TextBlock x:Name="programStartBlock" Text="{Binding StartTime, BindsDirectlyToSource=True, FallbackValue=Binding sucks so much!!!,  StringFormat=ProgramStarted: \{0\}, TargetNullValue=This thing is null}" Padding="{DynamicResource labelPadding}" FontSize="{DynamicResource fontSize}"/>
    <TextBlock x:Name="totalTimeLabel" Text="{Binding SM.currentSession.TotalTime, StringFormat=Total Time: \{0\}}" Padding="{DynamicResource labelPadding}" FontSize="{DynamicResource fontSize}"/>
</Window>

MainWindow.xaml.cs:

public partial class MainWindow : Window
{
    private const string SESSION_FILENAME = "SessionFiles.xml";

    /// <summary>
    /// Represents, during selection mode, which TimeEntry is currently selected.
    /// </summary>

    public SessionManager SM { get; private set; }

    public MainWindow()
    {
        InitializeComponent();
        SM = new SessionManager();
        SM.newAddedCommentEvent += currentTimeEntry_newComment;
        SM.timeEntryDeletedEvent += currentTimeEntry_delete;
        SM.commentEntryDeletedEvent += entry_delete;
    }
}

SessionManager.cs:

public class SessionManager : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        [NonSerialized]
        private DateTime _dtStartTime;
        private Session current_session;
        #region Properties

        public DateTime StartTime
        {
            get
            {
                return _dtStartTime;
            }
            private set
            {
                if (_dtStartTime != value)
                {
                    _dtStartTime = value;
                    OnPropertyChanged("StartTime");
                }
            }
        }


 public Session CurrentSession
    {
        get
        {
            return current_session;
        }
        set
        {
            if (current_session != value)
            {
                OnPropertyChanged("CurrentSession");
                current_session = value;
            }
        }
    }
        #endregion

        public SessionManager()
        {
            _dtStartTime = DateTime.Now;
        }

        private void OnPropertyChanged([CallerMemberName] string member_name = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(member_name));
            }
        }
    }

Session.cs:

public class Session : INotifyPropertyChanged
    {
        private TimeSpan total_time;
        public DateTime creationDate { get; private set; }
        public event PropertyChangedEventHandler PropertyChanged;


        public TimeSpan TotalTime
        {
            get
            {
                return total_time;
            }
            set
            {
                if (total_time != value)
                {
                    OnPropertyChanged("TotalTime");
                    total_time = value;
                }
            }
        }

        public Session()
        {
            creationDate = DateTime.Now;
        }

        private void OnPropertyChanged([CallerMemberName] string member_name = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(member_name));
            }
        }
    }
Community
  • 1
  • 1
Skello
  • 333
  • 2
  • 15
  • Please tell us what does not work and what do you want to achieve so we can help you better – PSWai Dec 15 '15 at 03:56
  • You should provide more detail when you write a question on here. It will help you logically think about your problem, plus it will help users to answer your question. – Daniel Hakimi Dec 15 '15 at 03:57
  • Is "SM" defined in your MainWindow.xaml.cs? Can you post the code of the file that defines "SM"? Also, where did you implement INotifyPropertyChanged? Please post the code for that file as well, if it's not the MainWindow.xaml.cs – Rowbear Dec 15 '15 at 04:01
  • @DanielHakimi: try now. – Skello Dec 15 '15 at 04:13
  • @ParkSoonWai: try now. – Skello Dec 15 '15 at 04:13
  • currentSession in SessionManager is private – Jamaxack Dec 15 '15 at 04:22
  • Also when you set the DataContext to parent element(Your main window) you don't need write ElementName in binding the TextBlocks. – Jamaxack Dec 15 '15 at 04:25
  • @Jamaxack: Actually, there's a public property that goes with current_session, but I didn't include it here. I did all that Element Name stuff because nothing was working, and that was default text that generated from setting the binding within the properties panel. – Skello Dec 15 '15 at 04:31
  • Did you enable WPF trace setting for binding option for the Output window and check there? That can be useful many times. – Piyush Parashar Dec 15 '15 at 04:34
  • chech binding mode set to two way what will heppen? – Jamaxack Dec 15 '15 at 04:35
  • @Jamaxack: all that does is make it so I can edit from the UI, which I don't want to do. – Skello Dec 15 '15 at 04:36
  • @PiyushParashar: I have...no idea...what you're talking about, and I never touched whatever that is. Let me also say that all this was working before I decided to change SessionManager and Session from inheriting from DependencyObject. When I changed it to implement INotifyPropertyChanged, everything broke all at once. But I can't use that inheritance because I require these two classes to be serialized. – Skello Dec 15 '15 at 04:39

2 Answers2

2
  1. In first TextBlock, instead of SM.StartTime, write only StartTime.

  2. Remove ElementName from first TB.

  3. Make CurrentSession public property, Your currentSession is private now.

  4. In your SessionManager ctor, current_session = new Session();

  5. Remove DataContext from XAML, use this.DataContext = SM; in your window contructor.

  6. If you want to use DataContext in XAML,

    <Window.DataContext>
       <local:SessionManager />
    </Window.DataContext>
    
AnjumSKhan
  • 9,647
  • 1
  • 26
  • 38
  • 1. Had that originally; did nothing. 2 Had that originally; did nothing. 3 Already have that; still nothing. I also explained this to Jamaxack in previous comments. 4 Had that originally; did nothing. – Skello Dec 15 '15 at 04:50
  • I have made application exactly as your code. Your edited code doesn't reflect suggested changes. – AnjumSKhan Dec 15 '15 at 04:52
  • What I mean is I tried all that before I posted this, and those didn't work. However, upon further trial, I have found that setting the DataContext in the code-behind does work. You beat me back here on your next comment. However, it does not work for the currentsession.TotalTime. But I have to say: if that DataContext="" binding doesn't work in XAML code, then why is it in here in the first place? I have also tried this before numerous times, and one time for a grade where I did almost exactly this, and I was able to set the data context in XAML code, and it worked. Today it refuses to do so. – Skello Dec 15 '15 at 04:58
  • @SageKelly Check updated answer now. Also check your code for common silly mistakes. – AnjumSKhan Dec 15 '15 at 05:10
  • Well thank you for the "common silly mistakes" thing. That, indeed, WAS the last error. Forgot to capitalize currentsession in the binding instruction. Thanks for your patience and the help you've given me. – Skello Dec 15 '15 at 05:27
  • This is honestly the most, hands-down, frustrating thing to implement, both in Windows Forms and WPF. – Skello Dec 15 '15 at 05:28
  • Honestly, I tried those, but I still can't seem to get the hang of this. – Skello Dec 15 '15 at 06:10
0

The marked correct answer is definitely the better way to do it, but I just wanted to answer explaining more in detail why what you posted didn't work.

The issue is that when you wrote DataContext={Binding SM, RelativeSource={RelativeSource Self} in your MainWindow.xaml, the binding was evaluted before your line SM = new SessionManager(); was executed in your MainWindow.xaml.cs constructor.

You can see this in effect if you changed your getter for SM to:

public SessionManager SM
{
    get { return new SessionManager();}
}

This basically ensures that when WPF evaluates your binding, it'll get an actual object for your SM property instead of null.

Just thought perhaps this will help understanding and reduce frustration next time :). The way you asked your question, you technically needed to implement INotifyPropertyChanged on your MainWindow class, which is a big no-no.

Rowbear
  • 1,619
  • 12
  • 15
  • So I'm new to this WPF development. I have two questions. 1) Is it possible that would have worked if I had just moved SM=new SessionManager() after the InitalizeComponent() method call? 2) Why is it a big no-no to implement INotifyPropertyChanged on the MainWindow, so I don't try it on another project? – Skello Dec 15 '15 at 06:17
  • 1) It seems you already have it this way? Did you mean move the new SessionManager() call to BEFORE InitializeComponent()? If so, yes it will work because the xaml is loaded within InitializeComponent(). I just tested on my machine and verified. 2) Because with WPF, most people do some sort of MVVM design in order to separate the view (xaml + xaml.cs) from the data (viewmodel). INotifyPropertyChanged (INPC) is basically nearly always implemented by the ViewModel class. If you implement INPC in your view class, it implies that you're mixing your data with your view, which is the actual no-no :) – Rowbear Dec 15 '15 at 06:33
  • Oh and before someone jumps on my comment, some implementers of MVVM (Model View ViewModel) will argue that the implementation of INotifyPropertyChanged should be on the model; the are valid arguments for both ways. Check out http://stackoverflow.com/questions/772214/in-mvvm-should-the-viewmodel-or-model-implement-inotifypropertychanged – Rowbear Dec 15 '15 at 06:36