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.
Related
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
}
What I want to do:
I want do change a background color of a button from anywhere in my code (other classes Xamarin Forms). For example a button A in Page A changes the color of button B in Page B
on Windows you can use the MethodInvoker Delegat which isn't available on Android/iOS.
Can you give me a hint?
I tried it with the text of the buttons before with the MVVM approach.
in my PageB.xaml:
<Button Name="Button_B" Text="{Binding MyText}"/>
in my PageB.cs in public PageB
BindingContext = new MVVMPageB();
in my MVVMPageB.cs
private string myText;
public string MyText
{
get => mytring;
set
{
mystring = value;
PropertyChanged?
.Invoke(this, new PropertyChangedEventArgs(MyText)));
}
if i call:
MyText("Test");
in my MVVMPageB.cs it works fine. but i dont know how to access this from anywhere else.
i tried:
var Testobjekt = new MVVMPageB() //pretty sure thats not correct
Testobjekt.MyText("Test"); //wont work
Technique 1
This is a Singleton pattern for MVVMPageB.
This works if you never have two "Page B"s. IF there is a Page B on the navigation stack (so you can "Go Back" to it), and you display ANOTHER Page B, THEN this will not work well, because both Page B's will refer to the SAME MVVMPageB instance.
public class MVVMPageB : ...
{
// "Singleton": This is the only instance of MVVMPageB.
private static MVVMPageB _It;
public static MVVMPageB It
{
if (_It == null)
_It = new MVVMPageB();
return _It;
}
// Your constructor.
// It is private; only used via "It" getter above.
private MVVMPageB()
{
...
}
}
Code in another class, to access a member of the MVVMPageB.
MVVMPageB.It.MyText("Test");
Replace this code:
BindingContext = new MVVMPageB();
With this code:
BindingContext = MVVMPageB.It;
NOTE: Because MVVMPageB.It is static, if you go to Page B a second time, it will show the values you had last time (within the same app session).
Technique 2
A more robust approach, which works even if you create another Page B, requires having some way to pass the current instance of MVVMPageB to MVVMPageA or to PageA.
A complete example depends on exactly how/where you create each page. But this shows the idea.
public class MVVMPageB : ...
{
// Your constructor. Add parameters as needed.
public MVVMPageB()
{
...
}
}
public partial class PageB : ...
{
// Convenience property - our BindingContext is type MVVMPageB.
public MVVMPageB VMb => (MVVMPageB)BindingContext;
...
}
public class MVVMPageA : ...
{
// This is here, so both MVVMPageA and PageA can find it.
public MVVMPageB VMb;
}
public partial class PageA : ...
{
// Convenience property - our BindingContext is type MVVMPageA.
public MVVMPageA VMa => (MVVMPageA)BindingContext;
...
}
Code that creates Page B and then Page A:
var pageB = new PageB();
var pageA = new PageA();
// Tell MVVMPageA about MVVMPageB.
pageA.VMa.VMb = pageB.VMb;
Methods in MVVMPageA can now access members of MVVMPageB:
VMb.MyText("Test");
Methods in PageA can now access members of MVVMPageB:
VMa.VMb.MyText("Test");
NOTE: In this dynamic technique, if you go to Page B a second time (in the same app session), it will have a new instance of MVVMPageB.
You need a singleton viewModel for this use. I usually use one for the navbar.
So every scoped page viewModel references the singleton global viewModel inside:
PageAViewModel has property NavBarModel
PageBViewModel has property NavBarModel
and so on..
So it's obvious your button will be bind as
BackgroundColor={Binding NavBarModel.ActionColor} on every different page.
Now to have a singleton and obtain its reference i can see two ways: dependency injection (DI) or single instance creation. You can read a lot about DI on the net, while for a simple case you can have a single instance model with a prop like:
private NavBarModel _current;
public NavBarModel Current
{
get
{
if (_current == null)
_current = new NavBarModel();
return _current;
}
}
then in pages viewModels constructor set NavBarModel = NavBarModel.Current;
You would need DI though to reference more models inside your singleton, or/and make your code more reusable. Good luck.
I have a class named as pendingData with a list of objects and it instantiated with the start of the application and will remain as long as application runs. But I have to change add objects to the list. How can I access that object in other view without passing the object in the constructor?
So, is there a broadcasting method or any way to do that?
And pendingData class is instantiated only once.
To ensure you only get one instance of your object you could use the singleton pattern like this
public class Singleton
{
private static Singleton instance;
private Singleton() {}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
You'll notice the constructor is private so you must obtain an instance through the Instance method. You'll also notice that method only creates an instance of the object if it doesn't exist.
You could use the same Singleton object for all your views knowing that it'll be the same one and therefore the same data.
Alternatively, you could just declare it in a central location, you main window's viewmodel perhaps, and then everything else could access it from there.
As for updating it you could pass a reference to your object to each place that it's used and then update it directly. Or you could do something with events like this
In your view's viewmodel
public static event EventHandler MyEvent;
private void OnMyEvent()
{
if (MyEvent != null)
{
MyEvent(this, new EventArgs());
}
}
In the location where your data object is, perhaps your main window's view model
MyView.MyEvent += delegate
{
// Update your data
};
If you can't have multiple views open and/or don't want your views to respond to data changes once opened then this is probably enough. However, if you want your views to respond to data in real time you could do something with events so one view can tell another view that the data has changed and that it needs to update.
I am developing a WPF application. I need some variables/information not to destroy until user closes that application. Which method is best? Static Class with static variables? Moreover what is the best practice in this scenario?
I belive what you can do is to write a class which would hold variables for you as the session object does in ASP .net . You can do something like
public static class ApplicationState
{
private static Dictionary<string, object> _values =
new Dictionary<string, object>();
public static void SetValue(string key, object value)
{
if (_values.ContainsKey(key))
{
_values.Remove(key);
}
_values.Add(key, value);
}
public static T GetValue<T>(string key)
{
if (_values.ContainsKey(key))
{
return (T)_values[key];
}
else
{
return default(T);
}
}
}
To save a variable:
ApplicationState.SetValue("MyVariableName", "Value");
To read a variable:
MainText.Text = ApplicationState.GetValue<string>("MyVariableName");
This would be accesses all through yuor application and would remain in memory throughout.
In this situation, you can use a static Class with static fields. He is never released, it doesn't have any destructors, and is not involved in garbage collection.
If you want to a normal class stayed alive, you can use the method GC.KeepAlive():
SampleClass sample = new SampleClass();
//... Somewhere in the end ...
GC.KeepAlive(sample);
Here, KeepAlive() creates a reference to your instance of the class in order to garbage collection think, that he still in use in your application. The purpose of the KeepAlive() is to ensure the existence of a reference to an object that is at risk of being prematurely reclaimed by the GC.
Quote from MSDN:
This method references the obj parameter, making that object ineligible for garbage collection from the start of the routine to the point, in execution order, where this method is called. Code this method at the end, not the beginning, of the range of instructions where obj must be available.
The KeepAlive method performs no operation and produces no side effects other than extending the lifetime of the object passed in as a parameter.
Alternatively, information can be stored in the WPF-application settings. Especially if the information is important and should not be lost after system failure or reboot.
Settings located approximately here Project -> Properties -> Parameters. Example with setting new value:
MyProject.Properties.Settings.Default.MyButtonColor = "Red";
Saving is performed as follows:
MyProject.Properties.Settings.Default.Save();
It also possible using Binding with properties, indicating class of the settings in Source:
xmlns:properties="clr-namespace:MyProject.Properties"
<TextBlock Text="{Binding Source={x:Static properties:Settings.Default},
Path=MyButtonColor,
Mode=TwoWay}" />
For more information about using settings in WPF, please see:
User settings in WPF
A configurable Window for WPF
Saving user color settings of a clicked Button in WPF
You can also create static class and reference it in xaml like this:
namespace MyNamespace
{
public static class Globals
{
public static double SomeVariable { get { return 1.0; } }
}
}
Then access it from xaml like this:
<UserControl Width="{x:Static globals:Globals.SomeVariable}" />
where globals is defined at top top of your xaml like following:
<Window x:Class="MyNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:globals="clr-namespace:MyNamespace">
</Window>
Consider this code:
class GameEventsManager
{
public void StartGameEvent(GameEvent TheGameEvent)
{
SubscribeToGameEvent(TheGameEvent);
TheGameEvent.Begin();
UnsubscribeToGameEvent(TheGameEvent);
}
private void SubscribeToGameEvent(GameEvent TheGameEvent)
{
TheGameEvent.OnPlaySound += OnPlaySound;
TheGameEvent.OnShowWrittenItem += OnShowWrittenItem;
...
}
private void UnsubscribeToGameEvent(GameEvent TheGameEvent)
{
TheGameEvent.OnPlaySound -= OnPlaySound;
TheGameEvent.OnShowWrittenItem -= OnShowWrittenItem;
...
}
}
A GameEvent is a class that basically does this: when Begin() gets called, it raises events that get passed to the GameEventManager, so that it may "make" the appropriate changes to the game environment (this is by further propagating the events to the objects that are responsible for executing each particular instruction, like in the Observer pattern).
Now take into consideration that all of my InventoryItems (can trigger events, such as OnConsume, OnUse) are static fields in their particular classes. Although this may seem a bit rough around the edges, I feel that being able to do:
AddItem(WrittenItems.NoteFromKing) //NoteFromKing is a static field in WrittenItems
makes things a lot simpler, and it's a welcome sight considering I'm working on a quite complex game.
This, however, makes it very hard for me to list ALL of the game's items somewhere, in case this would be needed. Which brings us to my question:
A LevelManager, that manages things such as when the player interacts with a particular item in the level, tells the GameEventsManager to run a particular GameEvent, if required. The GameEventsManager then subscribes to the GameEvent, starts it, and then unsubscribes. Should I expect to see noticeable performance issues while following this subscribe/run/unsubscribe pattern? In the end, the manager might subscribe/unsubscribe to about 20 events inside GameEvent.
In case the subscribe/unsubscribe mechanism is slow, I could make a single subscribe process that runs at game initialization, but that would force me to build an extra structure, to list all of the items.
So, in short, I'd like to know if I should be expecting considerable slowdowns from this kind of implementation. Or more exactly, if subscribing to about 20 events, and then unsubscribing from them is considerably slow.
Language is C#, using .NET 2.0 subset under Unity 4.
This, however, makes it very hard for me to list ALL of the game's items somewhere
Why so? You could create an ItemManager (which is a singleton):
public class ItemManager
{
private static volatile ItemManager _instance;
private static object syncRoot = new Object();
private ObservableCollection<ItemBase> _registeredItems = new ObservableCollection<ItemBase>();
private ItemManager()
{
}
public ItemManager Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new ItemManager();
}
}
return instance;
}
}
public void RegisterItem(ItemBase item)
{
_registeredItems.Add(item);
// Do some stuff here, subscribe events, etc.
}
public void UnregisterItem(item)
{
// Do some stuff here, unregister events, etc.
_registeredItems.Remove(item)
}
}
Afterwards you make all item classes derive from a class called "ItemBase". And in ItemBases Constructor you call this:
ItemManager.Instance.RegisterItem(this);
So you don't have to add every single item manually. For more information about the singleton pattern, take a look here: http://msdn.microsoft.com/en-us/library/ff650316.aspx.
A little benefit of this is also, that you can implement a general communication between the GameManager and the ItemManager.