WPF binding to a function?

Go To StackoverFlow.com

1

Let me start by saying I am very new to WPF so be gentle.

It seems like this should be easy but I am just missing something. I have implemented INotifyPropertyChanged on a few classes/properties and started binding them to elements in XAML but now I have a little more complex binding to make then updating text or changing a color. What I need is when the Alarm property of my object is set to true I need to change colors, start an animation, create and display other elements in the control. I thought I could just call a function in my control when the property is changed but since WPF hides how an element is "bound" to the model's property I am not sure how to wire that up. Is there a better way to perform this type of more complex response to a property change? If not are there any samples out there? I have not been able to find anything close to what I am looking for but I may not be searching with the correct terms.

2012-04-05 17:49
by mdutra


0

For complex behaviour in response to a property changed event, you should use the following approach: (I'm typing this freestyle so pardon any minor syntax errors)

class MyClass : INotifyPropertyChanged
{    
    //Presumably you've already done this part
    private object _myProperty = null;
    public object MyProperty
    {
        get { return _myProperty; }
        set
        {
            _myProperty = value;
            NotifyPropertyChanged("MyProperty");
        }
    }

    public MyClass()
    {
        this.PropertyChanged += My_PropertyChanged;
    }

    private void My_PropertyChanged( object sender, PropertyChangedEventArgs e)
    {
        if( e.PropertyName == "MyProperty" )
        {
            //Do Something complicated
        }
    }
2012-04-05 18:55
by Alain
This is what I was looking for except I added the handler somewhere other than my object model. I am not using a VM at this point. Thanks - mdutra 2012-04-05 19:40
This is really poor design and should be avoided. I find that whenever you start using PropertyChanged like this, it unravels all kinds of hell. But sure, it works - Louis Kottmann 2012-04-05 19:43
@Baboon - If your property changed event needs to trigger a non-ui action, like invoking an external thread which performs calculations on a backgroundworker, and you don't want the user to have to click a "calculate" button, I'd like to see your proposed alternative. Note: placing a method call in the property setter is not a better alternative - Alain 2012-04-05 19:45
The "alternative" is to use Commands. You can fire them on any event with the use of System.Windows.Interactivity... PropertyChanged should only be used by the binding engine, don't try to reinvent the way it works and use what they provide - Louis Kottmann 2012-04-05 20:21


1

What I need is when the Alarm property of my object is set to true I need to change colors, start an animation, create and display other elements in the control.

  • Change colors: Bind the Color/Foreground of the element you want to change the color of, to the boolean that sets the alarm, and add an IValueConverter in the binding that returns a Brush based on the boolean.
  • Start an animation: Use a (data)trigger on whichever element needs to be animated, in that trigger, use a Storyboard to define the animation you want.
  • create and display other elements in the control: that really depends on how well you did your MVVM, if the elements are a visualisation of an ObservableCollection through a ListBox/ListView/ItemsControl (which it should), wire up a Command to whatever sets the alarm on/off (the Button class has a Command property built in, other UIElements may require the use of System.Windows.Interactivity) and in the method that this Command will point to, add a new item to the ObservableCollection, the ItemsControl will automatically reflect the change by adding a new control.

Of course this is just raw information, and you're probably not familiar will all these things, that's when Google comes into play ;)

HTH,

Bab.

2012-04-05 18:46
by Louis Kottmann
I need to look into the MVVM pattern a little more. Right now I have a Viper data model and it implements INotifyPropertyChanged and I have elements bound directly to it. The control is only displaying the data, not modifying it. The possible problem with my design is that all devices pass in a Viper object containing some data and I "merge" that data into my master Viper object and the UI displays that data. If I create a VM to bind to the UI then incoming client data would need to be translated to the new object type (which is 95% the same as data model Viper) before merging them in. Right - mdutra 2012-04-05 19:47
Yes, most UI changes in response to a property can and should be arranged using bindings, converters, and triggers, but there's absolutely nothing wrong with stringing model changes off of property changed events registered in the VM - Alain 2012-04-05 19:48
Actually, there is, and if you keep on doing that, you'll start to have StackOverflowExceptions everywhere. I have been debugging apps done that way, and it's a big pain. Especially since once you started down that path, it just gets messier and messier, until you ultimately have to redo it all, which was my solution - Louis Kottmann 2012-04-05 20:25
The last item is the piece that does not fit. There is no UI element that sets the alarm. Data coming into the WPF app determines is an alarm is set. This is why I have to react to the domain model's alarm property. Once it is true I then need to go out and get the data and display it. How can I use a Command in that scenario - mdutra 2012-04-10 19:38
Either you don't use a command at all and just add logic to whatever brings data to your WPF app (i guess it doesn't just pop in your app, there's a method somewhere), or you have an event you can react to and then you can use a command - Louis Kottmann 2012-04-10 21:03
Actually it does just pop into the app. The app subscribes to a channel via WebSync so data gets pulled in randomly as it becomes available. This is why I wanted to have the PropertyChanged event on the alarm property that I could react to and use the command as you have suggested. I suppose I can put that command logic into the viewmodel? Or is there a more appropriate place to implement the command - mdutra 2012-04-11 13:30
Commands should be in a ViewModel, unless they are meant to be used globally by the app in which case they can be in a static class somewhere. and again, when WebSync pushes data in your app, they enter somewhere, it doesn't directly modify your live RAM.. - Louis Kottmann 2012-04-11 13:41


0

Your timer / alarm just needs to update the bound property when it elapses. The property should then raise the PropertyChanged event to notify the GUI to update.

2012-04-05 17:57
by ConditionRacer
I don't think I understand your statement. I already do that as I do with several other properties. The problem is I am not sure what should be binding to the Alarm property. There is a lot that needs to occur when the Alarm is triggered. Not only do several pieces of the GUI need to update (color/animation) but I also need to go to a web service and get much more data and display it. Imagine I am monitoring a house alarm and it gets triggered. I now want to query what exactly was triggered and where and then display that. It seems more complicated than binding a label text to a username prop - mdutra 2012-04-05 18:04
The get; set; is .NET can will run code - paparazzo 2012-04-05 18:11
Blam, can you please elaborate on that comment? I think I understand what you are trying to say but the get/set is in the data model and in another project altogether so I don't want it to perform GUI operations - mdutra 2012-04-05 18:28


0

You should take a look at DataTriggers that get fired when a property changes in the view model. The EnterActions and ExitActions will allow you to play a Storyboard when the value of the property changes. Here's an example of how it is used MSDN. You can use a content control and style the Template or ContentTemplate to add all of your elements and have it control the Visibility or Opacity of the other elements.

2012-04-05 18:28
by evanb


0

I don't think you are looking at this right. Your class has logic, does calculation, enforces constraints, and enforces relationships among properties. If you have an alarm hopefully there is some business logic to deal with this and should be done in the class (not the UI). A UI is not built to handle an alarm it is built to display status and actions of that alarm. You will make new control visible in an alarm situation and hide other. On the animation I think you might want to throw an event that you listen for to start the animation. The idea there is that when an alarm is thrown to can register additional handles - you want to separate the business logic from the UI (not pull the business logic into the UI).

2012-04-05 20:54
by paparazzo
That is actually my thought as well. When my alarm is triggered I need the visuals to start flashing the UI red. In addition I wan to pull additional "readings" and display them as well to indicate why the alarm is triggered. I just was not sure how to wire up some custom function to fire when the alarm property is set to true. It seems I will need both the UI and a business logic layer to be bound to the data model in this case. The business logic here is simply to fetch more data and display it and then remove it when the alarm is finished - mdutra 2012-04-10 17:29
You have the alarm raise an event and you have an event handler - paparazzo 2012-04-10 18:17
Ads