I am using LiveCharts.WinForms.CartesianChart to render a large amount of points:
myChart.Zoom = ZoomingOptions.X;
myChart.Pan = PanningOptions.X;
myChart.Series.Add(new LineSeries
{
Values = chartValuesScores,
Fill = System.Windows.Media.Brushes.Transparent,
PointGeometrySize = 5
});
myChart.AxisX.Add(new Axis
{
Labels = labels
});
What I want to do is to display some kind of a progressbar and stop the time LiveCharts needs to render this points. But it seems that LiveCharts renders the points asynchronously. That means that after running the code above, it continues running other code lines and exits the function.
Thus, my question is: Is there a way to detect that LiveCharts.WinForms.CartesianChart is finished with rendering? I could not find an event or something else.
I found this while checking the docs: https://lvcharts.net/App/examples/v1/wpf/Events
It lists Chart.UpdaterTick as one of the events. That events seems to fire when the graph has finished loading the data and had rendered it on screen, I believe what you were looking for?
I've tested myself and appears to work as I expect.
There is an CartesianChart.Loaded event, which is fired after the chart is rendered.
myChart.Loaded += myChart_Loaded;
private void myChart_Loaded(object sender, RoutedEventArgs e)
{
// chart is rendered
}
Related
I have a windows form which hold a web browser control, that web browser will change it's position automatically in fixed positions
So first I set the navigate to position X then I will take a capture from my form then change the position to Y and also take another capture.
My Issue is that I use the navigation to position like
webBrowser1.Navigate("javascript:window.scroll(0," + X + ");");
So I should wait tell the ui change the position then Do the capture code, after finish I should re-change the position to Y same way and wait tell the UI finish then capture.
I try to use background worker but it didn't support me as well I also try Threading but as I;m not so good dealing with Threading my ui didn't navigate before capture.
I use Threading like:
ThreadStart captureFunc = new ThreadStart(CaptureScreen);
Thread captureThread = new Thread(captureFunc);
captureThread.Start();
while (!doneVal)
{
}
captureThread.Abort();
while CaptureScreen is my capture function and doneVal is a value with default false and changed to true after capture.
any help will be appreciated.
The WebBrowser-control offers Events, such as the Navigated-Event.
You can use this to determine the end of the navigation of the WebBrowser-control:
webBrowser1.Navigated += NavigatedEventHandler; //use in constructor for example
...
private void NavigatedEventHandler(object sender, NavigatedEventArgs e){
//perform actions here
}
Long time listener, first time caller here. I'm having a strange issue with the TextBox in WinRT C#/XAML that I hope someone may be able to help me with.
Basically, I'm working on creating a Custom Control that essentially requires a second TextBox to be a copy of the first, including showing the same Text, and showing the same Selected Text. Obviously for the Text requirement I simply respond to the TextChanged event on the first TextBox and set the Text of the second TextBox to the Text from the first, which works great.
For the Selected Text requirement I started with a similar solution, and my code for this is as follows:
void TextBox1_SelectionChanged(object sender, RoutedEventArgs e)
{
this.TextBox2.Select(this.TextBox1.SelectionStart, this.TextBox1.SelectionLength);
}
This seemed to work pretty well when initially used with a mouse:
But I'm having a problem when selecting text with Touch. I double-tap within the TextBox to create the first "anchor" as you do in Touch, then drag to begin the selection; but I only ever manage to select a single character normally before the selection stops. The TextBox doesn't lose focus exactly, but the behaviour is similar to that; the selection anchors disappear and I can't continue selecting anything unless I re-double-tap to start a new selection. If I remove the code to select text in TextBox2 then the Touch selection behaves perfectly in TextBox1.
I've been trying to fix this for a while and cannot, I'm not sure if I can get the desired behaviour with WinRT TextBoxes. Does anyone have any ideas? Or perhaps another way to implement a solution with two TextBoxes with this behaviour?
Thanks a lot.
So this is far from an answer, but discovered a few things that maybe will help you or others come up with a potential workaround. Apologies if these are things you've already seen and noted.
First, it's not the call to TextBox2.Select() that's the problem per se. This for instance, works fine for me
private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
{
var start = TextBox1.SelectionStart;
var length = TextBox1.SelectionLength;
TextBox2.Select(3, 5);
}
unfortunately, using start and length versus the hard-coded 3 and 5, that is, the following, DOES NOT WORK:
private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
{
var start = TextBox1.SelectionStart;
var length = TextBox1.SelectionLength;
TextBox2.Select(start, length);
}
I also discovered that I could select TWO characters if I started from the end, but only one from the beginning. That got me to thinking about dispatching the call to set the second selection:
private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
{
var start = TextBox1.SelectionStart;
var length = TextBox1.SelectionLength;
Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low,
() => TextBox2.Select(start, length));
}
Now I can select 2 from the front and 3 and sometimes 4 from the back. Took it a step further, and was able to select as many as six or seven with a really fast swipe.
private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
{
var start = TextBox1.SelectionStart;
var length = TextBox1.SelectionLength;
Dispatcher.RunIdleAsync((v) => Highlight());
}
public void Highlight()
{
TextBox2.Select(TextBox1.SelectionStart, TextBox1.SelectionLength);
}
Seems like the trick to working around this is not setting TextBox2 until whatever vestiges of the TextBox1 SelectionChanged event have completed.
This may be worth registering on Connect.
Mine is only a partial solution as well.
I did some debugging and noticed that the SelectionChanged event is fired throughout the text selection process. In other words, a single finger "swipe" will generate multiple SelectionChanged events.
As you found out, calling TextBox.Select during a text selection gesture affects the gesture itself. Windows seems to stop the gesture after the programmatic text selection.
My workaround is to delay as long as possible calling the TextBox.Select method. This does work well, except for one edge case. Where this method fails is in the following scenario:
The user begins a select gesture, say selecting x characters. The user, without taking their finger off the screen, pauses for a second or two. The user then attempts to select more characters.
My solution does not handle the last bit in the above paragraph. The touch selection after the pause does not actually select anything because my code will have called the TextBox.Select method.
Here is the actual code. As I mentioned above, there are multiple selection changed events fired during a single selection gesture. My code uses a timer along with a counter to only do the programmatic selection when there are no longer any pending touch generated selection changed events.
int _selectCounter = 0;
const int SELECT_TIMER_LENGTH = 500;
async private void TextBox1_SelectionChanged(object sender, RoutedEventArgs e)
{
// _selectCounter is the number of selection changed events that have fired.
// If you are really paranoid, you will want to make sure that if
// _selectCounter reaches MAX_INT, that you reset it to zero.
int mySelectCount = ++_selectCounter;
// start the timer and wait for it to finish
await Task.Delay(SELECT_TIMER_LENGTH);
// If equal (mySelectCount == _selectCounter),
// this means that NO select change events have fired
// during the delay call above. We only do the
// programmatic selection when this is the case.
// Feel free to adjust SELECT_TIMER_LENGTH to suit your needs.
if (mySelectCount == _selectCounter)
{
this.TextBox2.Select(this.TextBox1.SelectionStart, this.TextBox1.SelectionLength);
}
}
Is there a specific time in the page's lifecycle that the Map.SetView() function should be called? In our app we use this on various map objects and it seems to work randomly, sometimes perfectly and sometimes with no effect but also no exception.
example code:
RouteMap.SetView(LocationRectangle.CreateBoundingRectangle(DirectionCoordinates));
Where RouteMap is the mapping component and DirectionCoordinates contains the start/end coordinates for the map.
I can see that the bounding box is being created properly, but the map's positioning is not always being affected even loading the same data. If I add a break point it does seem to work, so I was assuming it had something to do with the map loading, but adding the SetView() functionality to the Loaded event has the same issue. We currently process the map information in the page Loaded event.
Update
I've been testing more and added events to what I could, I know for a fact that the MapLoaded event is being called before SetView. After SetView is called, it is working sometimes and not others. Neither ViewChanging or ViewChanged events are called.
This is obviously not the best solution, but there must be something that is not quite finished loading when the Loaded event is called that is preventing this from finishing.
I added a 100ms sleep to the Map_Loaded event and it has solved the problem I was having.
System.Threading.Thread.Sleep(500);
update
100ms isn't working for some people, you may want to play around with the numbers, 200, 500 etc. It's still a very short delay on the map's load time. I have contacted Microsoft about this and they have told me that they are looking into the issue and we will hopefully have some sort of response from them shortly.
update and edit
Use the following code instead to prevent UI hanging:
await Task.Delay(250);
I tackled this issue using ResolveCompleted event and boolean flag.
private void Map_ResolveCompleted(object sender, MapResolveCompletedEventArgs e)
{
if (this.zoomReq)
{
this.zoomReq = false;
if (this.locationList != null && this.locationList.Count > 0)
{
var viewRect = LocationRectangle.CreateBoundingRectangle(this.locationList);
this.Map.SetView(viewRect);
}
}
}
There is noticeable pause before map zooms but at least this seems to work all the time. The flag is needed because ResolveCompleted is fired every time the map moves.
I was both constructing a map layer (Microsoft.Phone.Maps.Controls.MapLayer) and setting the view (public void SetView(LocationRectangle boundingRectangle);) in an async method:
public async Task CreateMap()
{
map.Add(mapLayer);
map.SetView(locationRectangle);
}
I was doing some loading, that's why I used async.
This would only set the view once, the first time I navigated to the page.
The solution was to dispatch the set view call:
public async Task CreateMap()
{
map.Add(mapLayer);
Dispatcher.BeginInvoke(() =>
{
map.SetView(locationRectangle);
});
}
Hope that helps.
The Loaded event is the proper place for SetView(). You could try creating your rectangle in you OnNavigatedTo method. When I'm working with locations I always start my watcher in OnNavigatedTo and work with any map layers in _Loaded.
I worked myself some time at this problem. It didn't help to put most of the stuff to load into the constructor of the page. I tried to the trick with System.Threading.Thread.Sleep(500) but it took far beyond 500ms to take effect and this wasn't acceptable for me. For some people it helped to trigger an ZoomLevelChanged event and set the view in it. For myself I used a DispatcherTimer in which I used SetView() and fired an `ViewChanging´ event to stop the timer. If you use an animation the difference is pretty small.
I had this problem for MapAnimationKind.Linear but for MapAnimationKind.None it works without any problem
map.SetView(LocationRectangle.CreateBoundingRectangle(...), MapAnimationKind.None);
I had a very similar problem. Basically the setview of map would work the first time a page loaded (i.e. after all the data had finished loading) but if I left the page and came back and did not need to reload all the data, it did not work. While debugging, it seemed like I was setting the information for the map before it was finished loading.
So what I did to resolve the challenge was:
In the XAML - I added an event handler for the Loaded event of the map.
Example: Loaded="myMap_Loaded"
In the myMap_Loaded event, I simply called an async method to wait for the data to load then map
it.
Example:
private void myMap_Loaded(object sender, RoutedEventArgs e)
{
WaitAndLoadMap();
}
Coded the WaitAndLoadMap method to wait for the data to finish loading before loading the
map.
private async void WaitAndLoadMap()
{
//Check if the data is loaded and if it is not - loop.
while (!App.NearbyLocationsViewModel.IsLocationDataLoaded)
await Task.Delay(250);
//Load the map content and set the mapview.
}
It seems to be working. Hope this helps others.
I am using the charting stuff of the WPF toolkit.
After creating a chart I like to have a snaphshot of that chart, without visualizing that chart. My problem is that I don't know when the rendering process is done, so I can create a snapshot.
I tried listening to the "LayoutUpdated" event, but the chart is being updated very often.
Can anyone tell me how to find out if the chart is completely rendered?
You can use the Dispatcher in your code behind:
this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>
{
// code in here should be executed after chart has been rendered.
}
));
The Loaded event sounds like what you need.
MyChart.Loaded += (sender, e) =>
{
// chart has been loaded but not yet rendered
}
where "MyChart" is a the name you've given the chart in your XAML.
I'm not sure how well this works with frequent updates, but this link seems to indicate http://blogs.msdn.com/b/mikehillberg/archive/2006/09/19/loadedvsinitialized.aspx that this is what you're looking for.
I'm trying to take a snapshot of my Silverlight control using WriteableBitmap and it works fine, however, it only takes a snapshot of what is showing. I'm trying to resize the Silverlight control so it will show everything and then take a screenshot, however, the code doesn't resize the control until after the code after the call all runs which is the snapshot code...
I can get this work using a timer to fire the snapshot after the other code has caused the resize but I'm wondering if there is a better way. The HtmlPage.Plugin.SetStyleAttribute call has to be called from the UI thread so I'm assuming that's where the problem is. The fact that it is being dispatched onto the UI thread while the rest of the code is not and so the other code is being run first.
Is there anyway to create a new event or attach to the call to determine when it has been run to then fire off my snapshot code?
I have the following code:
private void btnTakeSnapshot_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (CurrentContractAction != null)
{
string heightBefore = HtmlPage.Plugin.GetStyleAttribute("height");
HtmlPage.Plugin.SetStyleAttribute("height", string.Format("{0}px", "1800")); //this line doesn't change the height until after the "TakeSnapshot" code is run for some reason, I'm thinking it is because it is most likely dispatched to the UI thread :( and the following code is not run on the UI thread
Snapshot snapshot = new Snapshot(string.Format("Action_Schedule_{0}", CurrentContractAction.Title), LayoutRoot, LayoutRoot, busyIndicatorDataGrid);
snapshot.HideElements(btnViewGanttChart, btnSave, btnEditAction, btnFullScreen, btnTakeSnapshot, btnLockAndSubmit);
snapshot.TakeSnapshot();
snapshot.ResetElementsVisibility();
HtmlPage.Plugin.SetStyleAttribute("height", string.Format("{0}px", heightBefore));
}
}
Thanks,
John
John,
You might want to handle the plugin resize event, take your snapshot there, and then restore the plugin height.
Application.Current.Host.Content.Resized += delegate(object sender, EventArgs e)
{
// Bail if this resize event was not triggered by the snapshot taker
// Take the snapshot
// Restore the plugin height
};
Good luck,
Jim McCurdy, Face to Face Software and YinYangMoney