wpf DispacherTimer sometimes don't starts - c#

I have roblem with timer and AutocompleteBox toolkit.
I have AutoCompletebox with TextChanged Event. On this event I start timer to make filtering smoother (when user writes, filter don't work).
When I writes everything works ok, but when I choose from DropDown list TextChanged event starts, but I don't have timer Tick event (filter don't starts). What I do wrong?
xaml:
<Controls:AutoCompleteBox Name="acbIdentyfikatorPcS" ValueMemberPath="Identyfikator" FilterMode="Contains" HorizontalAlignment="Left" Margin="100,5,0,0" Grid.Row="1" VerticalAlignment="Top" Width="121" ToolTip="Identyfikator" MinimumPrefixLength="0" TextChanged="acbSerwisant_TextChanged" IsTextCompletionEnabled="True">
<Controls:AutoCompleteBox.ItemTemplate>
<DataTemplate>
<TextBlock Margin="0,0,10,0" FontWeight="Bold" Text="{Binding Identyfikator}"></TextBlock>
</DataTemplate>
</Controls:AutoCompleteBox.ItemTemplate>
</Controls:AutoCompleteBox>
CS:
Declaration:
private DispatcherTimer timerfiltr = new DispatcherTimer();
private DataTable PcS;
public MainWindow()
{
InitializeComponent();
timerfiltr.Tick += new EventHandler(timerfiltr_Tick);
timerfiltr.Interval = new TimeSpan(0, 0, 0, 0, 400);
}
private void acbSerwisant_TextChanged(object sender, RoutedEventArgs e)
{
timerfiltr.Stop();
timerfiltr.IsEnabled = true;
timerfiltr.Start();
}
private void timerfiltr_Tick(object sender, EventArgs e)
{
PcS.DefaultView.RowFilter = "Identyfikator like '%" + acbIdentyfikatorPcS.Text + "%'";
timerfiltr.Stop();
timerfiltr.IsEnabled = false;
}
EDIT:
I think I found my problem:
This AutoCompleteBox is on one of the TabItem, I have also TabControl SelectionChanged event, where is also timer.stop() command
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//rest of code
// timerfiltr.Stop();
}
When I press key down on keyboard (AutoCompleteBox is focused), DropDown opens, and then also TabControl SelectionChanged event also starts and stops timer...
Weird

You can use the IsDropDownOpen property (or DropDownXXX events) of the AutoCompleteBox to figure out whether the DropDown is currently visible and one quick solution is to avoid stopping your timer inside its Tick method for example.

