Updating telerik:RadPieChart Palette asynchronously doesn't work - wpf

As the title suggests I'm trying to update the Palette of the telerik:RadPieChart asynchronously. I have implemented a Task which tries to check for new records at a given interval and updates the UI if there's any. Every other controls are updating correctly except the Palette of the telerik:RadPieChart. The Palette would disappear after the Task tries to update it. Here is the pie chart I'm working with.
<telerik:RadPieChart Name="PieLinearChart" Foreground="Gainsboro" FontSize="12" FontWeight="Black" Grid.Row="0" Palette="{Binding Tab.CurrentPoC.PalettePie1}" Height="50px">
<telerik:RadPieChart.Series>
<telerik:DoughnutSeries ShowLabels="True" InnerRadiusFactor="0.4" ValueBinding="Sum" ItemsSource="{Binding Tab.CurrentPoC.PieChart1, Mode=TwoWay}" />
</telerik:RadPieChart.Series>
</telerik:RadPieChart>
The telerik:DoughnutSeries values are updating, though.
The code behind looks something like this:
public Task Init()
{
.......
.......
ExchangeFile.DataUpdated += Exchange_DataUpdated;
.......
.......
}
//This method was called every certain interval
//and works from the background.
private void Exchange_DataUpdated()
{
......
......
//Setting colors to the Palette
//which didn't work in this case
//(works well for other situations)
PalettePie1 = new ChartPalette();
ChartPalette tmpPalette = new ChartPalette();
tmpPalette.GlobalEntries.Add(new PaletteEntry(Utilities.NvarBrushUtils.GetBrush("Red")));
tmpPalette.GlobalEntries.Add(new PaletteEntry(Utilities.NvarBrushUtils.GetBrush("Blue")));
tmpPalette.GlobalEntries.Add(new PaletteEntry(Utilities.NvarBrushUtils.GetBrush("Yellow")));
tmpPalette.GlobalEntries.Add(new PaletteEntry(Utilities.NvarBrushUtils.GetBrush("Green")));
PalettePie1 = tmpPalette;
......
}
I also tried something like this but didn't help:
Application.Current.Dispatcher.Invoke(new Action(() => {
......
ChartPalette tmpPalette = new ChartPalette();
tmpPalette.GlobalEntries.Add(new PaletteEntry(Utilities.NvarBrushUtils.GetBrush("Red")));
tmpPalette.GlobalEntries.Add(new PaletteEntry(Utilities.NvarBrushUtils.GetBrush("Blue")));
tmpPalette.GlobalEntries.Add(new PaletteEntry(Utilities.NvarBrushUtils.GetBrush("Yellow")));
tmpPalette.GlobalEntries.Add(new PaletteEntry(Utilities.NvarBrushUtils.GetBrush("Green")));
PalettePie1 = new ChartPalette();
PalettePie1 = tmpPalette;
......
}));
Please help!

Related

F# wpf async command completion status

