I am having a problem with updating the Window of a Wpf-Application. After googling a long time, I broke my problem down to the following example. I hope you can help me.
Let´s say we have a Window with a Button and a TextBlock ... nothing special:
...
<Grid>
<Button ... Click="button_Click"/>
<TextBox x:Name="textBox" Text="DefaultText" .../>
</Grid>
...
The button_Click is a simple event like this:
private void button_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 20; i++)
{
textBox.Dispatcher.Invoke(new Action(() => textBox.Text = i.ToString());
}
}
And here is my Problem. If I debug the loop, the Text of my TextBlock is always the "DefaultText". Only at the end of my loop, the Text is "19". Why is my dispatcher not able to change the Text? Like described here (What's the difference between Invoke() and BeginInvoke()) the Dispatcher should stop my Thread until the job is done.
I tried different DispatcherPriorities ... but no difference. What´s my problem?
Thank you for helping me.
For anyone googling around looking for a solution to their slow WPF application during debugging;
When instantiating the DispatcherTimer object use DispatcherPriority.Send as an argument. This sets the priority of your UI higher, making your application or game run smoother while debugging. Source
DispatcherTimer gameTimer = new DispatcherTimer(DispatcherPriority.Send);
I hope this will help out someone else in the future :)
Related
I'm making an automatic CarouselView (slider) to slide between images every x seconds. I know there are plenty of examples but none of them helped me to make mine work. So here is the deal:
This is my xaml page:
<CarouselView x:Name="carou_slideshow" Grid.Row="1" IsVisible="False">
<CarouselView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
Whenever the user clicks on the button to start the slideshow, it shows my carousel with its images without any issue but it doesn't change the current image after x seconds. Here's how I've done it :
private void btn_slideShow_Clicked(object sender, EventArgs e)
{
stk_header.IsVisible = false;
stk_options.IsVisible = false;
grid_images.IsVisible = false;
carou_slideshow.IsVisible = true;
carou_slideshow.ItemsSource = sources;
Device.StartTimer(TimeSpan.FromSeconds(5), (Func<bool>)(() =>
{
carou_slideshow.Position = (carou_slideshow.Position + 1) % sources.Count;
return true;
})
);
}
Any idea why ?
EDIT : I realized that in my project I already had a timer in the same class. After removing it and keeping the one in the button method, my application crashes without any error.
EDIT2 : Someone gave me a solution on this post and deleted it after. I tried it and it doesn't work for me.. As I was sure it would, I tried to increment something else and the timer works perfectly fine, but the image doesn't swipe. Also, it can randomly close the application as well as not having any issue.
I have a class MyWindow which inherits from Window. Within MyWindow, I have the following method to execute once my OK button is clicked:
private void OKButton_Click(object sender, RoutedEventArgs e)
{
var be = NameBox.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();
this.Close();
}
XAML:
<Button Content="OK"
Click="OKButton_Click"
HorizontalAlignment="Left"
Margin="175,473,0,0"
VerticalAlignment="Top"
Width="75"
RenderTransformOrigin="-0.04,0.5"/>
In a separate class where I initialize my UI window, I say
MainWindow window = new MainWindow(ViewModel);
window.Show();
However, as soon as window.Show() is executed, the subsequent code is executed and I cannot actually interact with my window to do what I need to do. I feel like this is just a misunderstanding in how to actually use WPF in a larger context...any help?
Window.ShowDialog is what is needed to view the page. But one doesn't get the binding information as you did; which should be changed as well.
When the textbox loses focus it will update the binding so the code
var be = NameBox.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();
is not needed. (Is this a leftover form winform programming?) So I suggestion one not update a binding as such.
The only possible thing to do if the binding is not updated is to change the binding to use the mode of TwoWay which ensures a back and forth data transfer between the variable bound to and the textbox on the screen.
I am using RichEditBox with XAML and C#
I have following 3 events in XAML and corresponding handlers in C#(back code)
DoubleTapped="RichEditBox_DoubleTapped" RightTapped="RichEditBox_RightTapped" PointerReleased="RichEditBox_PointerReleased"
But after putting debug points, I found, none of them is getting triggered.
DoubleTapped event gets triggered if I double tap not on the word but on empty space within the RichEditBox. Once this event is handled, double tap starts working even on words.
I need to handle any of the above events on words. But none of them is responding as expected.
How can I achieve it?
okies. Got other 2 events working as:
SelectionChanged="RichEditBox_SelectionChanged" Holding="RichEditBox_Holding"
Above events mentioned in the question might be a bug, not sure though.
this is a user control and I've got this code XAML:
<RichEditBox x:Name="TextElementControl" Background="{Binding Background, ElementName=userControlModified}" ManipulationMode="None" ScrollViewer.HorizontalScrollMode="Disabled"
AcceptsReturn="True" TextWrapping="Wrap"
SizeChanged="TextElementControlSizeChanged"
IsDoubleTapEnabled="False" DoubleTapped="TextElementControl_DoubleTapped" BorderThickness="0" BorderBrush="{x:Null}" Padding="10,10,10,10"/>
in the code behind :
private void TextElementControl_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
//log message, breakpoint is hitting this during double click.
}
on some portion of the code we've set
void ControlLoaded(object sender, RoutedEventArgs e)
{
TextElementControl.IsReadOnly = false;
}
it works and I hope it helps you.
I am developing a WPF application that follows MVVM design pattern. For threading I intend to use Backgroundworker. From viewmodels,I need to initiate threads to perform time taking opeartions.Please suggest me how to display an wait dialog until the thread is performing. If possible please provide a sample code.
Regards,
Anirban
You could add a property to the ViewModel that indicates that the backgroundworker (or other asynchronous action) is busy.
A View can bind bind to this property to show a progressbar or other busy indicator.
Just make sure you set and reset the property correctly.
EDIT
See this question/answer for making a modal dialog in WPF: How do make modal dialog in WPF?
As an alternative you could use this setup (pseudo code):
<Window>
<Grid>
<Grid x:Name="regularContent">
</Grid>
<Grid x:Name="Overlay" Visibility="Collapsed">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Progressbar Value="{Binding Path=Progress}" />
</StackPanel>
</Grid>
</Grid>
</Window>
Code behind:
private void ShowPopup()
{
RegularContent.IsEnabled = false;
Overlay.Visibility = Visibility.Visible;
}
private void ClosePopup()
{
RegularContent.IsEnabled = true;
Overlay.Visibility = Visibility.Collapsed;
}
Make sure you disable the regular content to prevent the user from tabbing to it.
You can use the same structure to blockout a part of the View instead of blocking it entirely as I have done.
The Progress property on the ViewModel that the ProgressBar is bound to should be modified on the UI thread. If you are using a backgroundworker that will be done automatically because the ReportProgress event is raised on the UI thread.
If you use a different way of creating a worker thread make sure you use the dispatcher to update the Progress property.
I used it in Windows Phone :
private readonly BackgroundWorker worker = new BackgroundWorker();
private PerformanceProgressBar loader = new PerformanceProgressBar();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
bar.IsIndeterminate = true;
Bar.Enabled = true;
}
private void worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
bar.Enabled = false;
}
worker.RunWorkerAsync();
If you want to define a MVVM structure :
PerformanceProgressBar "Invalid cross-thread access" exception
Of course an similar user control also exists in WPF : http://wpftoolkit.codeplex.com/wikipage?title=Extended%20WPF%20Toolkit%20Controls
The easiest way is to use wpf busyindicator (http://elegantcode.com/2011/10/07/extended-wpf-toolkitusing-the-busyindicator/).
You can bind it to some thread_is_busy_flag_property in your model model (I prefer it in some singletone accessible through application-wide resource via locator pattern - it's easy to share across xaml and model view/code behind).
Just don't forget about thread safety when setting this flag (or you can use AutoResetEvent/ManualResetEvent to catch background operation ends). And I suggest to use TPL and tasks (more robust way) instead of BackgroundWorker/QueueUserWorkItem.
I want to highlight a Line if it was clicked. Like a TreeViewItem is highlighted while it is selected or got focused (It seems, that there is a diffrence - While it is focused(and selected) its Highlight-Color is blue, if it only got selected and lost focused its grayish.).
I tried to catch the Gotfocus Event of Line without knowing which property I want to change, but it is not even firing(Though Focusable = true).
I got the MouseDown event firing(which i primarly don't want to use for this) and still don't know which property to change. Msdn and Google returns nothing senseful.
Any Ideas?
Thanks in Advance.
You can use style and triggers for this kind of work. You won't need any code only XAML will work. Create a trigger that will fire once the mouse down = true and inside that trigger change the color of line or it's background or whatever you want
see this for basics about Triggers.
Check this now.
for example
<Path Data="M101,42 L380,76" Fill="#FFF4F4F5" Height="35"
Margin="101,42,243,0" Stretch="Fill" Stroke="Black"
VerticalAlignment="Top" MouseEnter="Path_MouseEnter" Name="myLine"/>
and c#
private void Path_MouseEnter(object sender,
System.Windows.Input.MouseEventArgs e)
{
myLine.Stroke = new SolidColorBrush(Colors.Green);
}
please check now :)