none
Обновление привязки в ItemContainerStyle RRS feed

  • Вопрос

  • Добрый день.

    У меня в программе есть планировщик заданий в виде ObservableCollection<Shedule>

    где Shedule - это класс

    class Shedule 
    {
      public string Name;
      public DateTime SheduleTime;
    }


    привязана эта коллекция к ListBox, у которого в ItemContainerStyle есть такой сеттер

    <Style x:Key="SheduleListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
       <Setter Property="Foreground" Value="{Binding Converter={StaticResource SheduleColorConverter}}"/>
    </Style>


    код ковертера

     [ValueConversion(typeof(Shedule), typeof(Brush))]
        public class SheduleColorConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                Shedule shedule = (Shedule)value;
                ResourceDictionary dict = new ResourceDictionary();
                dict.Source = new Uri("Styles/Brushes.xaml", UriKind.Relative);
                Brush resultBrush = (Brush)dict["SheduleBrush"];
    
                if (shedule.SheduleTime < DateTime.Now)
                    resultBrush = (Brush)dict["NotActiveShedule"];
    
                return resultBrush;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }

    Вобщем то выполняется простая проверка, истекло ли время задания и если да, то возвращается другой цвет.

    Проблема в том, что привязка эта действует один раз при создании окна с этим ListBox, а хотелось бы чтобы цвет изменялся с течением времени. 

    Думал сделать обновление привязки в новом потоке с помощью GetBindingExpression().UpdateTarget(), только не могу додуматься для какого объекта выполнять GetBindingExpression().

    Подскажите как можно добиться такого? Может я вобще не туда копаю?

    24 августа 2012 г. 7:35

Ответы

  • Способ  lstShedules.GetBindingExpression(ListBox.ItemsSourceProperty).UpdateTarget();  ничего не дал

    Решил проблему следующим образом:

    Свойство Tag у ListBox

    <ListBox Name="lstShedules"
                     Tag="{x:Static sys:DateTime.Now}"
                     ItemsSource="{Binding Source={x:Static local:Storage.shedules}}"
                     ItemContainerStyle="{StaticResource SheduleListBoxItemStyle}"/>

    Привязка в стиле через MultiValueConverter

    <Style x:Key="SheduleListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
            <Setter Property="Foreground">
                <Setter.Value>
                    <MultiBinding Converter="{StaticResource SheduleColorConverter}">
                        <Binding/>
                        <Binding Path="Tag" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}"/>
                    </MultiBinding>
                </Setter.Value>
            </Setter>
    </Style>


    Сам конвертер:

     public class SheduleColorConverter : IMultiValueConverter
        {
            public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                Shedule shedule = (Shedule)values[0];
                DateTime dt = (DateTime)values[1];
                ResourceDictionary dict = new ResourceDictionary();
                dict.Source = new Uri("Styles/Brushes.xaml", UriKind.Relative);
                Brush resultBrush = (Brush)dict["SheduleBrush"];
    
                if (shedule.SheduleTime < dt)
                        resultBrush = (Brush)dict["NotActiveDateShedule"];
    
                return resultBrush;
            }
    
            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }

    И в загрузке страницы запускаю новый поток, который меняет Tag у ListBox

    private void Page_Loaded(object sender, RoutedEventArgs e)
            {
                Thread threadUpdate = new Thread(new ThreadStart(UpdateColor));
                threadUpdate.IsBackground = true;
                threadUpdate.Start();
            }
    
            private void UpdateColor()
            {
                while (true)
                {
                    this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                        (ThreadStart)delegate()
                        {
                            lstShedules.Tag = DateTime.Now;
                        });
                    Thread.Sleep(1000);
                }
            }

    Все работает как надо

    • Помечено в качестве ответа LXGDARKEditor 24 августа 2012 г. 14:03
    24 августа 2012 г. 8:38

Все ответы

  • Проще всего реализовать у класса Shedule интерфейс INotifyPropertyChanged (http://msdn.microsoft.com/ru-ru/library/system.componentmodel.inotifypropertychanged.aspx) тогда если вы поменяете у любого экземпляра этого класса дате она автоматически пробросится наверх и контрол узнает что нужно перечитать значение
    24 августа 2012 г. 7:39
  • Так у экземпляров этого класса ничего и не меняется. Цвет нужно изменять в зависимости от текущего времени, которое как раз и изменяется.

    24 августа 2012 г. 7:56
  • тогда как вы и говорили делать GetBindingExpression().UpdateTarget() для ListBox и обновлять свойство ItemSource
    24 августа 2012 г. 8:12
  • Способ  lstShedules.GetBindingExpression(ListBox.ItemsSourceProperty).UpdateTarget();  ничего не дал

    Решил проблему следующим образом:

    Свойство Tag у ListBox

    <ListBox Name="lstShedules"
                     Tag="{x:Static sys:DateTime.Now}"
                     ItemsSource="{Binding Source={x:Static local:Storage.shedules}}"
                     ItemContainerStyle="{StaticResource SheduleListBoxItemStyle}"/>

    Привязка в стиле через MultiValueConverter

    <Style x:Key="SheduleListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
            <Setter Property="Foreground">
                <Setter.Value>
                    <MultiBinding Converter="{StaticResource SheduleColorConverter}">
                        <Binding/>
                        <Binding Path="Tag" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}"/>
                    </MultiBinding>
                </Setter.Value>
            </Setter>
    </Style>


    Сам конвертер:

     public class SheduleColorConverter : IMultiValueConverter
        {
            public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                Shedule shedule = (Shedule)values[0];
                DateTime dt = (DateTime)values[1];
                ResourceDictionary dict = new ResourceDictionary();
                dict.Source = new Uri("Styles/Brushes.xaml", UriKind.Relative);
                Brush resultBrush = (Brush)dict["SheduleBrush"];
    
                if (shedule.SheduleTime < dt)
                        resultBrush = (Brush)dict["NotActiveDateShedule"];
    
                return resultBrush;
            }
    
            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }

    И в загрузке страницы запускаю новый поток, который меняет Tag у ListBox

    private void Page_Loaded(object sender, RoutedEventArgs e)
            {
                Thread threadUpdate = new Thread(new ThreadStart(UpdateColor));
                threadUpdate.IsBackground = true;
                threadUpdate.Start();
            }
    
            private void UpdateColor()
            {
                while (true)
                {
                    this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                        (ThreadStart)delegate()
                        {
                            lstShedules.Tag = DateTime.Now;
                        });
                    Thread.Sleep(1000);
                }
            }

    Все работает как надо

    • Помечено в качестве ответа LXGDARKEditor 24 августа 2012 г. 14:03
    24 августа 2012 г. 8:38
  • Спасибо, что поделились решением проблемы. Оно пригодится тем, кто столкнется с подобной проблемой.

    Для связи [mail]

    28 августа 2012 г. 12:27