2010-10-18 4 views
1

У меня есть одно свойство зависимостей, которое привязано к текстовому блоку. В зависимости от свойства зависимости, если значение изменяется, оно будет отражать значение в текстовом блоке. Данные в собственности поступают с устройства реального времени. Теперь всякий раз, когда будут поступать какие-либо данные, он распространяется на свойство зависимости и доходит до текстового блока. Но теперь у меня возникает вопрос, что клиент хочет, чтобы, если одно и то же значение приходит 5 раз, измените цвет фона в текстовом поле.Проблема с зависимым свойством

Но я не могу получить уведомление об изменении. В этот момент нам очень сложно изменить дизайн.

Можете ли вы, пожалуйста, предложить мне некоторое обходное решение и способ получить все уведомления, либо значение такое же или другое через свойство зависимости?

+0

Можете ли вы поделиться кодом, по которому вы говорите? – Ragepotato

ответ

0

Я не уверен, что вы собираетесь делать, но похоже, что вы хотите отслеживать, как «свежие» или «устаревшие» значения, исходящие из фида. Если это так, INotifyPropertyChanged (сила за Свойства зависимостей), вероятно, не сделает вас счастливыми, так как это будет полностью зависеть от реализации этого интерфейса в отношении того, будет ли вам сказано, будет ли SAMPLE IS TAKEN против или нет ОБРАЗЕЦ ИЗМЕНЕН (они не та же концепция).

В зависимости от того, сколько у вас контроля над этим, я бы рекомендовал реализации «Устаревшие» отслеживания внутри ViewModel (вы используете MVVM, верно?)

Что-то вроде:

Model.cs :

using System; 
using System.Windows.Threading; 

namespace WpfApplication1 
{ 
    public class Model 
    { 
    private readonly double[] _data = new[] { 2.3, 2.4, 2.5, 2.4, 2.1, 2.1, 2.1, 2.1, 2.0, 2.1, 2.0, 2.1, 2.2, 2.2, 2.2, 2.2, 2.2, 2.4 }; 
    private readonly DispatcherTimer _timer = new DispatcherTimer(); 
    private int _nextSample; 


    public Model() 
    { 
     _timer.Interval = new TimeSpan(0, 0, 0, 1); 
     _timer.Tick += _timer_Tick; 
     _timer.Start(); 
    } 

    public event EventHandler<SampleTakenEventArgs> SampleTaken; 

    private void _timer_Tick(object sender, EventArgs e) 
    { 
     if (SampleTaken != null) 
     { 
     SampleTaken(this, new SampleTakenEventArgs { SampleValue = _data[_nextSample] }); 
     } 
     _nextSample = (++_nextSample%_data.Length); 
    } 
    } 
} 

View.xaml:

<Window x:Class="WpfApplication1.View" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <StackPanel> 
     <TextBlock Text="{Binding Sample}"/> 
     <TextBlock Text="{Binding StaleCount}"/> 
    </StackPanel> 
</Window> 

View.xaml.cs:

using System.Windows; 

namespace WpfApplication1 
{ 
    public partial class View : Window 
    { 
    public View() 
    { 
     InitializeComponent(); 
     DataContext = new ViewModel(); 
    } 
    } 
} 

ViewModel.cs:

using System.ComponentModel; 

namespace WpfApplication1 
{ 
    public class ViewModel : INotifyPropertyChanged 
    { 
    private readonly Model _model; 
    private double _sample; 
    private int _staleCount; 

    public ViewModel() 
    { 
     _model = new Model(); 
     _model.SampleTaken += _model_SampleTaken; 
    } 

    public double Sample 
    { 
     get { return _sample; } 
     set 
     { 
     _sample = value; 
     OnPropertyChanged("Sample"); 
     } 
    } 

    public int StaleCount 
    { 
     get { return _staleCount; } 
     set 
     { 
     _staleCount = value; 
     OnPropertyChanged("StaleCount"); 
     } 
    } 

    #region INotifyPropertyChanged Members 

    public event PropertyChangedEventHandler PropertyChanged; 