I've been experimenting with async commands using F# Viewmodule. The problem is when I click the button, the command get executed, but afterwards the button stays disabled.
Xaml:
<Button Content="start async worker" Command="{Binding StartAsyncCommand}" />
ViewModel:
type MainViewModel() as me =
inherit ViewModelBase()
//...
member __.StartAsyncCommand = me.Factory.CommandAsync(fun _ -> async { return () } )
What am I doing wrong?
EDIT:
Thanks to #FoggyFinder, we determined that the issue was actually with the App.fs file:
open System
open FsXaml
open System.Windows
type MainWindow = XAML< "MainWindow.xaml">
[<STAThread>]
[<EntryPoint>]
let main argv =
Application().Run(MainWindow().Root)
Creating basically empty App.xaml and starting like this:
module main
open System
open FsXaml
type App = XAML<"App.xaml">
[<STAThread>]
[<EntryPoint>]
let main argv =
App().Root.Run()
fixed it. If anyone knows the explanation for this, don't hesitate to provide it.
What am I doing wrong?
The problem is that there is no SynchronizationContext in place when you construct your ViewModel layer, which means that the internal code that pushes things back to the UI context don't work properly.
You can work around this by adding the following at the beginning of your entry point, before you call Application.Run():
if SynchronizationContext.Current = null then
DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher)
|> SynchronizationContext.SetSynchronizationContext
This will make sure the Dispatcher is created and a valid SynchronizationContext is installed, and will likely fix the issue for you.
I used asynchronous commands, but this problem never arose. I tried to reproduce your code - everything is working fine. Are you sure you gave complete code?
Try to run the code:
.xaml:
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<Button Content="start async worker" Command="{Binding StartAsyncCommand}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5" />
<TextBlock Text="{Binding Count}" Margin="5" HorizontalAlignment="Right" VerticalAlignment="Top"></TextBlock>
</Grid>
ViewModel:
type MainViewModel() as me =
inherit ViewModelBase()
let count = me.Factory.Backing(<# me.Count #>, 0)
member __.StartAsyncCommand = me.Factory.CommandAsync(fun _ -> async { count.Value <- count.Value + 1 })
member __.Count with get() = count.Value
About the differences between
let dosomething _ = async { return () }
member __.StartAsyncCommand = me.Factory.CommandAsync(dosomething)
and :
member __.StartAsyncCommand = me.Factory.CommandAsync(fun _ -> async { return () } )
look this answer:
https://chat.stackoverflow.com/transcript/message/26511092#26511092
The easy workaround is to use interaction triggers:
<Button>
<ia:Interaction.Triggers>
<ia:EventTrigger EventName="Click">
<fsx:EventToCommand Command="{Binding StartAsyncCommand}" />
</ia:EventTrigger>
</ia:Interaction.Triggers>
</Button>

InteractionRequest CustomPopupWindow does not resize

Using a prism Interactionrequest together with a CustomPopUpWindow I have the Problem, that the custom popup window does not resize.
Calling the interaction the first time, it sizes its self to the content correctly, but if I call it again, it kind of memorizes this size and does not change size according to its changed content.
Is this a known issue, or am I doing things wrong?
Regards
Rainer
<i:Interaction.Triggers>
<InteractionRequest:InteractionRequestTrigger SourceObject="{Binding ImportConfirmation, Mode=OneWay}">
<InteractionRequest:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True">
<InteractionRequest:PopupWindowAction.WindowContent>
<Views:ImportMachineDefintionConfirmationView/>
</InteractionRequest:PopupWindowAction.WindowContent>
</InteractionRequest:PopupWindowAction>
</InteractionRequest:InteractionRequestTrigger>
<InteractionRequest:InteractionRequestTrigger SourceObject="{Binding DeleteMachineDefinitionConfirmation, Mode=OneWay}">
<InteractionRequest:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True" >
<InteractionRequest:PopupWindowAction.WindowContent>
<Views:DeleteMachineDefinitionConfirmationView/>
</InteractionRequest:PopupWindowAction.WindowContent>
</InteractionRequest:PopupWindowAction>
</InteractionRequest:InteractionRequestTrigger>
</i:Interaction.Triggers>
private void DeleteMachineDefinitionCommandExecute(IVersionAwareMachineDefinition machineDefinition)
{
var deleteConfirmation =
this.unityContainer.Resolve<IDeleteMachineDefinitionConfirmationViewModel>(
new ParameterOverride("machineDefinitionToDelete", machineDefinition));
this.DeleteMachineDefinitionConfirmation.Raise(
deleteConfirmation,
_ =>
{
if (!_.Confirmed)
{
return;
}
this.repository.DeleteMachineDefinition((MachineType)machineDefinition.MachineTypeId, machineDefinition.MachineNumber);
this.MachineDefinitions =
new ObservableCollection<IVersionAwareMachineDefinition>(this.repository.GetKnownVersionAwareMachineDefinitions());
this.SelectedMachineDefinition = null;
});
}

freeze wpf app during update binding source

I created thumbnails based on ListView control. On ListView.ItemSource I bind ObservableColletion<Photos> Photos{get;set}.
I create thumbnail images in another threads also in parallel way.
I simplified my code.
public class ThumbnailCreator
{
public static List<Photos> CreateThumbnailImage(List<Photos> photos)
{
var thumbnails = new List<Photos>();
Parallel.ForEach(photos, photo =>
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.DecodePixelHeight = 128;
bitmap.DecodePixelWidth = 128;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.CreateOptions = BitmapCreateOptions.DelayCreation;
bitmap.UriSource = new Uri(photo.FullPath);
bitmap.EndInit();
if (bitmap.CanFreeze)
bitmap.Freeze();
thumbnails.Add(new Photos{ThumbnailImage = bitmap});
});
return thumbnails;
}
}
Problem is here:
//I break binding before I start refreshing thumbnails
this.Thumbnails.ItemsSource = null;
//load files from folder
List<Photos> photos = _fileManager.LoadFromDir(folderBrowserDialog.SelectedPath);
//create thumbnail images in another threads, not on UI
List<Photos> thumbnails = ThumbnailCreator.CreateThumbnailImage(photos);
//create new source
Photos = new ObservableCollection<Photos>(thumbnails);
//reenable binding, this part of code cause that UI free
this.Thumbnails.ItemsSource = Photos;
When I reenable binding UI freeze, I tried use dispatcher but result is same UI freeze.
this.Dispatcher.Invoke(DispatcherPriority.SystemIdle, new Action(() =>
{
Photos = new ObservableCollection<Photos>(thumbnails);
this.Thumbnails.ItemsSource = Photos;
}));
How can I avoid freeze UI?
EDITED:
I edited my code based on Dean K. advice. I dont break bind before update source of listview.
I updated source of ListView.ItemSource via Dispatcher:
Sync Invoke:
App.Current.Dispatcher.Invoke(new Action(() =>
{
thumbnails.Add(new Photos { ThumbnailImage = bitmap });
}), DispatcherPriority.ContextIdle);
Result - UI behavior.
Images are being added continuously but if collection contains more than 500 images at the and WPF window freezes. For example it is not possible move window, scroll listview.
Async Invoke
App.Current.Dispatcher.InvokeAsync(new Action(() =>
{
thumbnails.Add(new Photos { ThumbnailImage = bitmap });
}), DispatcherPriority.ContextIdle);
Result - UI behavior.
At start app freezes but after several seconds images are being added continously and also is it possible move window, scroll listview.
So my question is what is root of problem that app freezes ? How can I avoid this behaviour. I upload sample application.
Don't break the binding before adding items to the ObservableCollection.
Bind Thumbnails.ItemsSource to Photos OC and than on another thread load and add items to Photos OC. That way your UI will not freeze.
You might want to use the multithreaded ObservableColleciton you can find on code project. Search for ObservableCollectionMt...

