horizontal line on wpftoolkit chart - c#-4.0

I'm using the WPF toolkit to create a line graph.
Here's what I'm doing:
<Window x:Class="TempDataAnalyzer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit" Loaded="Window_Loaded">
<Grid>
<chartingToolkit:Chart Name="lineChart" Title="Temperature" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<chartingToolkit:LineSeries DependentValuePath="Value" IndependentValuePath="Key" ItemsSource="{Binding}" IsSelectionEnabled="True"/>
</chartingToolkit:Chart>
</Grid>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
List<KeyValuePair<int, int>> entries = new List<KeyValuePair<int, int>>();
entries.Add(new KeyValuePair<int, int>(0, 0));
entries.Add(new KeyValuePair<int, int>(1, 23));
entries.Add(new KeyValuePair<int, int>(2, 45));
entries.Add(new KeyValuePair<int, int>(3, 46));
entries.Add(new KeyValuePair<int, int>(4, 71));
lineChart.DataContext = entries;
}
}
this question was already asked, but i didnt understand the answer, could some one please provide me with an example

Related

WPF TreeView in ControlTemplate - Handling Item Expanded

I am creating a Custom Control and in the control template I have a TreeView class in it.
<Style TargetType="{x:Type local:MyControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyControl}">
<Border>
<TreeView ItemsSource="{Binding TreeDataItems, RelativeSource={RelativeSource TemplatedParent}}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TreeViewItem.Expanded">
<i:InvokeCommandAction Command="{Binding TreeItemExpandedCommand, RelativeSource={RelativeSource TemplatedParent}}"
CommandParameter="{Binding}">
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
In the code file for the custom control I have this command:
private ICommand _TreeItemExpandedCommand;
public ICommand TreeItemExpandedCommand
{
get
{
if (_TreeItemExpandedCommand == null)
_TreeItemExpandedCommand = new RelayCommand(p => TreeItemExpandedExecuted(p));
return _TreeItemExpandedCommand;
}
}
private void TreeItemExpandedExecuted(object args)
{
}
I have also tried
<TreeView TreeViewItem.Expanded="TreeViewItem_Expanded">
...
</TreeView/>
but neither gets fired.
How can I handle the TreeView's Expanded event INSIDE my custom control's code file?
Thanks
I am not pro Wpf programmer, but i manage to figure out the solution for your problem. The problem with your code, is that the event is not exactly belongs to TreeView itself, but rather the elements inside it (Items property).
So this wont work:
...
<i:EventTrigger EventName="TreeViewItem.Expanded">
...
On the other hand, this would work:
...
<i:EventTrigger EventName="SelectedItemChanged">
...
because this event belongs to TreeView
Basicly, what you need to do is subscribe for the Expanded event of all the TreeViewItems in the TreeView. You can do this from code behind.
Here is how i did it:
public class MyCustomControl : Control
{
public TreeView MyTreeView { get; set; }
public static readonly DependencyProperty TreeViewItemListProperty = DependencyProperty.Register("TreeViewItemList",
typeof(List<StorageItem>),
typeof(MyCustomControl),
new UIPropertyMetadata(null));
public List<StorageItem> TreeViewItemList
{
get { return (List<StorageItem>)GetValue(TreeViewItemListProperty); }
set { SetValue(TreeViewItemListProperty, value);}
}
public static readonly RoutedEvent MyEventRoutedEvent = EventManager.RegisterRoutedEvent("MyEvent",
RoutingStrategy.Bubble,
typeof(EventHandler<RoutedEventArgs>),
typeof(MyCustomControl));
public event RoutedEventHandler MyEvent
{
add { this.AddHandler(MyEventRoutedEvent, value); }
remove { this.RemoveHandler(MyEventRoutedEvent, value); }
}
public override void OnApplyTemplate()
{
MyTreeView = Template.FindName("MyTreeView", this) as TreeView;
MyTreeView.Items.CurrentChanged += Items_CurrentChanged;
base.OnApplyTemplate();
}
private void Items_CurrentChanged(object sender, EventArgs e)
{
SubscribeAllTreeViewItems(MyTreeView);
}
private void SubscribeAllTreeViewItems(ItemsControl treeViewItem)
{
foreach (object item in treeViewItem.Items)
{
TreeViewItem treeItem = treeViewItem.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
if (treeItem != null)
{
SubscribeAllTreeViewItems(treeItem);
treeItem.Expanded += TreeViewItem_Expanded;
}
}
}
private void TreeViewItem_Expanded(object sender, RoutedEventArgs e)
{
RoutedEventArgs args = new RoutedEventArgs(MyEventRoutedEvent, this);
this.RaiseEvent(args);
}
static MyCustomControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), new FrameworkPropertyMetadata(typeof(MyCustomControl)));
}
}
First we need to acquire our TreeView Control and subscribe the event if it gets items:
public override void OnApplyTemplate()
{
MyTreeView = Template.FindName("MyTreeView", this) as TreeView;
MyTreeView.Items.CurrentChanged += Items_CurrentChanged;
base.OnApplyTemplate();
}
Then, if this is fired, we know that our TreeView has Items in it, so we can cycle through its elements and subscribe for the event Expanded:
private void Items_CurrentChanged(object sender, EventArgs e)
{
SubscribeAllTreeViewItems(MyTreeView);
}
private void SubscribeAllTreeViewItems(ItemsControl treeViewItem)
{
foreach (object item in treeViewItem.Items)
{
TreeViewItem treeItem = treeViewItem.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
if (treeItem != null)
{
SubscribeAllTreeViewItems(treeItem);
treeItem.Expanded += TreeViewItem_Expanded;
}
}
}
After that, we are good to go! I also added code for to be able to subscribe for this event from outside the custom control:
public static readonly RoutedEvent MyEventRoutedEvent = EventManager.RegisterRoutedEvent("MyEvent",
RoutingStrategy.Bubble,
typeof(EventHandler<RoutedEventArgs>),
typeof(MyCustomControl));
public event RoutedEventHandler MyEvent
{
add { this.AddHandler(MyEventRoutedEvent, value); }
remove { this.RemoveHandler(MyEventRoutedEvent, value); }
}
....
....
private void TreeViewItem_Expanded(object sender, RoutedEventArgs e)
{
RoutedEventArgs args = new RoutedEventArgs(MyEventRoutedEvent, this);
this.RaiseEvent(args);
}
So this way, you can subscribe it from outside like that:
<local:MyCustomControl TreeViewItemList="{Binding Path=Items}"
MyEvent="MyCustomControl_MyEvent"/>
Finally, here it is the .xaml
<Style TargetType="{x:Type local:MyCustomControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyCustomControl}">
<TreeView ItemsSource="{TemplateBinding TreeViewItemList}"
x:Name="MyTreeView">
<TreeView.Resources>
<!--Here we specify how to display a FolderItem-->
<HierarchicalDataTemplate DataType="{x:Type localviewmodels:FolderItem}"
ItemsSource="{Binding Path=Items}">
<TextBlock Text="{Binding Path=Name}"
Margin="0 0 35 0"/>
</HierarchicalDataTemplate>
<!--Here we specify how to display a FileItem-->
<DataTemplate DataType="{x:Type localviewmodels:FileItem}">
<TextBlock Text="{Binding Path=Name}"
Margin="0 0 35 0"/>
</DataTemplate>
</TreeView.Resources>
</TreeView>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
UPDATE
if you want to set TreeView items inside the custom Control, you should
subscribe the MyTreeView.Loaded event as well to catch the first time when it gets values.
i hope it helps!
If anything is not clear, feel free to ask, i am ready to help!

