i am trying to increment a variable everytime the Hall Sensor detects the magnet but its not working . I am very new in the field windows iot c# with raspi 3.
So my code looks like:
public sealed partial class MainPage : Page
{
private int count = 5;
private const int SENSOR_PIN = 5; //SENSOR PIN
private GpioPin sensorPin;
public MainPage()
{
this.InitializeComponent();
InitGPIO();
}
private void InitGPIO()
{
var gpio = GpioController.GetDefault();
if (gpio == null)
{
GpioStatus.Text = "No Gpio Pins!";
return;
}
sensorPin = gpio.OpenPin(SENSOR_PIN);
sensorPin.SetDriveMode(GpioPinDriveMode.Input);
sensorPin.ValueChanged += sensorPin_ValueChanged;
GpioStatus.Text = "GPIO pins initialized correctly.";
}
//INTERRUPT HANDLER
private void sensorPin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs e)
{
// Increment
if (e.Edge == GpioPinEdge.FallingEdge)
{
count++;
}
}
}
}
Here is a simple test to narrow down the issue.
Connect GPIO5 and GPIO6 together like this:
Here I simulate Hall Sensor using GPIO6. Every time you click the button the GPIO6 output value will change. The following is the code sample you can test to see if the sensorPin_ValueChanged hander can be triggered or not.
public sealed partial class MainPage : Page
{
private int count = 5;
private const int SENSOR_PIN = 5; //SENSOR PIN
private GpioPin sensorPin;
private GpioPin OutputPin;
private const int OPinNum = 6;
public MainPage()
{
this.InitializeComponent();
InitGPIO();
}
private void InitGPIO()
{
var gpio = GpioController.GetDefault();
if (gpio == null)
{
GpioStatus.Text = "No Gpio Pins!";
return;
}
sensorPin = gpio.OpenPin(SENSOR_PIN);
sensorPin.SetDriveMode(GpioPinDriveMode.Input);
sensorPin.ValueChanged += sensorPin_ValueChanged;
GpioStatus.Text = "GPIO pins initialized correctly.";
OutputPin = gpio.OpenPin(OPinNum);
OutputPin.SetDriveMode(GpioPinDriveMode.Output);
}
//INTERRUPT HANDLER
private void sensorPin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs e)
{
// Increment
if (e.Edge == GpioPinEdge.FallingEdge)
{
count++;
}
}
// Simulate Hall Sensor
private void Button_Click(object sender, RoutedEventArgs e)
{
if(OutputPin.Read() == GpioPinValue.Low)
OutputPin.Write( GpioPinValue.High);
else
OutputPin.Write(GpioPinValue.Low);
}
}
XAML code:
<StackPanel VerticalAlignment="Center" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Name="GpioStatus" />
<Button Content="Change output value" Click="Button_Click"/>
</StackPanel>
Related
I have 2 entries. When I tap anything on entry 1 I would like to get "Yess" on entry 2 and when I type anything on entry 2 I would like to get "Noo"
The problem:
When I tap on entry 1, entry 2 change and get the value "Noo" but entry 1 change too and get the value "yess".
Question :
How can make entry 2 change when tapping on entry 1 without changing entry 1. And the same for entry 2
Here is Xaml code :
<Entry ClassId="1" x:Name="myWord1"TextChanged="OnEntryTextChange"/>
<Entry ClassId="2" x:Name="myWord2" TextChanged="OnEntryTextChange"/>
Code :
private async void OnEntryTextChange(object sender, TextChangedEventArgs e)
{
var EntryTapped = (Xamarin.Forms.Entry)sender;
Device.BeginInvokeOnMainThread(() => {
if (EntryTapped.ClassId == "1")
{
myWord2.Text="Noo";
}
else if (EntryTapped.ClassId == "2")
{
myWord1.Text="yess";
}
});
}
Thanks for your help
You could use the Focused event instead of TextChanged event.
<StackLayout>
<Entry ClassId="1" x:Name="myWord1" Focused="EntryFocused"/>
<Entry ClassId="2" x:Name="myWord2" Focused="EntryFocused"/>
</StackLayout>
private void EntryFocused(object sender, FocusEventArgs e)
{
var EntryTapped = (Xamarin.Forms.Entry)sender;
if (EntryTapped.ClassId == "1")
{
myWord2.Text = "Noo";
}
else if (EntryTapped.ClassId == "2")
{
myWord1.Text = "yess";
}
}
There are several ways of doing this:
Using bindings
In this case you would have 2 private variables and 2 public variables, and the entries binded to each one. Check this link how to implement INotifyPropertyChanged
private string entry1String;
private string entry2String;
public string Entry1String {
get => entry1String;
set
{
entry2String = "Noo";
entry1String = value;
OnPropertyChanged(Entry1String);
OnPropertyChanged(Entry2String);
}
}
public string Entry2String {
get => entry2String;
set
{
entry1String = "Yees";
entry2String = value;
OnPropertyChanged(Entry1String);
OnPropertyChanged(Entry2String);
}
}
Another way could be using a variable as a Semaphore. While the variable is True, the method cannot be fired at the same time by another.
private bool semaphoreFlag=false;
private async void OnEntryTextChange(object sender, TextChangedEventArgs e)
{
if(semaphoreFlag) return;
semaphoreFlag=true;
var EntryTapped = (Xamarin.Forms.Entry)sender;
Device.BeginInvokeOnMainThread(() => {
if (EntryTapped.ClassId == "1")
{
myWord2.Text="Noo";
}
else if (EntryTapped.ClassId == "2")
{
myWord1.Text="yess";
}
});
semaphoreFlag=false;
}
To simplify the example let's suppose we just add a GridView in the Page:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<GridView x:Name="MainGrid" />
</Grid>
And this is the code:
public MainPage()
{
this.InitializeComponent();
this.Loaded += MainPage_Loaded;
}
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var collection = new ObservableCollection<String>();
MainGrid.ItemsSource = collection;
await Dispatcher.RunIdleAsync(test =>
{
for (int i = 0; i < 20000; i++)
{
collection.Add(i.ToString());
}
});
}
A GridView is filled with that ObservableCollection, I do not complain about scrolling but about resizing and maximizing the Window makes a huge lag and even worse in low spec computers.
I have done the following improvements:
Play with the values of IncrementalLoadingThreshold & DataFetchSize
<GridView x:Name="MainGrid" IncrementalLoadingThreshold="100" DataFetchSize="3"/>
Sometimes goes better but not sure if this values works with an static collection.
Change the alignment to top and left to track the SizeChanged and adapt to the Grid.
This goes better but when I tap on maximize it has a large lag.
I have also tried to follow old examples like http://xurxodeveloper.blogspot.com.es/2014/03/scroll-infinito-en-windows-81-con-xaml.html but it does not add more items when scroll has arrived to the end. And the performance tips and articles I found are just for scrolling.
So In this static case, is there a technique or another collection source to improve the resizing lag?
Firstly create a new Observable Collection that allows you to AddRange. Here's what I have
public class ObservableCollection2<T> : ObservableCollection<T>
{
bool _suppressNotification = false;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (!_suppressNotification)
base.OnCollectionChanged(e);
// do nothing
}
public ObservableCollection2() : base() { }
public ObservableCollection2(IEnumerable<T> collection) : base(collection)
{ }
public void AddRange(IEnumerable<T> list)
{
this._suppressNotification = true;
if (list == null)
throw new ArgumentNullException("list");
int index = this.Count;
foreach (T item in list)
{
base.Items.Add(item);
}
this._suppressNotification = false;
OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs("Count"));
OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs("Items[]"));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, list.ToList(), index));
}
}
Next you don't instantiate the collection on Loaded rather do it in constructor
public MainPage()
{
this.InitializeComponent();
dataCol = new ObservableCollection2<String>();
}
ObservableCollection2<String> dataCol = null;
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
MainGrid.ItemsSource = dataCol;
List<stirng> tempList = new List<string>();
for (int i = 0; i < 20000; i++)
{
tempList .Add(i.ToString());
}
dataCol.AddRange(tempList);
}
In short you aren't triggering UI updates after every insert only when the collection has finished processing.. that means GridView gets update notification once rather than 2000 times
I have a binding of the following form in XAML,
Title="{Binding SelectedNewsItems[0].Title}"
Note that it refers to a particular element in the SelectedNewsItems which is an ObservableCollection. (I have a collection of nine buttons of various sizes, each styled, and sized differently and so a more standard ListView is not appropriate.)
When I reassign SelectedNewsItems I raise a PropertyChanged event for SelectedNewsItems, however, this does not appear to cause the bindings to update for the individual bound elements and their properties. I have tried the following,
public ObservableCollection<NewsItem> _selectedNewsItems;
public ObservableCollection<NewsItem> SelectedNewsItems
{
get
{
return this._selectedNewsItems;
}
set
{
if (this._selectedNewsItems != value)
{
this._selectedNewsItems = value;
this.NotifyPropertyChanged();
for (int i = 0; i < this._selectedNewsItems.Count; i++)
{
this.NotifyPropertyChanged(String.Format("SelectedNewsItems[{0}].Content", i));
this.NotifyPropertyChanged(String.Format("SelectedNewsItems[{0}].Title", i));
this.NotifyPropertyChanged(String.Format("SelectedNewsItems[{0}].Id", i));
this.NotifyPropertyChanged(String.Format("SelectedNewsItems[{0}].Image", i));
}
}
}
}
Hmm, I cannot exacly say where your code is wrong (as I see only part of it), but maybe you haven't set your DataContex or something else. For the purpose of research I've made simple example, which works quite fine. Take a look at it and maybe it will help you:
In Xaml:
<Button x:Name="first" VerticalAlignment="Top" Content="{Binding SelectedNewsItems[0].Name}" Grid.Row="0"/>
<Button x:Name="second" VerticalAlignment="Center" Content="{Binding SelectedNewsItems[1].Name}" Grid.Row="1"/>
In code behind (I put all the code - yeah quite a lot of, but I cannot guess what is wrong with your code):
public class NewsItem
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
public partial class MainPage : PhoneApplicationPage, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaiseProperty(string property = null)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(property));
}
private ObservableCollection<NewsItem> _selectedNewsItems = new ObservableCollection<NewsItem>();
public ObservableCollection<NewsItem> SelectedNewsItems
{
get
{
return this._selectedNewsItems;
}
set
{
if (this._selectedNewsItems != value)
{
this._selectedNewsItems = value;
this.RaiseProperty();
for (int i = 0; i < this._selectedNewsItems.Count; i++)
{
this.RaiseProperty(String.Format("SelectedNewsItems[{0}].Name", i));
}
}
}
}
public MainPage()
{
NewsItem firstT = new NewsItem() { Name = "First" };
NewsItem secondT = new NewsItem() { Name = "Second" };
SelectedNewsItems.Add(firstT);
SelectedNewsItems.Add(secondT);
InitializeComponent();
this.DataContext = this;
first.Click += first_Click;
second.Click += second_Click;
}
private void first_Click(object sender, RoutedEventArgs e)
{
NewsItem change = new NewsItem() { Name = "Changed by First" };
SelectedNewsItems[1] = change;
}
private void second_Click(object sender, RoutedEventArgs e)
{
NewsItem change = new NewsItem() { Name = "Changed by Second" };
SelectedNewsItems[0] = change;
}
}
As I click on buttons the bindigs work, so maybe it will help you.
I am displaying a list of timers which constantly update the UI (every one second) to show proper time.
Is this the efficient way ? How this process can be improved from performance point of view ?
I am using MVVMLight toolkit for windows phone.
XAML code:
<ListBox ItemsSource="{Binding TimersCollection}"
ItemTemplate="{StaticResource SingleItemTemplate}"/>
Here is my simple itemtemplate code,It also has Pause, Add Minute button but removed from here for simplicity:
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="SingleItemTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding CurrentTime.Hours}"/>
<TextBlock Text="H"></TextBlock>
<TextBlock Text="{Binding CurrentTime.Minutes}" />
<TextBlock Text="M"></TextBlock>
<TextBlock Text="{Binding CurrentTime.Seconds}" />
<TextBlock Text="S"></TextBlock>
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
Here is my ViewModel code which is injected in view:
public class Page1VM : ViewModelBase
{
private ObservableCollection<MyTimer> _timersCollection = new ObservableCollection<MyTimer>();
public Page1VM()
{
// sample code to simulate collection of timers
for (int i = 1; i < 5; i++)
{
var t = new MyTimer();
t.TotalTimeSpan = new TimeSpan(0, i, 0);
_timersCollection.Add(t);
t.Start();
}
}
public IList<MyTimer> TimersCollection
{
get { return _ghatikatimerscoll; }
}
}
Here is ITimer Interace
public interface ITimer
{
bool Start();
bool Stop();
bool IsRunning { get; set; }
void AddMinute();
}
Its implementation
public class MyTimer : ViewModelBase, ITimer
{
public TimeSpan TotalTimeSpan { private get; set; }
private readonly DispatcherTimer _myDispatcherTimer;
private TimeSpan _startTime;
public bool IsRunning { get; set; }
public MyTimer()
{
_myDispatcherTimer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 1) };
_myDispatcherTimer.Tick += _myDispatcherTimer_Tick;
}
private TimeSpan _currentTime;
public TimeSpan CurrentTime
{
get
{
return _currentTime;
}
set
{
_currentTime = value;
RaisePropertyChanged("CurrentTime");
}
}
void _myDispatcherTimer_Tick(object sender, EventArgs e)
{
if (_myDispatcherTimer.IsEnabled)
{
var currenttime = TotalTimeSpan.Add(new TimeSpan(0, 0, 1)) - (DateTime.Now.TimeOfDay - _startTime);
CurrentTime = currenttime;
}
}
public bool Start()
{
_startTime = DateTime.Now.TimeOfDay;
if (_currentTime.TotalSeconds != 0)
{
// resuming after paused
TotalTimeSpan = CurrentTime;
}
IsRunning = true;
_myDispatcherTimer.Start();
return true;
}
public bool Stop()
{
_myDispatcherTimer.Stop();
IsRunning = false;
return true;
}
public void AddMinute()
{
TotalTimeSpan = TotalTimeSpan.Add(new TimeSpan(0, 1, 1));
}
}
Basically, I am displaying a collection of Timers on screen which updates itself. Each item in list has its own DispatcherTimer. User an click "Pause" button for each item to pause that particular timer. User can also click on "Add Minute" button which adds 1 minute to the particular item in collection.
Is this method efficient to update the UI constantly?
Rather than having one timer per item, you can declare one global dispatcher timer that will update every item every second (actually, you should set a delay lower than a second or you may see some items skipping a second). It will be much more efficient than using x dispatcher timers. You'd have to put it in the ViewModel and iterate with a foreach loop. You could also create a wrapper around the timer, define an event that will be triggered every second, and have all the items subscribe to that event, but I don't think it's worth the trouble.
In XAML I have the <Slider />. It has the ValueChanged event. This event fires with every change to Value. I need to detect when the value change is over. LostFocus, PointerReleased are not the correct event. How can I detect this?
XAML, WinRT, Windows8.1 and UWP:
PointerCaptureLost event should work for mouse / touch
KeyUp event for keyboard
You can create a new class and inherit from Slider. From there on, you can look for the Thumb control & listen for the events you want.
Something like this should work:
public class SliderValueChangeCompletedEventArgs : RoutedEventArgs
{
private readonly double _value;
public double Value { get { return _value; } }
public SliderValueChangeCompletedEventArgs(double value)
{
_value = value;
}
}
public delegate void SlideValueChangeCompletedEventHandler(object sender, SliderValueChangeCompletedEventArgs args);
public class ExtendedSlider : Slider
{
public event SlideValueChangeCompletedEventHandler ValueChangeCompleted;
private bool _dragging = false;
protected void OnValueChangeCompleted(double value)
{
if (ValueChangeCompleted != null)
{
ValueChangeCompleted(this, new SliderValueChangeCompletedEventArgs(value) );
}
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
var thumb = base.GetTemplateChild("HorizontalThumb") as Thumb;
if (thumb != null)
{
thumb.DragStarted += ThumbOnDragStarted;
thumb.DragCompleted += ThumbOnDragCompleted;
}
thumb = base.GetTemplateChild("VerticalThumb") as Thumb;
if (thumb != null)
{
thumb.DragStarted += ThumbOnDragStarted;
thumb.DragCompleted += ThumbOnDragCompleted;
}
}
private void ThumbOnDragCompleted(object sender, DragCompletedEventArgs e)
{
_dragging = false;
OnValueChangeCompleted(this.Value);
}
private void ThumbOnDragStarted(object sender, DragStartedEventArgs e)
{
_dragging = true;
}
protected override void OnValueChanged(double oldValue, double newValue)
{
base.OnValueChanged(oldValue, newValue);
if (!_dragging)
{
OnValueChangeCompleted(newValue);
}
}
}
You can use pair of bool values isValueChanged and (if possible change value without manipulation of pointer
) isPressed;
private void Slider_ValueChanged(object s, RangeBaseValueChangedEventArgs e) {
if (!isPressed) {
AcceptChanges();
} else {
isValueChanged = true;
}
}
Initialization code:
Window.Current.CoreWindow.PointerPressed += (e, a) => { isPressed = true; };
Window.Current.CoreWindow.PointerReleased += (e, a) => {
isPressed = false;
if (isValueChanged) AcceptChanges();
};
I had a similar issue using a Slider on Windows8/WinRT.
My problem was the following: I was reacting to the ValueChanged Event and performing a long lasting operation (writing asynchronously to a file) after each trigger. And thus running into a concurrent editing exception. In order to avoid this, I used a DispatcherTimer.
//Class member
private DispatcherTimer myDispatcherTimer = null;
private void OnSliderValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
//I update my UI right away
...
//If the dispatcher is already created, stop it
if (myDispatcherTimer!= null)
myDispatcherTimer.Stop();
//Overwrite the DispatcherTimer and thus reset the countdown
myDispatcherTimer= new DispatcherTimer();
myDispatcherTimer.Tick += (sender, o) => DoSomethingAsync();
myDispatcherTimer.Interval = new TimeSpan(0,0,2);
myDispatcherTimer.Start();
}
private async void DoSomethingAsync()
{
await DoThatLongSaveOperation();
}
You cannot directly detect what the final value is, but you can at least delay the operation until there is a long pause between two updates (e.g. in my case, if the user drags the slider and stops while maintaining the drag for 2 seconds, the save operation will be fired anyway).