How to make static class which updated itself? (Similar to Mouse) - c#

Mouse, as you know it, is a static class. It has a static property called Mouse.Position. That property, is updated dynamically (binded to mouse, maybe??). (I've read the Mouse documentation in msdn)
I need to build a same class with this scenario.
I am making an application which able to have multiple pages, and each of the pages shared, for example, Margin value.
There're 2 options (I think) to do it :
Make a field in "page" class, and pass the value via constructor (easiest)
Static class, similar to Mouse.Position usage, but, in this case, for example, PageInformation.Margin (PageInformation is a class, not a property nor a field)
I prefer the second option since it's easier to debug (i guess), and make the Page class cleaner, codeless, and easier during update if the Margin somehow changed by the user..
Anyone know how to do it? (mvvm way preferred)
Thanks.
UPDATE :
P.S. I already understand the basic mvvm practice (INPC and such)
This is the general code so far in my application :
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
...
}
public class SheetPage : ViewModel
{
...
}

Your class will be a Singleton and therefor next to impossible to unit test. That does not seem to be a very practical solution.
In WPF you can bind all margins of all pages to the same ViewModel property. This way, when your ViewModel property changes (assuming you properly implemented INotifyPropertychanged or used DependencyProperty) all your margins will change as well.

Related

INotifyPropertyChanged doesnt fire when property changes [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I have a bool value that gets updated and the INotifyPropertyChanged event doesnt fire properly. It gets to the IF portion and steps over because it sees a null being passed. I did add using System.ComponentModel at the top of the class
The first portion:
public class ToolTipInortfyPropertyChange : INotifyPropertyChanged
{
private bool form15TooltipShow;
public bool Form15TooltipShow
{
get { return form15TooltipShow; }
set
{
form15TooltipShow = value;
OnPropertyChanged("Form15TooltipShow");
}
}
and then the second portion all in the same class
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
when I step in the code it gets to the "Set" portion then jumps to the OnPropertyChanged and skips the if so my view doesnt get updated with another event needing the bool
Tx
This the case with every event in c#, if no one subscribed to the event then it will be null. In this case it seems like no one subscribed to the PropertyChanged event.
PS: I recommend putting the [CallerMemberName] attribute in the OnPropertyChanged method so you don't have to pass the name along manually every time. Like so:
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
Notice how I made the method protected instead of public, we don't wan't just anyone being able to raise the event
Edit: Here's the full OnPrertyChanged method:
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
When I step through the code I can see that
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
does execute and the value is no longer null so there must be a "listener" I gather. But the view doesnt update. The checkbox is on one form and the control that will receive the event from the checkbox is on another form. Its almost like 2 objects are created and they cant talk to each other because they are 2 different enteties. Is that possible when creating a new object of lets say type person on form 1 and the same on form 2. They will be distinct wouldnt they?
I created a whole new project and made it as simple as possible. Textbox on form1 and textbox on form 2 and try to pass text between these 2 forms. The line
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
excecutes with no Null value but the view doesnt update.
Here is the XAML
<TextBox Text="{Binding Path=CheckBoxState ,Mode=TwoWay}"></TextBox>
and I have tried all kinds of different options like ASYNC etc. The result is always the same. I even removed the code behind from the forms and did the binding on the XAML
<Window.Resources>
<local:CheckBoxClass x:Key="CheckBoxFinder" />
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource CheckBoxFinder}}">
I believe this worked fine because intelensense automatically comes up after I type PATH=
then the only property listed pops up.
any advice would be appreciated.
tx
Ok just used the EXACT same code and simply added another textbox to form1. So form1 has 2 textboxes. I bound them exactly as previously only difference is the controls sending and receiving are on the same form. And guess what... It worked.
The problem arises when 2 forms need to pass data. Its like 2 objects are created and they cant communicate. I'm sure this is common knowledge to all the seasoned guys / gals. But how do I use one object between these forms so they will be synced? Wish I knew this before could have asked my question more concisely

Multiple views sharing same data with two-way data binding between multiple threads

