poco
poco

Reputation: 2995

wpf MVVM confusion

I have been looking at MVVM for the last couple days and thought i would try out a simple example to update a text box with a time. However i'm having a bit of trouble wrapping my head around this. I have a two projects in my Solution.. one i'm calling TimeProvider that right now is just returning Datetime event and another that is called E. Eventually i will use TimeProvider to provide a lot more information but i want to understand something simple first. Can some one please tell me why i'm not geting the gui to update.

namespace E.TimeProvider
{
    public interface ITimeSource
    {
        void Subscribe();

        event Action<Time> TimeArrived;
    }
}
namespace E.TimeProvider
{
    public class Time
    {
        private DateTime _earthDate;

        public Time()
        {

        }

        public Time(DateTime earthDate)
        {
            this._earthDate = earthDate;
        }

        public DateTime EarthDate
        {
            get { return _earthDate; }
            set { _earthDate = value; }
        }
    }
}

namespace E.TimeProvider
{
    public class TimeSource : ITimeSource
    {
        private const int TIMER_INTERVAL = 50;

        public event Action<Time> TimeArrived;

        private bool subscribe;

        public TimeSource()
        {
            subscribe = false;
            Thread timeGenerator = new Thread(new ThreadStart(GenerateTimes));
            timeGenerator.IsBackground = true;
            timeGenerator.Priority = ThreadPriority.Normal;
            timeGenerator.Start();
        }

        public void Subscribe()
        {
            if (subscribe)
                return;

            subscribe = true;
        }

        private void GenerateTimes()
        {
            while (true)
            {
                GenerateAndPublishTimes();
                Thread.Sleep(TIMER_INTERVAL);
            }
        }

        private void GenerateAndPublishTimes()
        {
            DateTime earthDate = DateTime.Now;
            Time time = new Time(earthDate);
            TimeArrived(time);
        }
    }
}

Then i have my project E xaml

<Window x:Class="E.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="300" Width="200" xmlns:my="clr-namespace:Exiled" WindowStyle="None" WindowStartupLocation="CenterScreen" ResizeMode="NoResize">
    <Grid>
        <my:TimeControl HorizontalAlignment="Left" x:Name="timeControl1" VerticalAlignment="Top" Height="300" Width="200" />
    </Grid>
</Window>

<UserControl x:Class="E.TimeControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="200" Background="Black" Foreground="White">
    <Grid>
        <TextBlock Height="41" HorizontalAlignment="Left" Margin="12,31,0,0"  Text="{Binding Path=EarthTime}"  VerticalAlignment="Top" Width="176" FontSize="35" TextAlignment="Center" />
    </Grid>
</UserControl>

and the rest

namespace E
{
    public class TimeControlViewModel : DependencyObject
    {
        private readonly ITimeSource _source;


        public ObservableCollection<TimeViewModel> Times { get; set; }

        public TimeControlViewModel()
        {
            this.Times = new ObservableCollection<TimeViewModel>();
        }

        public TimeControlViewModel(ITimeSource source)
        {
            this.Times = new ObservableCollection<TimeViewModel>();

            _source = source;
            _source.TimeArrived += new Action<Time>(_source_TimeArrived); 
        }

        public void Subscribe()
        {
            _source.Subscribe();
        }

        void _source_TimeArrived(Time time)
        {
            TimeViewModel tvm = new TimeViewModel();
            tvm.Time = time;
        }   
    }
}

namespace E
{
    class SubscribeCommand
    {
        private readonly TimeControlViewModel _vm;

        public SubscribeCommand(TimeControlViewModel vm)
        {
            _vm = vm;
        }

        public void Execute(object parameter)
        {
            _vm.Subscribe();
        }
    }
}

namespace E
{
    public class TimeViewModel : DependencyObject
    {
        public TimeViewModel()
        {

        }

        public Time Time
        {
            set
            {
                this.EarthDate = value.EarthDate;
            }
        }

        public DateTime EarthDate
        {
            get { return (DateTime)GetValue(DateProperty); }
            set { SetValue(DateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Date.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DateProperty =
            DependencyProperty.Register("EarthDate", typeof(DateTime), typeof(TimeViewModel), new UIPropertyMetadata(DateTime.Now));
    }
}

Upvotes: 3

Views: 274

Answers (2)

Chris Wenham
Chris Wenham

Reputation: 24017

For a start it looks like you're binding to EarthTime:

Text="{Binding Path=EarthTime}"

but the property itself is called EarthDate

public DateTime EarthDate

Upvotes: 0

Reed Copsey
Reed Copsey

Reputation: 564323

You've got a few issues here:

  1. You're not seeing an update, because the DataContext of your Window or UserControl is not set to the TimeViewModel instance you create.
  2. Typically, ViewModel instances should not be DependencyObjects. Instead, implement INotifyPropertyChanged. This keeps them from having a dependency on WPF, but still allows them to work properly with MVVM.

I'd recommend reading through a detailed introduction to MVVM, such as the one I wrote here. In particular, you'll need to understand how templating works and the DataContext in order to use binding properly.

Upvotes: 2

Related Questions