Tooltip position in Oxyplot - oxyplot

I am recently using OxyPlot to draw charts for my WPF project. I have an issue with the tooltip in a line series. The rectangle box of the tooltip is too close to the point my mouse locates. I am wondering if there is any way to modify the position of the tooltip box and make it further from the cursor. Thank a lot. For example, I would like to move the tooltip box (in the red box) to right a bit.
[Edit]
Following Anu's idea, I added the following code but seems like it not works as expected.
In the xaml.cs file, I added
<UserControl.Resources>
<popups:ScreenPointToOffSetScreenPointConverter x:Key="ScreenPointToOffSetScreenPointConverter"/>
</UserControl.Resources>
And then change my OxyPlot to
<ItemsControl ItemsSource="{Binding AmplitudeDtos}" Margin="0" Name="Amplitude" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid popups:GridUtilities.ItemsPerRow="1" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type dtoModels:SignalDto}">
<oxy:PlotView Height="Auto" Width="Auto" MinHeight="40" MinWidth="100" HorizontalContentAlignment="Stretch"
FontStyle="Normal" FontFamily="Roboto, Microsoft YaHei" FontSize="8" Model="{Binding PlotModel}" Controller="{Binding PlotController}" Padding="8" Margin="0">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding SignalLoadedCommand}" CommandParameter="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<oxy:PlotView.DefaultTrackerTemplate>
<ControlTemplate>
<oxy:TrackerControl Position="{Binding Position, Converter={StaticResource ScreenPointToOffSetScreenPointConverter}}" LineExtents="{Binding PlotModel.PlotArea}">
<oxy:TrackerControl.Content>
<TextBlock Text="{Binding}" />
</oxy:TrackerControl.Content>
</oxy:TrackerControl>
</ControlTemplate>
</oxy:PlotView.DefaultTrackerTemplate>
</oxy:PlotView>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Please note that my OxyPlot is in a DataTemplate.
ScreenPointToOffSetScreenPointConverter class is the exactly the same as in Anu's example.

A relatively simple fix for the requirement would be to modify DefaultTrackerTemplate and use a Custom Converter to change the Position.For example, You could define a ScreenPoint converter as following
public class ScreenPointToOffSetScreenPointConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is ScreenPoint screenPoint)
{
return new ScreenPoint(screenPoint.X + 50, screenPoint.Y);
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// TODO: Implement
throw new NotImplementedException();
}
}
And then in your XAML
<oxy:PlotView Model="{Binding MyModel}">
<oxy:PlotView.DefaultTrackerTemplate>
<ControlTemplate>
<oxy:TrackerControl Position="{Binding Position,Converter={StaticResource ScreenPointToOffSetScreenPointConverter}}" LineExtents="{Binding PlotModel.PlotArea}">
<TextBlock Text="{Binding}" />
</oxy:TrackerControl>
</ControlTemplate>
</oxy:PlotView.DefaultTrackerTemplate>
</oxy:PlotView>
The Converter would add an Offset to the ScreenPoint position for the Tracker. You could modify the Offset Value to the Converter if it makes sense for your application requirement.

Related

UWP Changing gridview element size programmatically

I'm trying to use XAML binding to affect the gridview datatemplate element size from a slider on my screen.
I have a gridview made of thumbnails images where the elements are defined as following:
<GridView.ItemTemplate >
<DataTemplate >
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center"
VerticalAlignment="Center"
KeyDown="IsitenterThumb"
BorderBrush="LightSeaGreen"
BorderThickness="1"
PointerWheelChanged="ctlThumbnails_PointerWheelChanged">
<Image Source="{Binding thumb}"
x:Name="thumbimg"
Visibility="Visible"
Height="{Binding ItemSize}" Width="{Binding ItemSize, ElementName=page}" Stretch="Uniform"
Tapped="ThumbnailSelected"
DoubleTapped="CloseThumbnails"
/>
<TextBlock Text="{Binding name}" Margin="5,5"
Foreground="White"
Width="{Binding ItemSize}"
/>
</StackPanel>
</DataTemplate>
And I have the following variable defined as follow:
public double ItemSize
{
get => _itemSize;
set
{
if (_itemSize != value)
{
_itemSize = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ItemSize)));
}
}
}
private double _itemSize;
public event PropertyChangedEventHandler PropertyChanged;
I would have thought that changing the value of ItemSize would have affected the gridview datatemplate. This is taken litterally from the PhotoLab sample.
Instead I get a single huge "thumbimg" per page... Any help would be greatly appreciated!
Ok... I got it finally. I'm not quite sure what I was doing wrong above, but the code below works.
I have put the DataTemplate as part of a Page.Resource, I'm not sure if this is what was causing the binding issue. However the Xaml code looks like this:
<Page.Resources>
<DataTemplate x:Key="ThumbnailsTemplate">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center"
VerticalAlignment="Center"
KeyDown="IsitenterThumb"
BorderBrush="LightSeaGreen"
BorderThickness="1"
<Image Source="{Binding thumb}"
x:Name="thumbimg"
Visibility="Visible"
Height="{Binding ItemSize, ElementName=page}" Width="{Binding ItemSize, ElementName=page}"
Stretch="Uniform"
Tapped="ThumbnailSelected"
DoubleTapped="CloseThumbnails"
/>
<TextBlock Text="{Binding name}" Margin="5,5"
Foreground="White" Width="{Binding ItemSize}"
/>
</StackPanel>
</DataTemplate>
</Page.Resources>
<GridView x:Name = "ctlThumbnails" Grid.Column="0"
BorderBrush="White" BorderThickness="2"
Grid.RowSpan="4" Grid.Row="0" Grid.ColumnSpan="3" Height ="auto" Width="auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Margin="30,30,30,30" KeyDown="IsitenterThumb"
DoubleTapped="CloseThumbnails"
ItemTemplate="{StaticResource ThumbnailsTemplate}">
</GridView>
And here is the C# code to affect the bound variable ItemSize
public event PropertyChangedEventHandler PropertyChanged;
public double ItemSize
{
get => _itemSize;
set
{
if (_itemSize != value)
{
_itemSize = value;
topcmdbarcontent.Text = "Thumb Size:" + _itemSize.ToString();
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ItemSize)));
}
}
}
private double _itemSize;
From this, when you change the value of ItemSize, through a ValueChanged event, for example, it does change the grid element size dynamically.