Adding colored outline to text

I am newer to xamarin forms and I am currently trying to add an outline to my text here. I am not quite sure how to go about it. I believe it may have something to do with a custom renderer. I have currently attempted to add a background color to the label text but id prefer it to stick more closely to the text.
Here is my main.xaml
<StackLayout>
<Grid Padding="40 "/>
<Label VerticalOptions="StartAndExpand" HorizontalOptions="CenterAndExpand" Text="Plural Buddy" TextColor="#000000" BackgroundColor="FloralWhite" FontFamily=" { StaticResource CustomFont3}" FontSize="Large" Padding="0" />
<Button VerticalOptions="StartAndExpand" HorizontalOptions="CenterAndExpand" Text="Get Started" BorderColor= "AntiqueWhite" FontFamily=" { StaticResource CustomFont3}" />
</StackLayout>
</ContentPage>
What effect do you want ? like below ?
If yes,you could use CustomRederen to achieve it.
For Android.
create custom label OutLineLabel :
public class OutLineLabel :Label
{
}
in Android project:
create a custom TextView StrokeTextView:
class StrokeTextView : TextView
{
private TextView borderText = null;
public StrokeTextView (Context context) : base(context)
{
borderText = new TextView(context);
init();
}
public StrokeTextView(Context context,IAttributeSet attrs) : base(context,attrs)
{
borderText = new TextView(context, attrs);
init();
}
public StrokeTextView(Context context, IAttributeSet attrs,int defStyle) : base(context, attrs,defStyle)
{
borderText = new TextView(context, attrs, defStyle);
init();
}
public void init()
{
TextPaint tp1 = borderText.Paint;
tp1.StrokeWidth =5; // sets the stroke width
tp1.SetStyle(Style.Stroke);
borderText.SetTextColor(Color.White); // set the stroke color
borderText.Gravity = Gravity;
}
public override ViewGroup.LayoutParams LayoutParameters { get => base.LayoutParameters; set => base.LayoutParameters = value; }
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
string tt = borderText.Text;
if (tt == null || !tt.Equals(this.Text))
{
borderText.Text = Text;
this.PostInvalidate();
}
base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
borderText.Measure(widthMeasureSpec, heightMeasureSpec);
}
protected override void OnLayout(bool changed, int left, int top, int right, int bottom)
{
base.OnLayout(changed, left, top, right, bottom);
borderText.Layout(left, top, right, bottom);
}
protected override void OnDraw(Canvas canvas)
{
borderText.Draw(canvas);
base.OnDraw(canvas);
}
}
create custom renderer MyOutLineTextView:
[assembly: ExportRenderer(typeof(OutLineLabel), typeof(MyOutLineTextView))]
namespace EntryCa.Droid
{
class MyOutLineTextView : LabelRenderer
{
Context context;
public MyOutLineTextView(Context context):base(context)
{
this.context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (Control !=null)
{
StrokeTextView strokeTextView = new StrokeTextView(context);
strokeTextView.Text = e.NewElement.Text;
strokeTextView.SetTextColor(Android.Graphics.Color.Purple);
SetNativeControl(strokeTextView);
}
}
}
}
then in page.axml:
<StackLayout BackgroundColor="Black">
<local:OutLineLabel Text="Hellow World">
</local:OutLineLabel>
</StackLayout>

