How to add event listener to a enum type to check value changed in Unity3D, C# - events

Instead of checking every frame through the Update method, is there any event driven method to check if the value of an Enumerator as changed?
like:
public enum States{StateA, StateB,StateC};
States state;
void OnStateChanged(){
//do something..
}
Appreciate it.

You should use properties:
public enum States{StateA, StateB,StateC}
private States _state; //this holds the actual value
public States State { //this is public and accessible, and should be used to change "State"
get{
return _state;
}
set{
_state = value;
Debug.Log("Enum just got changed to: " + _state);
}
}

Related

MudBlazor dropdown not defaulting to value from database

I'm using Blazor with MudBlazor and I have the following form on an Edit page:
<EditForm Model="BookRequestVM" OnInvalidSubmit="InvalidBookRequest" OnValidSubmit="#ValidBookRequest">
...
<MudItem xs="12" sm="4">
<MudSelect T="BookType" Label="Book Type" #bind-Value="#BookRequestVM.BookType" #bind-SelectedValues="hashBookTypes" Required="true">
#foreach (var selectItem in BookTypes)
{
<MudSelectItem Value="#selectItem">#selectItem.TypeTitle</MudSelectItem>
}
</MudSelect>
</MudItem>
</EditForm>
...
#code {
public class BookType
{
public int BookTypeId { get; set; }
public string TypeTitle { get; set; }
}
public HashSet<BookType> hashBookTypes = new HashSet<BookType>();
...
protected override async Task OnInitializedAsync()
{
BookRequestVM = await _bookService.GetBookRequest(Id); // Fetch info from database
BookTypes = _bookService.GetBookTypes().ToList(); // Get all valid dropdown values
hashBookTypes = new HashSet<BookType>(BookTypes);
}
}
Because I'm pulling in existing data (this Book Type field is required when creating a book request), there will always be a Book Type associated with this Book Request. I see that the BookTypeVM was able to pull the Book Type in from the database in the service call, and on the valid submit method, it's bound and gets saved properly. It's just when it loads in, it doesn't default to the value that was saved to the database--only the first value from the dropdown list. Any ideas on what's going on here?
Is this a multi-select? If not then why are you setting #bind-SelectedValues="hashBookTypes". hashBookTypes comes from BookTypes which is a list of all the book types. I'm no expert on MudBlazor, but it appears your setting the selected values to the full list of values. Without MultiSelection="true" then I'm guessing its setting the current value to the first value in the list.
Your code has more problems than the one MrC found. You need to be very careful with using a POCO class in a select without overriding Equals() and GetHashCode() because the select uses a HashSet internally to find out which item is selected. Also, if you want it to convert the selected BookType to string it should override ToString().
Your BookType class should look like this:
public class BookType
{
public string Title { get; set; }
public override bool Equals(object other) {
return (other as BookType)?.Title == Title;
}
public override int GetHashCode()
{
return this.Title.GetHashCode();
}
public override string ToString() => Title;
}
And here is the Select to go with it:
<MudSelect T="BookType" Label="Book Type" #bind-Value="#RequestedBookType" Required="true">
#foreach (var selectItem in BookTypes)
{
<MudSelectItem Value="#selectItem">#selectItem.Title</MudSelectItem>
}
</MudSelect>
Here is a fiddle that demonstrates your code with above changes to make it work: https://try.mudblazor.com/snippet/mOwvPvbhHYHFBoiV
#bind-SelectedValues="hashBookTypes" was the culprit. This is used for multiselect. Unfortunately, I don't recall adding this code, but removing this resolved this issue.

Prism - moving data between viewmodels