Set xaml object height as % of other xaml object

In a DataTemplate in my UWP app, I want to set the hight of a rectangle as a % of the hight of a image.
My code looks like this.
<DataTemplate
x:Key="FlipViewTemplate">
<Grid>
<Image
x:Name="image"
Margin="20"
Source="{Binding fullImgUrl}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Rectangle
Height="{Binding
Converter={StaticResource PercentageConverter},
ElementName=image,
Path=ActualHeight,
ConverterParameter=0.2}"
Fill="#FFEA1E1E"
VerticalAlignment="Bottom" />
</Grid>
</DataTemplate>
And my converter like this
public class PercentageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return System.Convert.ToDouble(value) *
System.Convert.ToDouble(parameter);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
My problem is that the value in the converter that should be the actualhight of the image is always 0.
You are already using a Grid, so you could simply define two rows. In the example below the Image control span both rows, i.e. the whole Grid, while the Rectangle resides in the second row only, which has 20% of the whole height.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="4*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image Grid.RowSpan="2" .../>
<Rectangle Grid.Row="1" .../>
</Grid>

Binding ObservbleCollection to Combo box in XAML - Windows phone

I tried to bind an ObservableCollection variable to a ComboBox in the XAML. The data is not binding.
XAML File
<ComboBox x:Name="cmbCity" Height="44" Width="150" Grid.Row="4"
ItemsSource="{Binding}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Margin="5" Text="{Binding lstCity}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Code behind (After navigating to another page)
protected override void OnNavigatedTo(NavigationEventArgs e)
{
UserInfo userInfo = new UserInfo();
userInfo.UserName = "Gayathri";
userInfo.Country = "India";
userInfo.State = "TN";
ObservableCollection<string> cityInfo = new ObservableCollection<string>();
cityInfo.Add("Chennai");
cityInfo.Add("Cuddalore");
cityInfo.Add("Pondicherry");
cityInfo.Add("Villupuram");
userInfo.lstCity = cityInfo;
this.DataContext = userInfo;
}
Here I am passing values in the DataContext. The data is getting bound to the textbox but not the Combobox.
Output:
You're bindings are slightly wrong.
They should be like this:
<ComboBox x:Name="cmbCity" Height="44" Width="150" Grid.Row="4"
ItemsSource="{Binding lstCity}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Margin="5" Text="{Binding}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
(I've moved the reference to lstCity)
Previously you were binding the whole DataContext to the ComboBox and then each TextBlock to the Collection of strings.
You need to bind the ItemsSource of the ComboBox to the collection and then each TextBlock should contain one of the strings.

ListBox and ApplicationBar: last element padding

I have a ListBox and ApplicationBar with Opacity=.5. I want that ListBox items are under the ApplicationBar.
Like figure:
But when I scrolled to end of list then last element of ListBox is under the ApplicationBar.
I want that last element is over ApplicationBar.
Can I add padding for a last element of the ListBox (LongListSelector)? How can solved this issue?
UPDATE
<ListBox Name="MyListBox">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<i:Interaction.Triggers>
<ec:DataTrigger Binding="{Binding RelativeSource=
{RelativeSource Self},
Converter={StaticResource IsLastItemInContainerConverter}}"
Value="True">
<ec:ChangePropertyAction PropertyName="Padding" Value="0,0,0,72"/>
</ec:DataTrigger>
</i:Interaction.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Background="Red"
Width="400"
Height="120"
Margin="15">
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
UPDATE 2
My problem can be easily solved by using LongListSelector. Just add empty ListFooterTemplate with Height = ApplicationBar height.
You can use converter to check if it's last item in listbox and in case yes, set padding to desired value via DataTrigger.
Check my answer over here for converter code. Just for sake of completeness of this answer i will post that converter code here:
public class IsLastItemInContainerConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
DependencyObject item = (DependencyObject)value;
ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);
return ic.ItemContainerGenerator.IndexFromContainer(item)
== ic.Items.Count - 1;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
and use it like this:
<ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource=
{RelativeSource Self},
Converter={StaticResource IsLastItemInContainerConverter}}"
Value="True">
<Setter Property="Padding" Value="5"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
edit: Didn't see the update to the original question. The below remains for additional detail.
This solution is for Windows Phone 8 only (although you could use the LongListSelector from the Windows Phone Toolkit if you are targeting 7.1/5).
I'd replace the ListBox with the LongListSelector from the SDK
<Grid>
<controls:LongListSelector ItemTemplate="{StaticResource Item}" ListFooterTemplate="{StaticResource Footer}" />
</Grid>
and for the templates add
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="Item">
<StackPanel Background="Red"
Width="400"
Height="120"
Margin="15">
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="Footer">
<Border Height="72" />
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
Maybe simplest solution is to customize ItemsPanel property on ListBox:
<ListBox>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Margin="0,0,0,150"/> <!-- set margin to show some 'blank' space after last item -->
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
...
</ListBox>
But be aware that by default ListBox uses VirtualizedStackPanel as ItemsPanel. If you change it to StackPanel, it may bring some performance penalty. This is solution is suitable for lists with few items.