Adding a wpf button created in background thread to Mainwindow

Here's my scenario : I have a simple wpf window with a button. When the user clicks on the button, I want to create another window (let's call it child window) and then create a wpf button on a background thread, add it to the child window and show the child window. Here's the code for this:
Button backgroundButton = null;
var manualResetEvents = new ManualResetEvent[1];
var childWindow = new ChildWindow();
manualResetEvents[0] = new ManualResetEvent(false);
var t = new Thread(x =>
{
backgroundButton = new Button { Content = "Child Button" };
childWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => childWindow.MainPanel.Children.Add(backgroundButton)));
manualResetEvents[0].Set();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
WaitHandle.WaitAll(manualResetEvents);
childWindow.ShowDialog();
When I call the ShowDialog(), I get this error "The calling thread cannot access this object because a different thread owns it.". I know that this error is because the button added to the child window is created on a background thread and hence we get this error. Question is: How do I get past this error and still have my button to be created on the background thread
You must use Dispatcher every time, when you want to access Parent's window from another thread. I see in action of your thread , you use backgroundButton . Because of that, you must do whatever with your button inside Dispathcer.BeginIvoke statement
[EDIT]
Change Thread action to this
var t = new Thread(x =>
{
backgroundButton.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => backgroundButton = new Button { Content = "Child Button" }));
childWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => childWindow.MainPanel.Children.Add(backgroundButton)));
manualResetEvents[0].Set();
});
I wrote this according to your code.I doesn't check you code, but hope its right.

Can I put a Button in a RichTextBox in Silverlight 4?

I would like to allow users to put a System.Windows.Controls.Button in the System.Windows.Controls.RichTextBox. The button would do a pre-defined thing.
I figured out how to do this. It's called an InlineUIContainer you can do something like this to get it working. Although it doesn't save it into the Xaml
var p = new Paragraph();
var inlineUIContainer = new InlineUIContainer() { Child = new Button() { Content = "This is a Button!" } };
p.Inlines.Add(inlineUIContainer);
_richTextBox.Blocks.Add(p);

Resources