I'm struggling to find the best implementation.
I'm using Prism and I have a View (ParentView), which has a small region within it. Depending on the item in a ddl, another smaller view (ChildView) gets injected into the region of the ParentView.
The ChildView will just have some properties which I would like to access from the ParentView.
So I realize I can use a Publish/Subscribe method to move data between viewmodels, but the issue is I have nothing to hang the Publish on. The view is made up of TextBoxes and no event triggers. The ChildView can be vastly different based on the selection of the ddl. I like the clean separation of each ChildView being it's own view injected inside the ParentView.
What is the best way to achieve this?
One solution can be to implement the interface INavigationAware in your viewmodels. After that you can use the methods onNavigatedFrom(), onNavigatedTo() and onNavigatingTo() to register your event.
EDIT:
If you want launch the event when a field in the child is changed you can do something like this:
private string _yourField;
public string YourField
{
get { return _yourField; }
set { SetProperty(ref _yourField, value);
//Here you can launch the event
}
}
In this case when YourField change the event is launched.
I tried a few implementations, but the one that worked was creating a singleton instance of the ChildView (childviewmodel) and then gaining access to the properties through the instance. It may not be pretty, but it works.
private static ChildViewModel _instance = new ChildViewModel ();
public static ChildViewModel Instance { get { return _instance; } }
#region Properties
private ChildModel _childModel= new ChildModel ();
public ChildModel _childModel
{
get { return _instance._childModel; }
set
{
SetProperty(ref _instance._childModel, value);
}
}
private string _childProperty1;
public string ChildProperty1
{
get { return _childProperty1; }
set
{
SetProperty(ref _childProperty1, value);
ChildModel.ChildProperty1= _childProperty1;
}
}
In reality - there were many childproperties. I only listed one for demo. And then I call it in ParentView
var _instance = ChildViewModel.Instance;
var _cm = _instance.ChildModel;
_parentModel = new ParentModel
{
Property1= ParentViewProperty1,
Property2= _cm.ChildProperty1,
};
Hope that helps someone else.

RxJava subscription does not unsubscribe correctly

I have an MVC application in which I have to update the view with the current value of a stream.
In the model I have this method:
public Observable<Integer> getStreamInstance(){
if(stream == null){
this.stream = Observable.create((Subscriber<? super Integer> subscriber) -> {
new HeartbeatStream(frequence,subscriber).start();
});
}
return stream;
}
which I use in the controller to get the stream. Then, in the controller I have these two methods:
public void start(){
this.sb = stream.subscribe((Integer v) -> {
view.updateCurrValue(v);
});
}
public void stop(){
this.sb.unsubscribe();
}
With the start method I simply update a label in the view with the current value.
This works fine until I try to stop the updating with the unsubscribing; infact, when I press the button "stop" in the view, the label keeps updating with the current value and, if I press "start" again, the label shows the values from two different streams, the one that I first created with the first "start" and the second that seems has been created with the second pressing of "start".
Where am I wrong?
EDIT:
public class HeartbeatStream extends Thread{
private Subscriber<? super Integer> subscriber;
private int frequence;
private HeartbeatSensor sensor;
public HeartbeatStream(int freq, Subscriber<? super Integer> subscriber){
this.frequence = freq;
this.subscriber = subscriber;
sensor = new HeartbeatSensor();
}
public void run(){
while(true){
try {
subscriber.onNext(sensor.getCurrentValue());
Thread.sleep(frequence);
} catch (Exception e) {
subscriber.onError(e);
}
}
}
This is the HeartbeatStream class. HeartbeatSensor is a class that periodically generates a value that simulates the heartbeat frequence.
I'm guessing you tried to periodically signal some event that triggers the screen update. There is an operator for that:
Observable<Long> timer = Observable.interval(period, TimeUnit.MILLISECONDS,
AndroidSchedulers.mainThread());
SerialSubscription serial = new SerialSubscription();
public void start() {
serial.set(timer.subscribe(v -> view.updateCurrValue(v)));
}
public void stop() {
serial.set(Subscriptions.unsubscribed());
}
public void onDestroy() {
serial.unsubscribe();
}
Observable by design unsubscribe your observer once that all items are emitted and onComplete callback is invoked.
Look this example https://github.com/politrons/reactive/blob/master/src/test/java/rx/observables/creating/ObservableSubscription.java
I guess you're not handling the unsubscribe - although I can't see what's going on in your HeartbeatStream class.
If you're creating an Observable with Observable.create then you need to handle unsubscribing explicitly with subscriber.isUnsubscribed().
Where possible use some of the utility methods to create an Observable - they handle this all for you eg Observable.just() or Observable.from().
If this doesn't help, please post your HeartbeatStream class.
See the the docs for more details:
https://github.com/ReactiveX/RxJava/wiki/Creating-Observables
https://github.com/ReactiveX/RxJava/wiki/Async-Operators

How do I tell ReactiveUI to update bindings (i.e. RaiseCanExecuteChanged())?

How do I tell ReactiveUI to update bindings?
Normally, I would do something like this:
string _instructorNameInput;
public string InstructorNameInput
{
get { return _instructorNameInput; }
set
{
this.RaiseAndSetIfChanged(ref _instructorNameInput, value);
Submit.RaiseCanExecuteChanged();
}
}
However, the following isn't supported:
Submit.RaiseCanExecuteChanged();
As a result, how can I force bindings to update based on the CanExecute predicate that my command relies on?
Updated:
public partial class FormViewModel : ReactiveObject
{
public FormViewModel()
{
Submit = ReactiveCommand.Create(this.WhenAnyValue(x => x.CanSubmit));
Submit.Subscribe(x => OnSubmit());
}
bool _canExecute;
public bool CanSubmit
{
get { return !GetUnsatisfied().Any(); }
set { this.RaiseAndSetIfChanged(ref _canExecute, value); } // Need to update view based on command.CanExecute state change
}
void OnSubmit()
{
var rosterInfo = new RosterInfo(new Course(CourseInput.Name),
new Instructor(InstructorNameInput, InstructorIdInput));
var repository = GetRepository();
repository.AddCourseInfo(rosterInfo);
Publish(REQUEST_NAVIGATION_TO_SUBMITION_CONFIRMATION, rosterInfo);
}
ObservableCollection<RequiredField> GetUnsatisfied()
{
RequiredFields.Clear();
RequiredFields = Review();
return RequiredFields;
}
}
Multiple issues:
Have a read at the fundamentals on ReactiveObject, in particular how "Read-Write Properties" are written.
In your case, this.WhenAnyValue(x => x.CanSubmit) will trigger a refresh on the command whenever the property CanSubmit changes, but this one never does, because you never call the setter (and the getter has an incorrect impl).
Currently, your method GetUnsatisfied() has "polling" semantics, which mean you need something to trigger this method to update your command. This isn't reactive at all, you should instead bind/listen to updates.
If there's no way for you to make your Review() logic reactive, then you may do something like:
var canExec = Observable.Timer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))
.Select(_ => !GetUnsatisfied().Any());
Submit = ReactiveCommand.Create(canExec);
Submit.Subscribe(x => OnSubmit());
Basically, having a timer to do your polling.
(But I strongly suggest going further down the reactive way)

