Reputation: 4107
I have 2 controls that both bind to the same dependency property "Weather". In the first control you put the current weather, the other one displays a forecast.
In my XAML of the first control I bind a TextBox that contains the "Humidity" as follows.
<TextBox Text="{Binding Weather.Humidity}" />
Whenever the Humidity changes, I want the other control to do something, however changing only Humidity does not change the Weather - so the other control it not notified. Changing the Humidity should change the entire forecast.
(I'm not actually writing a weather app., but just using the above as an example)
My question: what is the proper way to do this? The only way I can think of is setting a SourceUpdated event handler on the TextBox that touches the Weather property. Is there a more elegant way to do this?
Thanks
Upvotes: 0
Views: 460
Reputation: 11198
A simple binding scenario will be something like this:
This might help:
<Window x:Class="BindingSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
WindowStartupLocation="CenterScreen"
Title="BindingDemo" Height="300" Width="300">
<Grid>
<StackPanel Margin="20">
<Slider Name="fontSizeSlider" Minimum="0"
Maximum="100" Value="{Binding Path=Weather.Humidity, Mode=TwoWay}"/>
<Label Content="Enter Humidity (between 0 to 100)" />
<TextBox x:Name="_humidity"
Text="{Binding Path=Weather.Humidity,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
/>
<TextBlock Text=" "/>
<Label Content="Forecast: " />
<TextBlock
Text="{Binding Path=Weather.Forecast}"
Foreground="Blue"
FontSize="{Binding ElementName=_humidity,Path=Text}" />
</StackPanel>
</Grid>
</Window>
And the Weather class can be something as follows:
public class DummyViewModel
{
public Weather Weather { get; set; }
public DummyViewModel()
{
this.Weather = new Weather();
}
public DummyViewModel(int humidity):this()
{
this.Weather.Humidity = humidity;
}
}
public class Weather : INotifyPropertyChanged
{
#region - Fields -
private string _forecast;
private decimal _humidity;
#endregion // Fields
#region - Constructor -
#endregion // Constructor
#region - Properties -
public string Forecast
{
get { return _forecast; }
set
{
if (value == _forecast)
return;
_forecast = value;
this.OnPropertyChanged("Forecast");
}
}
public decimal Humidity
{
get { return _humidity; }
set
{
if (value == _humidity)
return;
_humidity = value;
this.OnPropertyChanged("Humidity");
UpdateForeCast();
}
}
#endregion // Properties
#region - Private Methods -
private void UpdateForeCast()
{
if (this.Humidity < 0 || this.Humidity > 100)
this.Forecast = "Unknown";
else if (this.Humidity >= 70)
this.Forecast = "High";
else if (this.Humidity < 40)
this.Forecast = "Low";
else
this.Forecast = "Average";
}
#endregion
#region INotifyPropertyChanged Members
/// <summary>
/// Raised when a property on this object has a new value.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raises this object's PropertyChanged event.
/// </summary>
/// <param name="propertyName">The property that has a new value.</param>
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
#endregion // INotifyPropertyChanged Members
}
Then you can this:
public Window1()
{
InitializeComponent();
this.DataContext = new DummyViewModel(40);
}
Or M-V-VM style
Window1 view = new Window1();
view.DataContext new DummyViewModel(40);
view.Show();
Upvotes: 0
Reputation: 26
I assume that the reason why you want the other control to do something is because humidity affects some other property of the weather/forecast. In this case, you implement INotifyPropertyChanged, as in rmoore's answer, and you make sure that when humidity is modified, it either explicitly changes the other property, triggering its notification update, or it sends a notification for its update, like this:
private int myHumidity;
public int Humidity
{
get
{
return this.myHumidity;
}
set
{
this.myHumidity = value;
NotifyPropertyChanged("Humidity");
NotifyPropertyChanged("MyOtherProperty");
}
}
Upvotes: 1
Reputation: 15393
The default value for the UpdateSourceTrigger property on a TextBox binding is 'LostFocus' one thing you should do is change this to PropertyChanged, then the Humidity property will reflect any changes as you enter them in the TextBox.
Next, you want to make sure that your Weather Class implements INotifyPropertyChanged, like so:
public class Weather : INotifyPropertyChanged
{
private int myHumidity;
public int Humidity
{
get
{
return this.myHumidity;
}
set
{
this.myHumidity = value;
NotifyPropertyChanged("Humidity");
}
}
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
This will ensure that the UI is notified of any changes to the Humidity property.
Upvotes: 1