Reputation: 4045
I have a large application which has a lot of tooltips. The tooltips show a snapshot of data which is constantly changing. At the moment, I am recalcualting a snapshot of the data by polling, and then setting properties and following the INotifyPropertyChanged pattern. This works, but the result is that the user might notice that the data hasn't been refreshed if they are unlucky. Also the application wastes a lot of resources calculating snapshots of data which might never be used because the tooltip is not brought up.
This is an example app to demonstrate the point:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:WpfApplication2"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<l:ViewModel />
</Window.DataContext>
<Grid>
<Button Content="Test"
ToolTip="{Binding ElapsedTime}" />
</Grid>
</Window>
With a ViewModel of:
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
StartTime = DateTime.Now;
}
public DateTime StartTime { get; set; }
public double ElapsedTime { get { return (DateTime.Now - StartTime).TotalSeconds; } }
protected void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
So, my question is, instead of having some thread update the "ElapsedTime" property every second just in case the user needs a tooltip, is there a way in XAML to say that if the value for the binding is needed, always read it?
Upvotes: 1
Views: 123
Reputation: 2832
Better way would be having the MouseEnter
attached Behavior and update the ElapsedTime
on mouse hover.
ViewModel.cs
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
StartTime = DateTime.Now;
UpdateTime = new RelayCommand( UpdateElapsedTime, new Func<bool>(() => { return true; }));
}
public DateTime StartTime { get; set; }
private double _elapsedTime;
public double ElapsedTime
{
get { return _elapsedTime; }
set { _elapsedTime = value; RaisePropertyChanged("ElapsedTime"); }
}
public ICommand UpdateTime { get; set; }
private void UpdateElapsedTime()
{
ElapsedTime = (DateTime.Now - StartTime).TotalSeconds;
}
protected void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
MouseEnterBehavior.cs
public static class MouseEnterBehavior
{
public static readonly DependencyProperty MouseEnterProperty =
DependencyProperty.RegisterAttached("MouseEnter",
typeof(ICommand),
typeof(MouseEnterBehavior),
new PropertyMetadata(null, MouseEnterChanged));
public static ICommand GetMouseEnter(DependencyObject obj)
{
return (ICommand)obj.GetValue(MouseEnterProperty);
}
public static void SetMouseEnter(DependencyObject obj, ICommand value)
{
obj.SetValue(MouseEnterProperty, value);
}
private static void MouseEnterChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
UIElement uiElement = obj as UIElement;
if (uiElement != null)
uiElement.MouseEnter += new MouseEventHandler(uiElement_MouseEnter);
}
static void uiElement_MouseEnter(object sender, MouseEventArgs e)
{
UIElement uiElement = sender as UIElement;
if (uiElement != null)
{
ICommand command = GetMouseEnter(uiElement);
command.Execute(uiElement);
}
}
}
xaml
<Button Content="Test"
ToolTip="{Binding ElapsedTime}" local:MouseEnterBehavior.MouseEnter ="{Binding UpdateTime}"/>
Reference for MouseEnterBehavior: How can I execute a command binding on MouseEnter of a StackPanel in WPF?
Upvotes: 1
Reputation: 9827
Fire an event indicating change.
Handle this event to reset your DataContext
like,
SomeControl.DataContext = null;
SomeControl.DataContext = oldObject; // re-assign your object again
Upvotes: 0