Color Binding Not Working for Data Templates in Win8 App

I'm currently trying to add some sort of a Color Theme feature to a Win8 App I'm working at... I've though of making a binding from a vm, and everything works fine for static UI elements. But, I'm adding some notes (my model) into a DB, and they also appear on the screen into a GridView.
But in the declared DataTemplate for the GridView ItemTemplate, the Color Binding will not work at all...
My template looks like this :
<Grid Grid.Row="3" HorizontalAlignment="Left" Width="200" Height="200">
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="60"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="Lavender" Opacity="50"/>
<ScrollViewer Grid.Row="0">
<TextBlock Grid.Row="0" Text="{Binding Content}" Foreground="DodgerBlue" />
</ScrollViewer>
<Border Grid.Row="1" Background="DodgerBlue" Opacity="70"/>
<ScrollViewer Grid.Row="1">
<TextBlock Grid.Row="1" Text="{Binding Subject}" Foreground="LightBlue" />
</ScrollViewer>
<Border Grid.Row="2" Background="DodgerBlue" Opacity="70"/>
<TextBlock Grid.Row="2" Text="{Binding Importance}" Foreground="Black" FontSize="{StaticResource ComboBoxArrowThemeFontSize}" />
</Grid>
What I tried was simply instead of Foreground="DodgerBlue" to Foreground="{Binding ColorTheme}" but it had no effect, the SolidColorBrush was not acquired from vm....
Is there any workaround for this?
Many thanks in advance.
Altough I didn't really find out the actual explanation on why the below works (and I hope someone more experience, maybe could explain me), this post, seemed to have worked for me.
Not very sure, but was a matter of DataContext, so instead of trying a binding like this : Foreground={Binding ColorTheme}, I changed to this : Foreground={Binding DataContext.ColorTheme, ElementName=MyGridViewName}".
Color binding (or better: brush binding) should work just fine - in GridView.ItemTemplate scenario and elsewhere.
You haven't given enough info to pinpoint why it doesn't work in your case, but here is a small sample I've just tried out:
GridView to put in your page:
<GridView Width="600" Height="200" ItemsSource="{Binding GridItems}"
x:Name="GridViewName">
<GridView.ItemTemplate>
<DataTemplate>
<TextBlock Width="50" Height="50"
Foreground="{Binding Color}" Text="{Binding Text}" />
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
View model class bound as DataContext for your page:
public class ViewModel
{
public ViewModel()
{
GridItems = new List<GridItem>
{
new GridItem {Text = "First", Color = new SolidColorBrush(Colors.White)},
new GridItem {Text = "Second", Color = new SolidColorBrush(Colors.Yellow)},
new GridItem {Text = "Third", Color = new SolidColorBrush(Colors.Green)},
new GridItem {Text = "Fourth", Color = new SolidColorBrush(Colors.Red)},
};
}
}
GridItem class:
public class GridItem
{
public string Text { get; set; }
public Brush Color { get; set; }
}
The result:
EDIT:
I need to point out that inside data template DataContext is set to the current item of the bound collection (GridItems in my case) not to the page DataContext (ViewModel in my case).
This means that by setting {Binding Color} to a control property you're binding to GridItem.Color not to ViewModel.Color. To make the latter work you first need to access the parent DataContext using the ElementName syntax as you already suggested in your own answer: {Binding DataContext.ColorTheme, ElementName=GridViewName} - this binds to a named element on the page and allows you to access its properties, DataContext being ViewModel in this case.