tags:

views:

46

answers:

4

I have one dependency property which is binded to Text Block, as per dependency property if value change it will reflect the value in text block, data in property is coming from real time device, now whenever any data will come it is propagated to dependency property and will reach to text block, but now I have issue that client wants that if same value comes 5 times then change the background color of text box.

But I am unable to receive the change notification, at this moment its very hard for us to change the design.

Can you guys please suggest me some workaround and way to receive all notification either value is same or different through dependency property?

Thanks

A: 

I'm not sure what you're going for, but it sounds like you want to track how "fresh" or "stale" the live value coming from the feed is. If so, INotifyPropertyChanged (the power behind Dependency Properties) is probably not going to make you happy, since it's going to depend entirely on the implementation of that interface as to whether or not you'll be told when a SAMPLE IS TAKEN vs. when the SAMPLE HAS CHANGED (they're not the same concept).

Depending on how much control you have over this, I'd recommend implementing the "Stale" tracking inside your ViewModel (you are using MVVM, right?)

Something like:

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));
      }
    }
  }
}
Wayne
A: 

WARNING: This is a hack based on the question above, this is not ideal design but should accomplish the goal of the OP.

You could slide a IMultiValueConverter in your current binding and do something like this in the 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>

Then in the IMultiValueConverter a sample would be...

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();
}

What I am doing is making use of your existing property and essentially overloading it, allowing you to bind the TextBlock.Background property to the same property which already exists on your ViewModel. Note the use of passing the TextBlock instance in the MultiBinding.

The caveat with this is that if your design is moving through instances the count will be incorrect and the entire solution will be flawed...no idea...not enough information in the initial question. Again this is a hack, there are much better ways to do this if you have more access to making changes.

Aaron
Your code doesn't work. If you return a Brush from your converter, you'll set the text of a textbox to a brush, which will then display `System.Drawing.SolidColorbrush`, as the .ToString() of the brush. *Definitely* not the original requirement.
Dan Puzey
@Dan the targetType is being checked...if it is a String, which would be the TextBox.Text property it would return the text immediately, if the targetType is the Brush, which would be the other binding it would return the Brush...
Aaron
And *returning* the brush would set the text of the TextBox control to be the brush. I suspect your intent was to set the background of the textbox control to the brush, and then return the original string from the converter - but either way this is a pretty hacky use of a converter.
Dan Puzey
Actually, you're right. The converter would never return the brush, because there's nowhere in your xaml that would ask for a target type of Brush. Unfortunately there's still no solution to the original question in your code, though...
Dan Puzey
Yes, the XAML does not have the markup to bind the Background property, that is missing...
Aaron
@Dan Added the missing XAML and yes it's a hack, that was clearly stated throughout the post...however the OP did not want changes to the design of the DP, which this will not require.
Aaron
Well, it'll work now - but you don't need to bind the text property through your converter at all. I've taken back the -1 since you've fixed it tho :-)
Dan Puzey
@Dan at least the flaw was pointed out as I had thought of but missed that piece...ty
Aaron
A: 

Can you change the implementation of the DependencyProperty? Chances are you could implement it as a property using INotifyPropertyChanged, and if you can do that you'll be able to implement the counter logic you need.

The callback from a DependencyProperty doesn't fire when the value doesn't change, so if you can't change the implementation of that then you'd need to hook code in elsewhere...

Dan Puzey
Any reason this was voted down?
Dan Puzey
A: 

thanks for response... i know this is against our ideal design... but as this is already working with our most of part, recently client changed requirment, as wants to print this values as well color also.

so i have one way to resolve it use coerce callback in property metadata instead of propertychnage event.

which has resolved my issue. now i am doing this for my single control where i need this functionality, and now i am able to receive constant value also.

thanks again

Kasma