Search code examples
c#wpfxamlui-virtualization

How to test or work with DisconnectedItem on ListView in VS2010?


I am trying to change the background of a ListViewItem from an attached property. The following code works until the ListViewItem is scrolled out of the displayed ListView. The error is that the timer fires on a ListViewItem that has been disconnected.

{System.Windows.Controls.ListViewItem: {DisconnectedItem}} System.Windows.Controls.ListViewItem

How to test for a disconnected item in visual studio 2010?

TIA

namespace Stargate_V
{
    // Using singleton pattern to create one time to be shared among all ListViewItem instances.
    public static class ListTimer
    {
        // Reasons for using a DispatcherTimer opposed to a System.Timers.Timer are that the DispatcherTimer runs on the same thread as the 
        // Dispatcher and a DispatcherPriority can be set on the DispatcherTimer. Timer runs in its own thread.
        private static readonly Timer listTimer;

        static ListTimer()
        {
            listTimer = new Timer { AutoReset = true, Enabled = true, Interval = 10 * 1000 };  // Interval in milliseconds
            listTimer.Elapsed += listTimer_Elapsed;
        }

        static void listTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (ListTimerEvent != null)
            {
                ListTimerEvent(sender, e);       
            }  
        }

        public static event EventHandler ListTimerEvent;
    }

    // Static classes can not implement an interface. (Hence : INotifyPropertyChanged can not be used).
    public static class ListViewItemBehavior 
    {

        // Hint: create this with "propa" then tab

        public static string GetMyValue(DependencyObject obj)
        {
            return (string)obj.GetValue(MyValueProperty);
        }

        public static void SetMyValue(DependencyObject obj, string value)
        {
            obj.SetValue(MyValueProperty, value);
        }

        // Using a DependencyProperty as the backing store for MyValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MyValueProperty =
            DependencyProperty.RegisterAttached("MyValue", typeof(Object), typeof(ListViewItemBehavior), new UIPropertyMetadata(null, OnMyValueChanged));

        static void OnMyValueChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs args)
        {
            var item = depObj as ListViewItem;
            if (item == null) return;

           // This is unable to pass the instance data:  ListTimer.ListTimerEvent +=new EventHandler(ListTimer_ListTimerEvent);
           // Use an anonymous method in the OnMyValueChanged to specify the timer event handler. This will give access to the specific 
           // ListViewItem.
            ListTimer.ListTimerEvent += (sender, e) =>
            {
                Timer timer = sender as Timer;

                // The Timer is running on a different thread then the ListViewItem item
                item.Dispatcher.Invoke((Action)(() =>
                {
--THIS FAILS WHEN ITEM HAS BEEN SCROLLED OUT OF VIEW AND DISCONNECTED ---
                    View_encountertime vt = item.DataContext as   View_encountertime;
                    item.Background = Brushes.Azure;

                    // convert checkin time to a  datetime.
                    var b = vt.Checkin;
                    DateTime z = (DateTime)vt.Tencounter;

                   // string sdt = DateTime.Now.ToShortDateString() + " " + values[0].ToString();
                   // DateTime checkin = DateTime.Parse(sdt);

                    // get current time.
                    // DateTime now = DateTime.Now;
                    DateTime now = new DateTime(2015, 2, 13, 11, 30, 5);
                    TimeSpan ts = now.Subtract(z);

                    if (ts.CompareTo(WaitingTime.ninetymin) < 1) item.Background = Brushes.Orange;          // orange
                    if (ts.CompareTo(WaitingTime.seventyfivemin) < 1) item.Background = Brushes.Yellow;     // yellow 
                    if (ts.CompareTo(WaitingTime.sixtymin) < 1) item.Background = Brushes.Green;            // green
                    if (ts.CompareTo(WaitingTime.fortyfivemin) < 1) item.Background = Brushes.Turquoise;    // turquose
                    if (ts.CompareTo(WaitingTime.thirtymin) < 1) item.Background = Brushes.Blue;            // blue
                    if (ts.CompareTo(WaitingTime.fifteenmin) < 1) item.Background = Brushes.Violet;         // violet


                }));


            };


        }
    }

    // Waiting times
    public static class WaitingTime
    {
        public static TimeSpan fifteenmin;
        public static TimeSpan thirtymin;
        public static TimeSpan fortyfivemin;
        public static TimeSpan sixtymin;
        public static TimeSpan seventyfivemin;
        public static TimeSpan ninetymin;

        static WaitingTime()
        {
            fifteenmin = new TimeSpan(0, 15, 0);
            thirtymin = new TimeSpan(0, 30, 0);
            fortyfivemin = new TimeSpan(0, 45, 0);
            sixtymin = new TimeSpan(0, 60, 0);
            seventyfivemin = new TimeSpan(0, 75, 0);
            ninetymin = new TimeSpan(0, 90, 0);
        }

    } // end class WaitingTime


}

Solution

  • Has nothing to do with the version of Visual Studio. Has to do with the version of .NET. In 4.5 and above, you can use BindingOperations.DisconnectedSource. Before 4.5, .NET did not expose this member, so you have to do a string compare.