UWP app ( mvvm architecture ) I have a MainView which has a collection in its ViewModel, used to bind to the GridView on MainView and each item has a TextBox with 2 way databinding with Description property of class Note.
Xaml of the TextBox of each gridviewitem.
<TextBlock Text="{x:Bind Description,Mode=TwoWay}"
Collection property used to bind to ItemSource of gridview.
public ObservableCollection<Note> Notes { get; }
and this is the class Note
public class Note : Observable
{
private string _description;
public string Description
{
get => _description;
set => Set(ref _description, value, nameof(Description));
}
}
the Observable class is for two way data binding help.
public class Observable : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void Set<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
{
if (Equals(storage, value))
{
return;
}
storage = value;
OnPropertyChanged(propertyName);
}
protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Now everything uptil this point works perfectly, when I change the text in textbox, it changes the value of Description as well.
Second View
Now I have a feature where each GridViewItem has a button in it which opens the Note in new window. and this new window has nothing but only 1 TextBox, so now the secondary view and the GridViewItem which opened that view are using the same object of Note.
This TextBox in secondary view also has 2 way data binding with the Description of the Note.
The Problem
What I want is that whether the textbox in gridview or the textbox on the secondary view is edited, the value of description must remain synced between these 2 textboxes, that is why I tried to bind them 2 way with same object of Note hence the same Description object is bound to both of them.
Error here was expected to me which was Marshalling threading error, so whenever I try to change value of any textbox, it tried to update UI on other view ( which is another thread ) which is ofcourse not allowed.
I know about CoreDisptcher
I already know about the Dispatcher feature of UWP for safe cross thread communication, I already have it all setup and if I use it from a normal method I can easily use it for cross thread UI update and it totally works. But my issue is the following line :
protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));\
Exception occurs when it tried to invoke the PropertyChanged I tried to wrap following line in my Dispatcher :
OnPropertyChanged(propertyName);
but INotify interface does not allow me to have a Set<> method which returns a Task instead it needs to return just an object, this is the point where I am stuck and I dont know how to make use of Dispatcher in this scenario, please let me know if there is some better way to do this, it seems this way might not be so efficient.
Thanks.
The best solution in this case would be to have a separate set of INotifyPropertyChanged instances for each window and using some kind of messaging solution like EventHub in MvvmLight, which publishes message that the underlying model changed and all interested parties should update their instances.
Another option would be to create a base model class, which maintains a dictionary of INotifyPropertyChanged instances for each UI thread (so it would be a Dictionary<Dispatcher, YourModelClass>. Now the parent would subscribe to PropertyChanged event of each child instance and once it executes would propagate the event to other childs using the appropriate Dispatcher.
Also there is a very interesting utility class ViewSpecificBindableClass by Marian Dolinský on his GitHub which could potentially be a solution that would allow you to have "single" class in multiple views, aware of multiple dispatchers. I haven't tried it yet, but it seems promising.
So I finally had to take a totally different approach centralizing TextChanged events of MainView textbox and the one on the secondaryview.
I essentially passed the textbox on the mainpage through to the secondary page ( secondary view ) and then subscribed to its TextChanged event. I also subscribed to the TextChanged event of textbox on the secondary view, and then with help of reverse dispatchers I was able to sync the text between 2 windows without any problems.
Note : always make sure to unsubscribe to events when the secondary window closes to prevent memory leaks.
private async void PipBox_TextChanged(object sender, TextChangedEventArgs e)
{
string text = PipBox.Text;
await CoreApplication.MainView.Dispatcher.AwaitableRunAsync(() =>
{
if (parentBox.Text != text)
parentBox.Text = text;
});
}
private async void ParentBox_TextChanged(object sender, TextChangedEventArgs e)
{
string text = parentBox.Text;
// the awaitablerunasync extension method comes from "Windows Community Toolkit".
await _viewLifetimeControl.Dispatcher.AwaitableRunAsync(() =>
{
if (ViewModel.MyNote.Description != text)
ViewModel.MyNote.Description = text;
});
}
Notice that I still have 2 way data binding on both textboxes and it does not cause any exceptions because I am using 2 different instances of Note for both views.
<TextBox Text="{x:Bind ViewModel.MyNote.Description, Mode=TwoWay}"
x:Name="PipBox"/>
but because I have twoway data binding on both textboxes, that is how I can easily keep both instances of Note in sync as well on separate threads.
I will keep the github repo in case it can help anyone else : https://github.com/touseefbsb/MultiWindowBindingSync
P.S : A special thanks to Martin Zikmund who helped me a lot in figuring out this solution.

Update Label (WPF) During Runtime [duplicate]

I'm a web and backend programmer by nature. Normally I try to avaoid making windows programs. Now I have to make a WPF client.
I have a background task that raises an event every often time. (It is working like a poller and when the criteria are met an event is raised). Noob as I am I wrote this code that was attached to the event to update the UI.
private void IsDisconnectedEvent()
{
UserWindow.Visibility = Visibility.Hidden;
DisconnectWindow.Visibility = Visibility.Visible;
}
This gives an exception because I am not on the same thread. After some googling I found that I should change the code with:
private void IsDisconnectedEvent()
{
Dispatcher.Invoke(() =>
{
UserWindow.Visibility = Visibility.Hidden;
DisconnectWindow.Visibility = Visibility.Visible;
});
}
This works, but this is not the only event and thus makes my code horrible ugly. Are there better ways to do this?
Regarding this:
This works, but this is not the only event and thus makes my code
horrible ugly
Yes, your WPF-based code will definitely be extremely horrible unless you understand and embrace The WPF Mentality.
Basically, all interactions between your custom logic (AKA Business logic or Application Logic) and the WPF UI should manifest in the form of Declarative DataBinding as opposed to the traditional imperative approach.
This means that there should be nothing like this:
UserWindow.Visibility = Visibility.Hidden;
anywhere in your code, simply because introducing things like that makes your code dependent on the UI and thus only executable on the UI thread.
Instead, the WPF approach to that would be to declaratively DataBind the Visibility propety of the UI element (IN XAML) to a relevant bool property that you can operate from the outside, like this:
<UserWindow Visibility="{Binding ShowUserWindow, Converter={my:BoolToVisibilityConverter}}">
<!-- ... -->
</UserWindow>
Then, you would need to create a relevant class that contains the properties the UI is expecting to bind to. This is called a ViewModel.
Notice that in order to properly support Two-Way WPF DataBinding, your ViewModels must Implement the INotifyPropertyChanged interface.
When doing so, it is also convenient to have the PropertyChanged event from that interface marshalled to the UI thread, so that you no longer have to worry about setting the ViewModel's properties by using the Dispatcher.
Therefore our first step is to have all our ViewModels inherit from a class like this:
(taken from this answer):
public class PropertyChangedBase:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
//Raise the PropertyChanged event on the UI Thread, with the relevant propertyName parameter:
Application.Current.Dispatcher.BeginInvoke((Action) (() =>
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}));
}
}
Once we have our Property Change Notification Dispatch to the UI Thread in place, we can proceed to create a relevant ViewModel that suits, in this case, the UserWindow and it's DataBinding expectations:
public class UserViewModel: PropertyChangedBase
{
private bool _showUserWindow;
public bool ShowUserWindow
{
get {return _showUserWindow; }
set
{
_showUserWindow = value;
OnPropertyChanged("ShowUserWindow"); //This is important!!!
}
}
}
Finally, you would need to set the Window's DataContext to an instance of it's corresponding ViewModel. One simple way to do that is in the Window's constructor:
public UserWindow() //Window's Constructor
{
InitializeComponent(); //this is required.
DataContext = new UserViewModel(); //here we set the DataContext
}
As you can see in this example, there is literally no need to manipulate the UI element's properties in procedural code. This is good not only because it resolves the Thread Affinity issues (because now you can set the ShowUserWindow property from any thread), but also because it makes your ViewModels and logic completely decoupled from the UI and thus testable and more scalable.
This same concept applies to EVERYTHING in WPF.
One detail that I need to mention is that I'm making use of a technique of Combining MarkupExtension and IValueConverter in order to reduce the the XAML boilerplate involved in using Converters.
You can read more about that in the link and also the MSDN DataBinding page linked above.
Let me know if you need further details.

