I have created a custom FrameWorkElement ( Battery.cs ) to represent the data to the user in the UI. Within the Battery.cs class I had several dependencyProperties so the UI could monitor the various changes and re-render the object upon changes.
I placed that ObservableCollection within my MainWindowViewModel.cs, which was bound to the main view through a ListBox.
Everything was working properly however this was only for testing as I needed to move the collection down into another class which was going to manage / update the batteries. This management was going to happen asynchronously and thus I was running into a lot of problems with the DependencyProperties calls within the Battery.cs class as they were on the UI thread and not the management/process thread.
So I removed the DependencyProperties, and tried to move the DependencyProperty up to the MainWindowViewModel.cs. Now I am not getting errors about which thread has ownership and I can see that the Batteries in the ObservableCollection are being updated. However the OnRender method is never being called by the UI. So the Batteries are never being rendered/shown anymore.
Here is the code for the DependencyProperty in the MainWindowViewModel.cs
public static readonly DependencyProperty batteriesProperty = DependencyProperty.Register(
"Batteries",
typeof(ObservableCollection<Battery>),
typeof(MainWindow),
new UIPropertyMetadata(new ObservableCollection<Battery>()));
public ObservableCollection<Battery> Batteries
{
get { return tbModel.Modules[0].batteries; }
}
I think my main problem may be in this line
new UIPropertyMetadata(new ObservableCollection<Battery>()));
However I can't seem to figure out what it should be, or how to adjust the code such that the UI does update the graphics once I have called InvalidateVisual within the Battery.cs class.
public void UpdatePacket(Packet packet)
{
packet= packet;
Voltage = packet.Voltage;
InvalidateVisual();
}
The InvalidateVisual() method is executing however the OnRender override is never being executed.
Making ViewModel derived from DependecyObject is pointless. This only complicates and confuses the implementation.
The Batteries property of type ObservableCollection must be a regular CLR read-only property in the ViewModel.
public ObservableCollection<Battery>() Batteries {get;}
= new ObservableCollection<Battery>();
If an instance of the ViewModel exists in the entire session of the Application, then in the ViewModel constructor, synchronize the bindings to this collection.
protected static readonly Dispatcher Dispatcher = Application.Current.Dispatcher;
public MainWindowViewModel()
{
if (Dispatcher.CheckAccess())
{
BindingOperations.EnableCollectionSynchronization(Batteries, ((ICollection)Batteries).SyncRoot);
}
else
{
Dispatcher.Invoke(()=>BindingOperations.EnableCollectionSynchronization(Batteries, ((ICollection)Batteries).SyncRoot));
}
// Some Code
}
If the instances of the ViewModel can be destroyed, replace each other, then the synchronization of the bindings retains a reference to the instance of the ViewModel and therefore this instance will not be deleted by the GC. Also, the synchronization of bindings does not always provide thread safety for working with a collection.
In these cases, you are not using BindingOperations.EnableCollectionSynchronization ().
But instead, you always work with the collection only in the Dispatcher thread.
protected static readonly Dispatcher Dispatcher = Application.Current.Dispatcher;
public MainWindowViewModel()
{
// Some Code
}
... SomeMethod(...)
{
// Some Code
if (Dispatcher.CheckAccess())
{
Batteries.Add(...);
}
else
{
Dispatcher.Invoke(()=>Batteries.Add(...));
// Or
Dispatcher.InvokeAsync(()=>Batteries.Add(...));
}
// Some Code
}
Related
Is there any way to use binding which directly interacts with methods to get a value and set its value?
I have a class which has methods instead of properties
public class Foo
{
public object GetProp1()
{
//some logic
return someObject;
}
public object GetProp2()
{
//some logic
return someObject;
}
public object SetProp1(object someObject)
{
//some logic
}
public object SetProp2(object someObject)
{
//some logic
}
}
To achieve data binding, I'm declaring properties for each function and calling model's method
public class FooViewModel
{
Foo foo = new Foo();
public object Prop1
{
get => foo.GetProp1();
set => foo.SetProp1(value);
}
public object Prop2
{
get => foo.GetProp2();
set => foo.SetProp2(value);
}
}
Problem is if I have 50 methods, in Foo, I need to create approx 50 properties in ViewModel. Is there any other way to eliminate properties in ViewModel just to bind with View?
Something like this:
Textbox will set its value and Label will display
<TextBox Text="{MethodBinding MethodName=foo.SetProp1}"/>
<Label Content="{MethodBinding MethodName=foo.GetProp1}"/>
You can technically manage to bind to methods if you really put your mind to it but I don't think that's a very helpful answer.
In any commercial team I've worked in, doing this would see your MR/PR rejected. It is widely considered bad practice.
What I would recommend is make those properties regular properties raising property changed. Get your data for them in async tasks.
If you define an interface you can then give all your Getting-Data Tasks the same name and generically invoke them on any viewmodel you instantiate.
In some real world code I have, I call this Task Initiate.
interface IInitiatedViewModel
{
Task Initiate();
}
Here's one such task ( slightly simplified ) out one of my viewmodels:
public async Task Initiate()
{
DateFrom = LastApril();
Transactions = await repository.GetFlattenedTransactionsAsync(DateFrom, DateTo);
}
Transactions is a public property a Datagrid is bound to.
Process is therefore to instantiate my ViewTransactionsViewModel. It comes out a DI container but let's not digress too far.
I can present that viewmodel to the UI and it is templated out into a View.
It has no data initially.
Then await Initiate.
That sets my properties with data.
In more complicated scenarios, Initiate could start multiple threads with Tasks. Arranging data might be quite expensive so a Task (or many ) could be started on another thread.
A common variation is to have a base viewmodel which exposes an IsBusy bool. That is used to flag commands and drive a busy spinner. That would initially be true. Your view would render with a spinner. The last line of Initiate would be to set IsBusy false. The spinner would disappear and the date would be rendered.
I have the following Singleton Pattern for the ViewModel of my Options:
private static volatile GeneralOptionsViewModel instance;
private static object syncRoot = new object();
/// <summary>
/// threadsave singleton
/// </summary>
public static GeneralOptionsViewModel Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new GeneralOptionsViewModel();
}
}
return instance;
}
}
In my XAML I have a color picker from the extended toolkit package:
<xctk:PropertyGridEditorColorPicker Background="Transparent" Name="face"
Margin="5,0" Width="50" BorderBrush="#32FFFFFF" BorderThickness="1"
SelectedColor="{Binding FaceRectColor, Mode=OneWayToSource,
UpdateSourceTrigger=PropertyChanged}"/>
As you can see it is bound to FaceRectColor property of the GeneralOptionsViewModel class which is defined like follows.
Within the setter there is a conversion to MCvScalar (also a property of the same class), the format I later need for my application:
public Color FaceRectColor
{
get
{
return faceRectColor;
}
set
{
if (faceRectColor != value)
{
faceRectColor = value;
FaceRectColorScalar = new MCvScalar(value.B, value.R, value.G, value.A);
SetProperty(ref faceRectColor, value);
}
}
}
My problem now is, that the binding works and also the correct values are written to the variable, however when I call the singleton with the property from a different class - and from a different thread - it always shows zero for all color channels. However, if I break the program directly within the singleton class I can see the correct values. AFAIK the singleton should be threadsafe, so I'm looking for the reason of this behavior.
My guess is some threading issue, since other properties from the singleton class are displayed correctly, but they are only called in the main thread.
Edit: In my case all property values of the singleton class are set before the worker thread is active. This means no changes during the time the worker thread is active.
Edit II: Here is the complete project for code evaluation.
In the class CameraViewModel in line 202 is the relevant call for a function, where I want to pass the values from the singleton.
Your "singleton" contains a public constructor which effectively makes it a non-singleton. And you are not binding to the singleton in your GeneralOptionsView.
If you really want GeneralOptionsViewModel to be a singleton, you should implement it like this:
public sealed class GeneralOptionsViewModel : ViewModelBase
{
private static readonly GeneralOptionsViewModel _instance = new GeneralOptionsViewModel();
private GeneralOptionsViewModel()
{
GetAvailableCameraList();
DetectorTypeList = new List<string>() { "Cascade Detector" };
SelectedDetectorTypeIndex = 0;
}
public static GeneralOptionsViewModel Instance => _instance;
//...
}
You should then set the DataContext of your view to the singleton:
<Grid DataContext="{Binding Source={x:Static local:GeneralOptionsViewModel.Instance}}">
When your property changes and it does so on a different thread, the calls that are made to notify everybody (in particular the UI) of this change are running in the calling thread. Accessing the UI in a thread that is not the UI thread is a bad idea. It might sometimes work. But it will fail sooner or later.
The solution to your current problem is changing the property in the UI thread.
That said, maybe you should think about whether you need a Singleton. That's a huge red flag that something is wrong with the structure of your program. You don't need a Singleton. Nothing bad would happen if some other context had a second settings viewmodel. You seem to want a Singleton because it's so nice and easy to have a global variable. That is the drawback of a Singleton. It's disadvantage that you buy into because you need something from this pattern. If you find you are using this pattern only because it's disadvantage gives you an excuse to have a global variable, you are doing patterns wrong. It's an anti-pattern.
After I tried lots and lots of solutions I couldn't solve this problem by any means so I started to believe that there is no solution for this problem.
I have an object that contains complex attributes. E.g: List<SomeComplexObject>. I am running a method from this class on a worker thread to keep the GUI running until the worker thread finishes. When it finishes execution, I want to use the attributes of these objects to update GUI let's say I want to use List<SomeComplexObject> looping through this list and update the GUI. But each time I try to access this list the debugger throws an InvalidOperationException: The calling thread cannot access this object because a different thread owns it.
I tried to make all attributes of this class volatile but with no hope I also used Lazy<T> class approach to solve but the same problem occurs.
Class that contain the worker function:
public class MainModules
{
#region Attributes
public VIDEO video;
public string VideoPath
{
get;
set;
}
LowLevelModule lowLevelOutput;
//this list that I want to use to Update GUI
public volatile List<FaceRecognitionModule> faceModuleOutput;
//worker function running on different thread
public void RunMainModules()
{
//some complex work to set the class attributes
}
}
Thread creation in GUI class
private void RunMainModules_BtnClick(object sender, RoutedEventArgs e)
{
// MainModule = new MainModules(mainModuleObj, Inpath, lif, keyframefolderpath, trdbpath, labelspath, rrankspath, alignmatpath, 11, 10);
this.LazyMainModule = new Lazy<MainModules>(this.InitLazyMainModule);
MainModuleThread = new Thread(this.RunMainModules);
MainModuleThread.Start(MainModule);
}
public MainModules InitLazyMainModule()
{
return new MainModules(mainModuleObj, Inpath, lif, keyframefolderpath, trdbpath, labelspath, rrankspath, alignmatpath, 11, 10);
}
public void RunMainModules(Object obj)
{
//MainModules mm = obj as MainModules;
MainModules mm = LazyMainModule.Value;
mm.RunMainModules();
this.Dispatcher.Invoke((Action)(() =>
{
this.InitSpeechRec_Btn.IsEnabled = true;
}));
}
When I try to access faceModuleOutput in class MainModules from GUI I got InvalidOperationException.
Image img = new Image();
//InvalidOperationException occurs here
img.Source = LazyMainModule.Value.faceModuleOutput[0].keyframes[1].keyframe;
To brief this post:
I want to access an object instantiated by a background thread from main thread but it throws
InvalidOperationException : The calling thread cannot access this object because a different thread owns it.
A UI control needs to be created/modified from the GUI Thread. Doing otherwise is illegal.
It seems that the MainModuleThread is (at least) creating and modifying an Image . This should be done in the GUI Thread (the one that called RunMainModules_BtnClick)
You cannot modify or even access pretty much anything that relates to the UI thread from another thread. This can get pretty extreme/annoying sometimes because you can't even get the value in a textbox or check if a checkbox is checked or not. If you want to perform an action on an object owned by the UI thread you need to invoke the UI thread to do it.
UIObject.Dispatcher.Invoke(() => {
//[Perform your action in here]
});
Finally I found the solution ... Class BitmapImage is thread-affine so it can't be accessed by multiple threads you need first to make it opened for reading only closed for writing so the compiler can guarantee that no threads will modify it's content
So the solution ... :
//keyframe here is a BitmapImage so on creation we must call keyframe.Freeze()
LazyMainModule.Value.faceModuleOutput[0].keyframes[1].keyframe;
class KeyFrame:
public class KeyFrame
{
public volatile BitmapImage keyframe;
public volatile List<string> personsNames;
public volatile List<string> categories;
public KeyFrame(BitmapImage keyframe, List<string> personsNames, List<string> categories)
{
this.keyframe = keyframe;
//here we call Freeze funcition on creation to make it modifiable
this.keyframe.Freeze();
this.personsNames = personsNames;
this.categories = categories;
}
}
I have a WPF User Control representing a Circular Gauge with some properties in it. When I Directly use it in my application everything works just fine but when I load it in Expression Blend in order to test its properties and simulate the expected animations it works expect collection dependency properties. The problem is when I use Expression Blend to add some item to the collection property
The “SetValue” is not called! What am I doing wrong?
public static readonly DependencyProperty RangesProperty =
DependencyProperty.Register("Ranges ", typeof(CircularRangeInfoList), typeof(UserControl1), new FrameworkPropertyMetadata(new CircularRangeInfoList()));
[Category("Test Collection")]
public CircularRangeInfoList Ranges
{
get { return (CircularRangeInfoList)GetValue(RangesProperty); }
set { SetValue(RangesProperty, value); }
}
public class CircularRangeInfoList : ObservableCollection<CircularRangeInfo>
{
public CircularRangeInfoList()
{
}
}
That's because you are not setting the property, you are altering the collection (to which the property is already set). If you need to watch for changes in the collection, then you should add a handler for the CollectionChanged event.
See this question for more information.
When you register your dependency property, specify a static property changed callback. This will be invoked when your dependency property is changed. Within this callback delegate, you should attach an event handler to the CollectionChanged event of your custom collection.
I have a lot of existing business objects with many properties and collections inside which I want to bind the userinterface to. Using DependencyProperty or ObservableCollections inside these objects is not an option. As I know exactly when I modify these objects, I would like to have a mechanism to update all UI controls when I do this. As an extra I also don't know which UI controls bind to these objects and to what properties.
Here is a simplified code of what I tried to do by now:
public class Artikel
{
public int MyProperty {get;set;}
}
public partial class MainWindow : Window
{
public Artikel artikel
{
get { return (Artikel)GetValue(artikelProperty); }
set { SetValue(artikelProperty, value); }
}
public static readonly DependencyProperty artikelProperty =
DependencyProperty.Register("artikel", typeof(Artikel), typeof(MainWindow), new UIPropertyMetadata(new Artikel()));
public MainWindow()
{
InitializeComponent();
test.DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
artikel.MyProperty += 1;
// What can I do at this point to update all bindings?
// What I know at this point is that control test or some of it's
// child controls bind to some property of artikel.
}
}
<Grid Name="test">
<TextBlock Text="{Binding Path=artikel.MyProperty}" />
</Grid>
This is, I tried to pack my object into a DependencyProperty and tried to call UpdateTarget on this, but didn't succeed.
What could I do to update the corresponding UI controls?
I hope I described my situation good enough.
Using INotifyPropertyChanged is a good alternative to DependencyProperties.
If you implement the interface you can raise the PropertyChanged event with null as parameter to notify the UI that all properties changed.
(I'm going to assume you can't add INotifyPropertyChanged to your business objects either, and that you don't want to add another "view of the data model" layer of wrapper objects a la MVVM.)
You can manually update bound properties from their data source by calling BindingExpression.UpdateTarget().
myTextBlock.GetBindingExpression(TextBlock.TextProperty).UpdateTarget();
To update all bindings on a control or window, you could use something like this:
using System.Windows.Media;
...
static void UpdateBindings(this DependencyObject obj)
{
for (var i=0; i<VisualTreeHelper.GetChildrenCount(obj); ++i)
{
var child = VisualTreeHelper.GetChild(obj, i);
if (child is TextBox)
{
var expression = (child as TextBox).GetBindingExpression(TextBox.TextProperty);
if (expression != null)
{
expression.UpdateTarget();
}
}
else if (...) { ... }
UpdateBindings(child);
}
}
If you're binding a diverse set of properties then rather than handling them individually as above, you could combine the above with this approach to enumerate all dependency properties on a control and then get any BindingExpression from each; but that relies on reflection which will not be particularly performant.
As a footnote, you can also use BindingExpression.UpdateSource() if you want to explicitly write back to the data source. Controls usually do this anyway when their value changes or when they lose focus, but you control this and do it by hand with {Binding Foo, UpdateSourceTrigger=Explicit}.
As I know exactly when I modify these objects, I would like to have a mechanism to update all UI controls when I do this.
You will find that the most straightforward and maintainable way to deal with this is to implement view model classes for each class you want to present in the UI. This is probably true if you can modify the underlying classes, and almost certainly true if you can't.
You don't need to be using dependency properties for this. Dependency properties are only necessary on the targets of binding, which is to say the controls in the UI. Your view model objects are the source; they need only implement INotifyPropertyChanged.
Yes, this means that you will need to build classes that contain a property for each property exposed in the UI, and that those classes will need to contain observable collections of child view models, and you'll have to instantiate and populate those classes and their collections at runtime.
This is generally not as big a deal as it sounds, and it may be even less of one in your case. The traditional way to build a view model that's bound to a data model is to build properties like this:
public string Foo
{
get { return _Model.Foo; }
set
{
if (value != _Model.Foo)
{
_Model.Foo = value;
OnPropertyChanged("Foo");
}
}
}
But if, as you've claimed, you know when the objects are being updated, and you just want to push the updates out to the UI, you can implement read-only properties, and when the underlying data model gets updated make the view model raise PropertyChanged with the PropertyName property of the event args set to null, which tells binding, "Every property on this object has changed; update all binding targets."