LINQ-To-Sharepoint Multiple content types for a single list

I'm using SPMetal in order to generate entity classes for my sharepoint site and I'm not exactly sure what the best practice is to use when there are multiple content types for a single list. For instance I have a task list that contains 2 content types and I'm defining them via the config file for SPMetal. Here is my definition...
<List Member="Tasks" Name="Tasks">
<ContentType Class="LegalReview" Name="LegalReviewContent"/>
<ContentType Class="Approval" Name="ApprovalContent"/>
</List>
This seems to work pretty well in that the generated objects do inherit from WorkflowTask but the generated type for the data context is a List of WorkflowTask. So when I do a query I get back a WorkflowTask object instead of a LegalReview or Approval object. How do I make it return an object of the correct type?
[Microsoft.SharePoint.Linq.ListAttribute(Name="Tasks")]
public Microsoft.SharePoint.Linq.EntityList<WorkflowTask> Tasks {
get {
return this.GetList<WorkflowTask>("Tasks");
}
}
UPDATE
Thanks for getting back to me. I'm not sure how I recreate the type based on the SPListItem and would appreciate any feedback.
ContractManagementDataContext context = new ContractManagementDataContext(_url);
WorkflowTask task = context.Tasks.FirstOrDefault(t => t.Id ==5);
Approval a = new Approval(task.item);
public partial class Approval{
public Approval(SPListItem item){
//Set all properties here for workflowtask and approval type?
//Wouldn't there be issues since it isn't attached to the datacontext?
}
public String SomeProperty{
get{ //get from list item};
set{ //set to list item};
}
Linq2SharePoint will always return an object of the first common base ContentType for all the ContentTypes in the list. This is not only because a base type of some description must be used to combine the different ContentTypes in code but also it will then only map the fields that should definitely exist on all ContentTypes in the list. It is however possible to get access to the underlying SPListItem returned by L2SP and thus from that determine the ContentType and down cast the item.
As part of a custom repository layer that is generated from T4 templates we have a partial addition to the Item class generated by SPMetal which implements ICustomMapping to get the data not usually available on the L2SP entities. A simplified version is below which just gets the ContentType and ModifiedDate to show the methodology; though the full class we use also maps Modified By, Created Date/By, Attachments, Version, Path etc, the principle is the same for all.
public partial class Item : ICustomMapping
{
private SPListItem _SPListItem;
public SPListItem SPListItem
{
get { return _SPListItem; }
set { _SPListItem = value; }
}
public string ContentTypeId { get; internal set; }
public DateTime Modified { get; internal set; }
public virtual void MapFrom(object listItem)
{
SPListItem item = (SPListItem)listItem;
this.SPListItem = item;
this.ContentTypeId = item.ContentTypeId.ToString();
this.Modified = (DateTime)item["Modified"];
}
public virtual void MapTo(object listItem)
{
SPListItem item = (SPListItem)listItem;
item["Modified"] = this.Modified == DateTime.MinValue ? this.Modified = DateTime.Now : this.Modified;
}
public virtual void Resolve(RefreshMode mode, object originalListItem, object databaseObject)
{
SPListItem originalItem = (SPListItem)originalListItem;
SPListItem databaseItem = (SPListItem)databaseObject;
DateTime originalModifiedValue = (DateTime)originalItem["Modified"];
DateTime dbModifiedValue = (DateTime)databaseItem["Modified"];
string originalContentTypeIdValue = originalItem.ContentTypeId.ToString();
string dbContentTypeIdValue = databaseItem.ContentTypeId.ToString();
switch(mode)
{
case RefreshMode.OverwriteCurrentValues:
this.Modified = dbModifiedValue;
this.ContentTypeId = dbContentTypeIdValue;
break;
case RefreshMode.KeepCurrentValues:
databaseItem["Modified"] = this.Modified;
break;
case RefreshMode.KeepChanges:
if (this.Modified != originalModifiedValue)
{
databaseItem["Modified"] = this.Modified;
}
else if (this.Modified == originalModifiedValue && this.Modified != dbModifiedValue)
{
this.Modified = dbModifiedValue;
}
if (this.ContentTypeId != originalContentTypeIdValue)
{
throw new InvalidOperationException("You cannot change the ContentTypeId directly");
}
else if (this.ContentTypeId == originalContentTypeIdValue && this.ContentTypeId != dbContentTypeIdValue)
{
this.ContentTypeId = dbContentTypeIdValue;
}
break;
}
}
}
Once you have the ContentType and the underlying SPListItem available on your L2SP entity it is simply a matter of writing a method which returns an instance of the derived ContentType entity from a combination of the values of the base type and the extra data for the missing fields from the SPListItem.
UPDATE: I don't actually have an example converter class as we don't use the above mapping extension to Item in this way. However I could imagine something like this would work:
public static class EntityConverter
{
public static Approval ToApproval(WorkflowTask wft)
{
Approval a = new Approval();
a.SomePropertyOnWorkflowTask = wft.SomePropertyOnWorkflowTask;
a.SomePropertyOnApproval = wft.SPListItem["field-name"];
return a;
}
}
Or you could put a method on a partial instance of WorkflowTask to return an Approval object.
public partial class WorkflowTask
{
public Approval ToApproval()
{
Approval a = new Approval();
a.SomePropertyOnWorkflowTask = this.SomePropertyOnWorkflowTask;
a.SomePropertyOnApproval = this.SPListItem["field-name"];
return a;
}
public LegalReview ToLegalReview()
{
// Create and return LegalReview as for Approval
}
}
In either situation you would need to determine the method to call to get the derived type from the ContentTypeId property of the WorkflowTask. This is the sort of code I would normally want to generate in one form or another as it will be pretty repetitive but that is a bit off-topic.

Resources