C# - XAML doesnt re-binding the changes

I am working on a small project..a game, but in the beggining was only console game, so decided to make it with UI using xaml..And here i have this problem - everythink seems to work fine except that it doesnt re-binding the changes i make.I have BaseModelView class which inherits INotifyPropertyChanged
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string prop)
{
if (this.PropertyChanged != null)
{
var propertyChangedArg = new PropertyChangedEventArgs(prop);
this.PropertyChanged(this, propertyChangedArg);
}
}
}
and also for collections im using ObservableCollection, but it doesnt not re-binding the changes..
I think the problem comes from here, because i dont call the OnPropertyChanged on every property for each class, i call it for the whole class but dont know.. like that
public Player Player
{
get { return this.player; }
set
{
this.player = value;
this.OnPropertyChanged("Player");
}
}
here i will link the repo, anyway its not a hidden project its mean to be open source, and maybe can find the problem more easily - http://goo.gl/mFgCXI
I hope someone can help me, because im stucked for days and dont know how to fix it to move on..
Thanks.
Saw your code on Github. You need to implement INotifyPropertyChanged on ALL classes that will be binded to. Also each property that will be bound should raise the OnPropertyChanged notification.
I see that you have binded to the properties of the Monstor & Hero class but its properties (which are bound in the UI) do not raise the OnPropertyChanged Notification.
Try making your binding mode TwoWay and test again.

Display arbitrary controls on a WPF Window

I'm developing a WPF wizard WiX custom managed bootstrapper application.
Some elements of the wizard are common (for example, the product information and logo at the top), and I don't want to have to redefine these. I also don't want to have to redevelop the whole thing from scratch for each install (yes, there are a number of installs I want to use this with and they have different wizards).
I have a model like this (simplified to avoid confusion)
public class WizardModel : INotifyPropertyChanged
{
private UserControl _currentPage;
public UserControl CurrentPage
{
get { return _currentPage; }
set
{
_currentPage = value;
if (PropertyChanged != null) PropertyChanged(this, "CurrentPage");
}
}
}
I would like to bind a control so that the control in CurrentPage is displayed when the property changes.
I did experiment with using ContentCrontol but I quickly dismissed that as not intended for this purpose, and I'm really not sure where to go from here.
I'm making a few guesses here because there's not a lot of detail in the original question, but I think I get the idea of what you are trying to accomplish.
Seems like you would want to have a base class with all of the common controls on it already. Say we call this class WizardUserControl. Anyway, let's say we define a Grid inside the WizardUserControl (let's call it CustomGridArea) and that grid will be the main area where we can drop all of our custom controls based on which page of the wizard we are processing. So maybe WizardUserControl may implement a method like:
public class WizardUserControl : UserControl
{
...
// All your standard wizard code stuff/behavior/business logic/etc...
...
...
public void InsertCustomizedControl(UserControl customizedControl)
{
CustomGridArea.Children.Clear();
CustomGridArea.Children.Add(customizedControl);
}
}

Categories