I didn't test your sample code, I think maybe *acbSerwisant_TextChanged* stop the dispatcher thread.
For this scenario, I suggest you do change your code like this, maybe not best, but should work, and there is framework is more suitable for dealing this which is called "RX"(https://rx.codeplex.com), method Throttle is what your want.
**Update: if you worry about perf, add flag as switch,since all code run under ui thread, this guarantee you that last text change will be accepted.But reality is a bit complex, normally you will do you filter in another thread...if that happened,i suggest you use other thread with while statement to check textchange, or you can take look at RX.
private bool enableFilter;
public MainWindow()
{
InitializeComponent();
timerfiltr.Tick += new EventHandler(timerfiltr_Tick);
timerfiltr.Interval = new TimeSpan(0, 0, 0, 0, 400);
acbIdentyfikatorPcS.GotFocus +=(s,e)=>{timerfiltr.Start();};
acbIdentyfikatorPcS.LostFocus +=(s,e)=>{timerfiltr.Stop();};
acbIdentyfikatorPcS.TextChanged +=(s,e)=>{enableFilter= true;};
}
private void timerfiltr_Tick(object sender, EventArgs e)
{
if(enableFilter)
{
enableFilter= false;
//do filter
}
}

Related

WPF: Figuring out whether a MouseBinding is a single click or double click

Im using Mousebindings in my view to listen to user clicks like this:
<Path.InputBindings>
<MouseBinding Gesture="LeftDoubleClick" Command="{Binding DoubleLeftClickProj}" />
<MouseBinding Gesture="LeftClick" Command="{Binding SingleLeftClick}"/>
</Path.InputBindings>
I only need one of the mouse gestures at a time. So if I double click on my application I want to ignore the single left click mousebinding. Possibly like waiting 1-2sec after the initial mouseclick then decided which should be called. Is there a simple way of doing this?
I got it working the following way (I used a Button to test it, you'll have to adapt it).
Use Event Handlers
<Button MouseDoubleClick="Button_MouseDoubleClick" Click="Button_Click"></Button>
store the DataContext in a static variable
private static object context;
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
context = DataContext;
}
Adapt this code (I mainly got it from https://stackoverflow.com/a/971676/4792869)
private static DispatcherTimer myClickWaitTimer =
new DispatcherTimer(
new TimeSpan(0, 0, 0, 1),
DispatcherPriority.Background,
mouseWaitTimer_Tick,
Dispatcher.CurrentDispatcher);
private void Button_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
// Stop the timer from ticking.
myClickWaitTimer.Stop();
((ICommand)DataContext).Execute("DoubleLeftClickProj");
e.Handled = true;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
myClickWaitTimer.Start();
}
private static void mouseWaitTimer_Tick(object sender, EventArgs e)
{
myClickWaitTimer.Stop();
// Handle Single Click Actions
((ICommand)context).Execute("SingleLeftClick");
}

Windows phone 8.1 textbox multiple click

If a textbox has focus and I want to be able to select it again is there a way to do this.
So first click the background turns blue and while it is still selected I press again the background turns green. How do I catch the second press even though its already selected?
You can subscribe to the PointerEntered and the SelectionChanged events. The first one is always fired when the pointer hits the TextBox. However if it contains text and you tap on it you will eventually select the text. The SelectionChanged handler will take care for that.
Your XAML markup looks as follows:
<TextBox x:Name="tb"
Text="Test"
PointerEntered="TextBox_PointerEntered"
SelectionChanged="TextBox_SelectionChanged"
GotFocus="TextBox_GotFocus"/>
The code behind file contains the following code:
private void TextBox_PointerEntered(object sender, PointerRoutedEventArgs e)
{
tb.Background = new SolidColorBrush(Colors.Green);
}
private void TextBox_SelectionChanged(object sender, RoutedEventArgs e)
{
tb.Background = new SolidColorBrush(Colors.Green);
}
private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
tb.Background = new SolidColorBrush(Colors.Blue);
}
You will have to adjust the code to your needs and take care of special cases where both SelectionChanged AND PointerEntered are fired (at this point both handlers do the same, so there's no problem).

Programatically set Focus to a TextBox in Windows Phone

In a Windows Phone app I have an TextBox and a Button. The user writes some text to the TextBox and taps the Button, the text from the TextBox is added to a list. The TextBox loses focus after the Button is tapped.
What I want to do is to set the focus back to the TextBox after the Button is tapped so the user can continue writing another text without needing to tap the TextBox.
I tried calling the Focus() method of the TextBox in the Button handler but this does not work. is there another, if any, way to do this?
When Button clicked try to add bollean flag = true. Then check this flag on event OnTextBoxLostFocus.
<TextBox x:Name="tb" Grid.Row="1" LostFocus="Tb_OnLostFocus"/>
<Button x:Name="btn" Click="Btn_OnClick" />
public partial class MainPage : PhoneApplicationPage
{
private bool flag;
public MainPage()
{
InitializeComponent();
}
private void Btn_OnClick(object sender, RoutedEventArgs e)
{
flag = true;
tb.Focus();
}
private void Tb_OnLostFocus(object sender, RoutedEventArgs e)
{
if (!flag) return;
tb.Focus();
flag = false;
}
}
Hope its help.
I have tried a lot of solutions, but this is the only one that works for me (Windows Phone 8.1 app).
First catch your TextBox's Loaded event, then call Focus(FocusState.Keyboard).
private void myTextBox_Loaded(object sender, RoutedEventArgs e)
{
myTextBox.Focus(FocusState.Keyboard);
}
Even I tried with lots of above solutions but none of them worked for me as am trying to focus on page load. Finally I got this solution and it worked.
private void txtBox_LayoutUpdated(object sender, EventArgs e)
{
txtBox.Focus();
}
What happens if you call:
yourTextBox.Select(0,0)
http://msdn.microsoft.com/en-us/library/system.windows.controls.textbox.select.aspx
you can accomplish this by programmatically giving it focus. This can be done by
calling its Focusmethod, although this call can fail (and return false) under certain conditions.
For example, you cannot set focus on a control from a page’s constructor; it’s too early. You can,
however, call it from a page’s Loadedevent.
The way that it worked best for me on the phone was, if I wanted to focus on a particular textbox when the page loaded:
private void OnPageLoaded(object sender, RoutedEventArgs e)
{
Dispatcher dispatcher = Deployment.Current.Dispatcher;
dispatcher.BeginInvoke(() => EnterLocationTextBox.Focus());
}
or if I just wanted it at a certain point. Just repeat these two lines:
Dispatcher dispatcher = Deployment.Current.Dispatcher;
dispatcher.BeginInvoke(() => EnterLocationTextBox.Focus());

Action on both button press and release

I can't get this straight: I have one button that I want one action for the press event and one action for release, I've searched everywhere and can't find an answer.
KeyDown, KeyUp or MouseLeftButtonDown doesn't work with button on windows phone 7.
First I tried combining GotFocus and Click clickmode release like this:
(As you can see I want Image1 to be shown while pressing button, and hidden when releasing the button)
xaml:
Button Click="button1_Click" ClickMode="Release" GotFocus="button1_GotFocus" Content="byt" Height="72" Margin="0,500,6,0" Name="button1" VerticalAlignment="Top"
private void button1_GotFocus(object sender, RoutedEventArgs e)
{
Image1.Visibility = System.Windows.Visibility.Collapsed;
}
private void button1_Click (object sender, RoutedEventArgs e)
{
Image1.Visibility = System.Windows.Visibility.Visible;
}
This works only one time and could work all the time if I could loose focus from the button when releasing it (tried searching for that as well)
The other thing I tried was changing the clickmode while pressing the button, but didn't get that to work either..
something like this:
private void button1_Click (object sender, RoutedEventArgs e)
{
Image1.Visibility = System.Windows.Visibility.Collapsed;
button1.SetValue(Button.ClickModeProperty, ClickMode.Release);
Image1.Visibility = System.Windows.Visibility.Visible;
}
(I know that the syntax is wrong somehow in the second one)
Would be grateful for help!
MouseLeftButtonDown / MouseLeftButtonUp do work on WP7. Obviously not named the best, but they do work on the device.
<TextBlock x:Name="ApplicationTitle" MouseLeftButtonDown="ApplicationTitle_MouseLeftButtonDown" MouseLeftButtonUp="ApplicationTitle_MouseLeftButtonUp"
Style="{StaticResource PhoneTextNormalStyle}"
Text="MY APPLICATION" />
You'll see Down gets fired, and then immediately Up.
private void ApplicationTitle_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
}
private void ApplicationTitle_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
}
Perhaps all you need is MouseLeftButtonDown/Up.
I used
Click="{x:Bind UpArrow_Click}"
ClickMode="Press"
PointerCaptureLost="Button_Release"
on a button. When button is pressed UpArrow_Click event occurs... when button is released Button_Release event occurs