Specify default ItemTemplate

I have a WPF custom Control in which I have a Listview. The control has dependancy properties for the ItemSource and ItemTemplate of the ListView. This all works fine. What I would like to do is to be able to set a default ItemTemplate so that I don't end up with object.ToString() for the Items in the Listview.
Below is the Xaml Style for my control.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:btl="clr-namespace:Btl.Controls"
mc:Ignorable="d">
<DataTemplate x:Key="DefaultListViewItem" DataType="btl:SelectableItem">
<StackPanel Orientation="Horizontal">
<CheckBox Margin="2" IsChecked="{Binding Selected}" />
<TextBlock Margin="5,2" Text="{Binding Description}" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
<Style TargetType="{x:Type btl:SelectItemsControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type btl:SelectItemsControl}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock x:Name="PART_Title" Margin="10"
Text="{Binding Path=Title,
RelativeSource={RelativeSource TemplatedParent}}"
TextWrapping="Wrap"
Visibility="Collapsed"/>
<GroupBox Grid.Row="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<GroupBox.Header>
<StackPanel Orientation="Horizontal">
<CheckBox x:Name="PART_EnabledCheck" Margin="0,5"
Content=""
IsChecked="{Binding Path=EnabledCheck, Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent}}"/>
<TextBlock x:Name="PART_GroupTitle" VerticalAlignment="Center"
Text="{Binding Path=GroupTitle,
RelativeSource={RelativeSource TemplatedParent}}"/>
</StackPanel>
</GroupBox.Header>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DockPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<ListView x:Name="PART_Items"
ItemsSource="{Binding ItemSourceList,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type btl:SelectItemsControl}}}"
ItemTemplate="{Binding ItemTemplate,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type btl:SelectItemsControl}}}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2"
>
</ListView>
</DockPanel>
<CheckBox x:Name="PART_SelectAllCheck" Grid.Row="1" Margin="11,5" Content="Select All"
IsChecked="{Binding Selected}"/>
</Grid>
</GroupBox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here is my control
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
namespace Btl.Controls
{
/// <summary>
///
/// </summary>
///
[TemplatePart(Name = "PART_Title", Type = typeof(TextBlock))]
[TemplatePart(Name = "PART_EnabledCheck", Type = typeof(CheckBox))]
[TemplatePart(Name = "PART_GroupTitle", Type = typeof(TextBlock))]
[TemplatePart(Name = "PART_Items", Type = typeof(ListView))]
[TemplatePart(Name = "PART_SelectAllCheck", Type = typeof(CheckBox))]
public class SelectItemsControl : UserControl
{
#region DependencyProperties
#region Title
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
// Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(SelectItemsControl), new PropertyMetadata(string.Empty,
OnTitleChanged
));
private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as TextBlock;
if (control != null)
if (string.IsNullOrEmpty(e.NewValue.ToString()))
{
control.Visibility = string.IsNullOrEmpty(e.NewValue.ToString()) ? Visibility.Collapsed : Visibility.Visible;
}
}
#endregion
#region HasEnabledCheck
public bool HasEnabledCheck
{
get { return (bool)GetValue(HasEnabledCheckProperty); }
set { SetValue(HasEnabledCheckProperty, value); }
}
// Using a DependencyProperty as the backing store for EnabledCheck. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HasEnabledCheckProperty =
DependencyProperty.Register("HasEnabledCheck", typeof(bool), typeof(SelectItemsControl), new UIPropertyMetadata(false));
#endregion
#region EnabledCheck
public bool EnabledCheck
{
get { return (bool)GetValue(EnabledCheckProperty); }
set { SetValue(EnabledCheckProperty, value); }
}
// Using a DependencyProperty as the backing store for EnabledCheck. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EnabledCheckProperty =
DependencyProperty.Register("EnabledCheck", typeof(bool), typeof(SelectItemsControl), new UIPropertyMetadata(true));
#endregion
#region GroupTitle
public string GroupTitle
{
get { return (string)GetValue(GroupTitleProperty); }
set { SetValue(GroupTitleProperty, value); }
}
// Using a DependencyProperty as the backing store for GroupTitle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty GroupTitleProperty =
DependencyProperty.Register("GroupTitle", typeof(string), typeof(SelectItemsControl), new UIPropertyMetadata(""));
#endregion
#region ItemSourceList
public IEnumerable<ISelectable> ItemSourceList
{
get { return (IEnumerable<ISelectable>)GetValue(ItemSourceListProperty); }
set { SetValue(ItemSourceListProperty, value); }
}
// Using a DependencyProperty as the backing store for Items. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ItemSourceListProperty =
DependencyProperty.Register("ItemSourceList", typeof(IEnumerable), typeof(SelectItemsControl));
#endregion
#region ItemTemplate
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ItemTemplateProperty =
DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(SelectItemsControl),
new UIPropertyMetadata(default(DataTemplate)));
#endregion
#region DescriptionTemplate
public DataTemplate DescriptionTemplate
{
get { return (DataTemplate)GetValue(DescriptionTemplateProperty); }
set { SetValue(DescriptionTemplateProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DescriptionTemplateProperty =
DependencyProperty.Register("DescriptionTemplate", typeof(DataTemplate), typeof(SelectItemsControl),
new UIPropertyMetadata(default(DataTemplate), OnDescriptionTemplateChanged));
private static void OnDescriptionTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
#endregion
#region ItemSelected
public bool ItemSelected
{
get { return (bool)GetValue(ItemSelectedProperty); }
set { SetValue(ItemSelectedProperty, value); }
}
// Using a DependencyProperty as the backing store for EnabledCheck. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ItemSelectedProperty =
DependencyProperty.Register("ItemSelectedCheck", typeof(bool), typeof(SelectItemsControl), new UIPropertyMetadata(false));
#endregion
#region ItemDescription
public string ItemDescription
{
get { return (string)GetValue(ItemDescriptionProperty); }
set { SetValue(ItemDescriptionProperty, value); }
}
// Using a DependencyProperty as the backing store for ItemDescription. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ItemDescriptionProperty =
DependencyProperty.Register("ItemDescription", typeof(string), typeof(SelectItemsControl), new UIPropertyMetadata(""));
#endregion
#region SelectAllCheck
public bool SelectAll
{
get { return (bool)GetValue(SelectAllProperty); }
set { SetValue(SelectAllProperty, value); }
}
// Using a DependencyProperty as the backing store for SelectAll. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectAllProperty =
DependencyProperty.Register("SelectAll", typeof(bool), typeof(SelectItemsControl), new UIPropertyMetadata(false));
#endregion
#endregion
#region Private Members
private TextBlock _partTitle;
private CheckBox _partEnabledCheck;
private TextBlock _partGroupTitle;
private ListView _partItemsListView;
private CheckBox _partSelectAllCheck;
#endregion
/// <summary>
///
/// </summary>
static SelectItemsControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(SelectItemsControl),
new FrameworkPropertyMetadata(typeof(SelectItemsControl)));
}
public SelectItemsControl()
{
Loaded += OnLoaded;
Unloaded += OnUnloaded;
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
if (ItemTemplate == null)
{
CreateDefaultItemTemplate();
}
PresentationSource presentationSource = PresentationSource.FromVisual((Visual)sender);
// Subscribe to PresentationSource's ContentRendered event
// ReSharper disable once PossibleNullReferenceException
presentationSource.ContentRendered += SelectItemsControl_ContentRendered;
}
private void SelectItemsControl_ContentRendered(object sender, EventArgs e)
{
// Don't forget to unsubscribe from the event
((PresentationSource)sender).ContentRendered -= SelectItemsControl_ContentRendered;
ListenToSelectedCheckBoxClickEvent(_partItemsListView, true);
}
private void OnUnloaded(object sender, RoutedEventArgs e)
{
ListenToSelectedCheckBoxClickEvent(_partItemsListView, false);
}
private void CreateDefaultItemTemplate()
{
DataTemplate template = new DataTemplate { DataType = typeof(ListViewItem) };
FrameworkElementFactory stackPanelFactory = new FrameworkElementFactory(typeof(StackPanel));
stackPanelFactory.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
FrameworkElementFactory selected = new FrameworkElementFactory(typeof(CheckBox));
selected.SetBinding(TextBlock.TextProperty, new Binding("Selected"));
stackPanelFactory.AppendChild(selected);
FrameworkElementFactory title = new FrameworkElementFactory(typeof(TextBlock));
title.SetBinding(TextBlock.TextProperty, new Binding("Description"));
stackPanelFactory.AppendChild(title);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
// Code to get the Template parts as instance member
_partTitle = GetTemplateChild("PART_Title") as TextBlock;
_partEnabledCheck = GetTemplateChild("PART_EnabledCheck") as CheckBox;
_partGroupTitle = GetTemplateChild("PART_GroupTitle") as TextBlock;
_partItemsListView = GetTemplateChild("PART_Items") as ListView;
//_partItemSelectedCheck = GetTemplateChild("PART_ItemSelectedCheck") as CheckBox;
_partSelectAllCheck = GetTemplateChild("PART_SelectAllCheck") as CheckBox;
if (_partTitle == null || _partEnabledCheck == null || _partGroupTitle == null || _partItemsListView == null ||
_partSelectAllCheck == null)
{
throw new NullReferenceException("Template parts not available");
}
// set visibility
_partEnabledCheck.Visibility = HasEnabledCheck ? Visibility.Visible : Visibility.Collapsed;
_partEnabledCheck.Click += PartEnabledCheckOnClick;
_partTitle.Visibility = string.IsNullOrEmpty(_partTitle.Text) ? Visibility.Collapsed : Visibility.Visible;
_partGroupTitle.Visibility = string.IsNullOrEmpty(_partGroupTitle.Text) ? Visibility.Collapsed : Visibility.Visible;
_partSelectAllCheck.Click += PartSelectAllCheckOnClick;
}
private void PartEnabledCheckOnClick(object sender, RoutedEventArgs routedEventArgs)
{
_partItemsListView.IsEnabled = EnabledCheck;
_partSelectAllCheck.IsEnabled = EnabledCheck;
}
private void ListenToSelectedCheckBoxClickEvent(DependencyObject parent, bool set)
{
foreach (CheckBox cb in VisualTreeHelpers.FindVisualChildren<CheckBox>(parent))
{
BindingExpression binding = cb.GetBindingExpression(CheckBox.IsCheckedProperty);
// ReSharper disable once PossibleNullReferenceException
if (binding.ParentBinding.Path.Path == "Selected")
{
if (set)
cb.Click += SelectedCheckBox_Click;
else
cb.Click -= SelectedCheckBox_Click;
}
}
}
private void SelectedCheckBox_Click(object sender, RoutedEventArgs e)
{
_partSelectAllCheck.IsChecked = !ItemSourceList.AsQueryable().Any(x => x.Selected == false);
}
private void PartSelectAllCheckOnClick(object sender, RoutedEventArgs routedEventArgs)
{
foreach (CheckBox cb in VisualTreeHelpers.FindVisualChildren<CheckBox>(_partItemsListView))
{
BindingExpression binding = cb.GetBindingExpression(CheckBox.IsCheckedProperty);
// ReSharper disable once PossibleNullReferenceException
if (binding.ParentBinding.Path.Path == "Selected")
{
cb.IsChecked = _partSelectAllCheck.IsChecked ?? false;
}
}
}
}
}
Could someone please post some code which shows how set - create the default template?
This turned out to be simpler than I thought. Because the ItemTemplate is bound to a dependency property I can specify the default template there. That just left the creation of the template. See below.
#region ItemTemplate
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ItemTemplateProperty =
DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(SelectItemsControl),
new UIPropertyMetadata(DefaultItemTemplate));
private static DataTemplate DefaultItemTemplate
{
get
{
// tried using a MemoryStream - StreamWriter but was getting a
// "Root element missing error", would be nice to know why.
var sb = new StringBuilder();
sb.Append("<DataTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">");
sb.Append("<StackPanel Orientation=\"Horizontal\">");
sb.Append("<CheckBox Margin=\"2\" IsChecked=\"{Binding Selected}\" />");
sb.Append("<TextBlock Margin=\"5,2\" Text=\"{Binding Description}\" VerticalAlignment=\"Center\"/>");
sb.Append("</StackPanel>");
sb.Append("</DataTemplate>");
var myByteArray = System.Text.Encoding.UTF8.GetBytes(sb.ToString());
var ms = new MemoryStream(myByteArray);
return (DataTemplate) XamlReader.Load(ms);
}
}
#endregion

Updating a ListView with Xamarin.Forms

I am having an issue with list views on in a couple of my Xamarin Forms applications. One form is within a tabbed page setup, the other is a normal content page (different apps)
I have a class like this
public class SomeClass
{
public string StringOne {get;set;}
public string StringTwo {get;set;}
public int IntOne {get;set;}
}
In my Content page, I set up an ObservableCollection and add some data in. I then tell the list that SomeClass is my ItemSource. This produces the ListView correctly on all of my devices.
The problem is that when I change one of the properties, nothing on the ListView changes (so if say I have 3 objects in the Observable and remove one, the list still says 3 - or if I change a property in my second object, the second item on the ListView doesn't change either).
I have also tried to solve the problem by using a standard List and implement INotifyChanged within the class. Again though, the ListView doesn't alter when the List changes.
I know the data has altered as if I make a change to the object, come out and go back in, the data has changed in the UI.
Am I doing something wrong or is this a bug I need to putting into Bugzilla?
It will not change if you don't bind it and implement INotifyPropertyChanged interface.
Sample Code:
public class ObservableProperty : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class SomeClass:ObservableProperty
{
string stringOne;
string stringTwo;
int intOne;
public string StringOne
{
get{return stringOne;}
set
{
stringOne = value;
OnPropertyChanged("StringOne");
}
}
public string StringTwo
{
get{ return stringTwo;}
set
{
stringTwo = value;
OnPropertyChanged("StringTwo");
}
}
public int IntOne
{
get{ return intOne;}
set
{
intOne = value;
OnPropertyChanged("IntOne");
}
}
}
public class MainVM:ObservableProperty
{
ObservableCollection<SomeClass> items;
public ObservableCollection<SomeClass> items
{
get{return items;}
set
{
items = value;
OnPropertyChanged("Items");
}
}
public MainVM()
{
Items = new ObservableCollection<SomeClass>();
Items.Add(new SomeClass(){StringOne = "123", StringTwo = "test", IntOne =12});
}
public void CallMeForChangingProperty()
{
SomeClass item = Items[0];
item.StringOne = "Test1";
}
}
public class MainView
{
public MainView()
{
this.BindingContext= new MainVM()
}
}
< ListView ItemsSource="{Binding Items}" RowHeight="120">
< ListView.ItemTemplate>
< DataTemplate>
< ViewCell>
< ViewCell.View>
< StackLayout>
< Label Text= "StringOne" />
< Label Text= "StringTwo" />
< Label Text= "IntOne" />
</ StackLayout>
</ ViewCell.View>
</ ViewCell>
</ DataTemplate>
</ ListView.ItemTemplate>
</ ListView>
Answer given by #eakgul works like a charm for me.
I'll attach here what I've implemented, maybe it could help someone.
You have to set INotifyPropertyChanged both, to the ObservableColection and to it's itens.
I have a BaseViewModel with INotifyPropertyChanged as follows:
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
protected void SetProperty<T>(ref T backingField, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals( backingField, value)) return;
backingField = value;
OnPropertyChanged(propertyName);
}
}
On my BluetoothPage.xaml, first I set bindincontext to my BluetoothPageViewModel.cs and set the ListView ItemsSource and it's binded labels:
<ContentPage.BindingContext>
<viewmodel:BluetoothPageViewModel/>
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout Padding="5,10">
<Button x:Name="Scan_Devices_Button"
Command="{Binding SearchNew_Button_Clicked}"/>
<ListView x:Name="DevicesList"
ItemsSource="{Binding BluetoothDevices}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
IsPullToRefreshEnabled="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Text="{Binding device.Device.NativeDevice.Name}"/>
<Label Grid.Column="1"
Text="{Binding device.Device.NativeDevice.Address, StringFormat='ID: {0}'}"/>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Text="{Binding device.Rssi, StringFormat='Power: {0:F2}dbm'}"/>
<Label Grid.Column="1"
Text="{Binding distance, StringFormat='Distance: {0:F2}m'}"/>
</Grid>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
Then, in my BluetoothPageViewModel.cs I extend it with the BaseViewModel and declare ItemsSource BluetoothDevices with INotifyPropertyChanged. At this moment, everytime I change an item on the ObservableCollection BluetoothDevices, the ListView will be updated. But, If I made a change on an item inside the ObservableCollection, nothing will happen!
So, you must set INotifyPropertyChanged to it's itens.
Following is my BluetoothPageViewModel, which uses a class BluetoothPageModel in the PageModel BluetoothPageModel.cs
The BluetoothPageViewModel:
public class BluetoothPageViewModel : BaseViewModel
{
public BluetoothPageViewModel()
{
SearchNew_Button_Clicked = new Command(NewDevices_Button_Clicked_Event);
Scan_Devices_Button_BgColor = "#D6D7D7";
Scan_Devices_Button_Text = "Scan nearby devices";
}
#region Declarations
public List<IDevice> iDeviceList = new List<IDevice>();
public ObservableCollection<BluetoothPageModel> _bluetoothDevices = new ObservableCollection<BluetoothPageModel>();
public BluetoothPageModel _selectedItem;
public ObservableCollection<BluetoothPageModel> BluetoothDevices
{
get { return _bluetoothDevices; }
set { SetProperty(ref _bluetoothDevices, value); }
}
public BluetoothPageModel SelectedItem
{
get { return _selectedItem; }
set { SetProperty(ref _selectedItem, value); }
}
public ICommand SearchNew_Button_Clicked { get; private set; }
#endregion
#region Functions
private void NewDevices_Button_Clicked_Event(object obj)
{
// discover some devices
if (!CrossBleAdapter.Current.IsScanning)
{
BluetoothDevices.Clear();
iDeviceList.Clear();
var scanner = CrossBleAdapter.Current.Scan().Subscribe(scanResult =>
{
if (!iDeviceList.Contains(scanResult.Device))
{
iDeviceList.Add(scanResult.Device);
Device.BeginInvokeOnMainThread(() =>
{
BluetoothDevices.Add(new BluetoothPageModel
{
device = scanResult,
distance = Math.Pow(10, ((-68 - scanResult.Rssi) / 31.1474))
});
});
}
else
{
int ind = iDeviceList.IndexOf(scanResult.Device);
Device.BeginInvokeOnMainThread(() =>
{
BluetoothDevices[ind].device = scanResult;
BluetoothDevices[ind].distance = Math.Pow(10, ((-68 - scanResult.Rssi) / 31.1474));
});
}
});
}
else
{
CrossBleAdapter.Current.StopScan(); //When you want to stop scanning
}
}
#endregion
}
Finally, to be able to update data when you change a property of the BluetoothPageModel class:
public class BluetoothPageModel:BaseViewModel
{
public IScanResult _device;
public double _distance;
public IScanResult device
{
get { return _device; }
set { SetProperty(ref _device, value); }
}
public double distance
{
get { return _distance; }
set { SetProperty(ref _distance, value); }
}
}
Thanks to eakgul answer I could get it working. Hope it can help someone else.