    #endregion 

    private void _model_SampleTaken(object sender, SampleTakenEventArgs e) 
    { 
     if (e.SampleValue == Sample) 
     { 
     StaleCount++; 
     } 
     else 
     { 
     StaleCount = 0; 
     } 
     Sample = e.SampleValue; 
    } 

    protected void OnPropertyChanged(string propertyName) 
    { 
     var propertyChanged = PropertyChanged; 
     if (propertyChanged != null) 
     { 
     propertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
    } 
} 
0

ВНИМАНИЕ: Это хак основан на поставленный выше вопрос, это не идеальный дизайн, но должен достичь цели ОП.

Вы могли скользить в текущем связывания с IMultiValueConverter и сделать что-то подобное в XAML ...

<TextBlock Name="TextBlock"> 
    <TextBlock.Background> 
     <MultiBinding Converter="{StaticResource MyConverter}"> 
      <Binding Path="ViewModelProperty"></Binding> 
      <Binding ElementName="TextBlock"></Binding> 
     </MultiBinding> 
    </TextBlock.Background> 
    <TextBlock.Text> 
     <MultiBinding Converter="{StaticResource MyConverter}"> 
      <Binding Path="ViewModelProperty"></Binding> 
      <Binding ElementName="TextBlock"></Binding> 
     </MultiBinding> 
    </TextBlock.Text> 
</TextBlock> 

Затем в IMultiValueConverter образец будет ...

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
{ 
    String text = (String)values[0]; 
    TextBlock reference = (TextBlock)values[1]; 

    if (targetType == typeof(String)) 
     return text; 
    else if (targetType == typeof(Brush)) 
    { 
     int count = 0; 
     if (reference.Tag == null) 
      reference.Tag = count; 

     count = (int)reference.Tag; 
     if (++count == 5) 
      return Brushes.Red; 
     else 
      return Brushes.White; 
    } 
    else 
     throw new NotSupportedException(); 
} 

То, что я делаю, заключается в использовании вашего существующего свойства и, по сути, его перегрузке, что позволяет привязать свойство TextBlock.Background к тому же свойству, которое уже существует на вашем ViewModel. Обратите внимание на использование передачи TextBlock экземпляра в MultiBinding.

Предостережение с этим состоит в том, что если ваш дизайн перемещается по экземплярам, ​​счет будет неправильным, и все решение будет ошибочным ... нет идеи ... недостаточно информации в исходном вопросе. Опять же это взломать, есть намного лучшие способы сделать это, если у вас есть больше возможностей для внесения изменений.

+0

Ваш код не работает. Если вы вернете кисть из вашего конвертера, вы установите текст текстового поля на кисть, а затем отобразите 'System.Drawing.SolidColorbrush' в качестве .ToString() кисти. * Определенно * не оригинальное требование. –

+0

@Dan targetType проверяется ... если это String, который будет свойством TextBox.Text, он немедленно вернет текст, если targetType - это Brush, который будет другим связыванием, он вернет Brush ... –

+0

И * возврат * кисть установила бы текст элемента управления TextBox как кисть. Я подозреваю, что вы намерены установить фон элемента управления текстовыми полями на кисть, а затем вернуть исходную строку из конвертера, но в любом случае это довольно хакерское использование конвертера. –

0

Можете ли вы изменить реализацию DependencyProperty?Скорее всего, вы можете реализовать его как свойство, используя INotifyPropertyChanged, и если вы можете это сделать, вы сможете реализовать логику счетчика, в которой вы нуждаетесь.

обратный вызов из DependencyProperty не срабатывает, когда значение не меняется, так что если вы не можете изменить реализацию, что тогда вам необходимо подключить код в другом месте ...

+0

Любая причина была отклонена? –

0

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

поэтому у меня есть один способ его разрешения использовать обратный вызов coerce в метаданных свойств вместо события propertychage.

, который разрешил мою проблему. теперь я делаю это для моего единственного элемента управления, где мне нужна эта функциональность, и теперь я тоже могу получить постоянную ценность.

еще раз спасибо