WPF ComboBox delayed filtering

Consider following situation:
there is ComboBox and a filter TextBox, then user types a text in a text box ComboBox items source is updated using filter text. Everything works, but filtering occurs on every typed letter. I want to add a delay before filtering occurs (filter is not applyed while user is typing). What is the simpliest way to do it?
The most used way of doing this is introducing a timer where everytime the user enters a new character your timespan get's reset but if it is longer than x seconds then execute the code.
Remember to do it async so that if the user starts typing again while you are performing a search you can cancel the async call as that information will now be outdated.
If you are using a viewmodel just change textbox1_TextChanged to the appropriate Properties setter
private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
if (!tmr.Enabled)
{
tmr.Enabled = true;
tmr.Start();
}
TimeSinceType = DateTime.Now;
}
public DateTime TimeSinceType { get; set; }
protected void Load()
{
tmr = new Timer();
tmr.Interval = 200;
tmr.Elapsed += new ElapsedEventHandler(tmr_Elapsed);
}
void tmr_Elapsed(object sender, ElapsedEventArgs e)
{
if ((DateTime.Now - TimeSinceType).Seconds > .5)
{
Dispatcher.BeginInvoke((Action)delegate()
{
//LoadData();
tmr.Stop();
});
}
}
This can be done much easier now by putting a delay directly on the binding:
<ComboBox Text={Binding MyBinding, Delay=200} />

Categories