WPF how to see last added text line in TexBox

I would like simmulate Console text output in my WPF app
but when I add new lines in TextBox I should use scroll bar to see last added text but I want to see last added text but for firsts lines use scroll bar
<TextBox TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Auto"
Text="{Binding Path=Data, Mode=TwoWay}" />`
Use the ScrollToLine method of TextBox (and the LineCount property to know how many lines there are) after adding text in order to make sure that the just-added line is visible.
Please consider scrolling the textbox directly from code behind like this (e.g. when text changes):
private void SampleTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (SampleTextBox.LineCount != -1)
{
SampleTextBox.ScrollToLine(SampleTextBox.LineCount - 1);
}
}
Please tell me if this helps.
thanks for answers: I expected to do it from XAML but as I undestood it's only possible from code behind
so here is my implimentation now with checkbox for stop ScrollToEnd function:
public partial class MainWindow : Window
{
private bool isScrollToEnd;
Timer timer;
public double WaitTime
{
get { return waitTime / 1000; }
set { waitTime = value * 1000; }
}
private double waitTime;
public MainWindow()
{
InitializeComponent();
isScrollToEnd = true;
waitTime = 5000;
tbWaitTime.DataContext = this;
timer = new Timer(waitTime);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
}
// событие изменения текста в контроле tbConsole
private void tbConsole_TextChanged(object sender, TextChangedEventArgs e)
{
if (tbConsole.LineCount != -1 && isScrollToEnd)
{
tbConsole.ScrollToLine(tbConsole.LineCount - 1);
cbIsScrolling.IsChecked = false;
}
}
private void cbIsScrolling_Click(object sender, RoutedEventArgs e)
{
if ((bool)cbIsScrolling.IsChecked)
{
isScrollToEnd = !(bool)cbIsScrolling.IsChecked;
isScrollToEnd = false;
timer.Interval = waitTime;
timer.Start();
return;
}
isScrollToEnd = true;
timer.Stop();
cbIsScrolling.IsChecked = false;
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
timer.Stop();
isScrollToEnd = true;
}
}
and here is XAML code:
<StackPanel Grid.Column="1" Grid.Row="2" Grid.ColumnSpan="2" Grid.RowSpan="2">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,3,10,2" VerticalAlignment="Top">
<Label Content="Stop autoscrolling for:" />
<TextBox Name="tbWaitTime" Text="{Binding Path=WaitTime}"
MinWidth="25" MaxWidth="50" Margin="5,0,0,0" />
<Label Content="sec."/>
<CheckBox Name="cbIsScrolling"
HorizontalAlignment="Right" VerticalAlignment="Center"
Click="cbIsScrolling_Click" />
</StackPanel>
<TextBox Name="tbConsole"
Background="LightGoldenrodYellow" Padding="5" Height="100"
VerticalScrollBarVisibility="Auto"
TextWrapping="Wrap"
AcceptsReturn="True"
Text="{Binding Path=Data, Mode=TwoWay}" TextChanged="tbConsole_TextChanged" />
</StackPanel>

Resources