I am working on an APP that can take number from user and send message to that number.
The number is saved in global variable, the number is changeable by the user. I want the phone number to appear in the textbox every time the user opens the app, so he/she can view the number and update it if they require.
What I've tried:
phonenumber.Text = (App.Current as App).phoneglobal;
I added it after InitializeComponent();, but that didn't work.
Since you are using WPF, I recommend using the MVVM pattern. In your case, you would have:
public partial class MainWindow : Window
{
private MainWindowViewModel viewModel = new MainWindowViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = viewModel;
}
}
public class MainWindowViewModel : System.ComponentModel.INotifyPropertyChanged
{
private App currentApp = (Application.Current as App);
public MainWindowViewModel()
{
}
public string PhoneNumber
{
get
{
return currentApp.phoneglobal;
}
set
{
currentApp.phoneglobal = value;
OnPropertyChanged(new PropertyChangedEventArgs("PhoneNumber"));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
}
Then, in your xaml, simply bind to the ViewModel's PhoneNumber property.
<Window x:Class="YourNamespace.MainWindow">
<TextBox x:Name="phonenumber" Text="{Binding PhoneNumber}" />
</Window>
Then you should never need to set phonenumber.Text from the code-behind. If you need to set the phone number programmatically, set viewModel.PhoneNumber and the text box will automatically update.
Note that if you set currentApp.phoneglobal directly (without using viewModel.PhoneNumber), then the text box will NOT automatically update.
If this doesn't help, post your xaml code as well as any references in code to the phonenumber text box.
Related
Hi !
I have a WPF application and I want to set the title of the window page without refresh the all page, because in this page I have two buttons that list a DataRow belong the Title when I press it.
void refreshStatusBar()
{
this.Title= "Holaaa";
}
WPF class:
<Height=.... Title="Prueba"...> the initial value
The problem is when I press a button (next or back) I need to set the Title of the page and never change when I call to refreshStatusBar() in the btNext or btBack method.
I tryed to binding the Title, but don´t work. Always show the same value, the initial:
Title="{Binding Path="windowTitleBar"}"
public String windowTitleBar {get; set;}
void refreshStatusBar(){
windowTitleBar="Holaaa";
}
I want the title change when I press some button. I don´t have pages inside the window page, just show one thing or another thing.
I tryed too:
Title="{Binding Path=windowTitleBar, RelativeSource={RelativeSource Mode=Self}}"
and don´t work neither.
Please, any solution to fix it?
Sorry for my english !
Thanks !
This works for me without a binding:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
this.Title = "Hellooo";
}
void RefreshStatusBar()
{
this.Title = "Holaaa";
}
private void button1_Click(object sender, RoutedEventArgs e)
{
RefreshStatusBar();
}
}
If you want to use a binding, set it up like you did with Title="{Binding Path=WindowTitleBar, RelativeSource={RelativeSource Mode=Self}}"
But as it is, WPF has no way of knowing when your property value changes. You can implement INotifyPropertyChanged to solve this:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private string _windowTitleBar = "Hellooo";
public MainWindow()
{
this.WindowTitleBar = "Hellooo";
InitializeComponent();
}
public string WindowTitleBar
{
get { return _windowTitleBar; }
set
{
_windowTitleBar = value;
OnPropertyChanged("WindowTitleBar");
}
}
void RefreshStatusBar()
{
this.WindowTitleBar = "Holaaa";
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private void button1_Click(object sender, RoutedEventArgs e)
{
RefreshStatusBar();
}
}
Edit:
I just noticed you said "Page". I've never used Pages, but it looks like to set the title of the window containing your page, you have to set the WindowTitle property. Unfortunately it's not a DependencyProperty so you can't use a binding. You can set it directly, though:
void RefreshStatusBar()
{
this.WindowTitle = "Holaaa";
}
I have a MVVM WPF application in C#, NET 3.5 and Visual Studio 2008.
From the app main xaml I import a user control.
This user control has some public methods, there are two I am interested in.
One method to start an animation and another to stop it.
From my view's constructor in code-behind (xaml.cs), I call the user control public method to start the animation to show it to user while I am loading some data into my gridview within listview. The method to load the data is called form my view model.
So now, when the loading task is finished, I need to call the another user control public method to stop animation but I do not know how to do this from my view model.
Any ideas? I cannot touch the user control as this is not mine.
Below some piece of code.
XAML:
xmlns:controlProgress="clr-namespace:Common.XAML.Controls.Progress;assembly=Common.XAML"
<controlProgress:Progress x:Name="Progress"
Grid.ZIndex="3"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="150"
CustomText="Loading...">
Code-behind (xaml.cs):
public MyView(ViewModelSession vm)
: base(vm)
{
InitializeComponent();
Progress.StartAnimation();
}
View Model:
public MyViewModel(Session session)
: base(session)
{
this.LoadDataIntoGridView();
}
You can use the INotifyPropertyChanged Interface e.g. create an ViewModelBase
public class ViewModelBase
: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Then you use this for your ViewModel and add a Property IsLoading
public class MyViewModel : ViewModelBase
{
private bool _isLoading;
public bool IsLoading
{
get { return _isLoading; }
set
{
if(_isLoading == value) return;
_isLoading = value;
OnPropertyChanged();
}
}
Then in your View Codebehind use the PropertyChanged event of the ViewModel to Start/Stop Animation.
Then you can set the bool in your ViewModel to start stop closing animation
in your view
UPDATE
public class MyView
{
private readonly MyViewModel _viewModel;
public MyView(MyViewModel viewModel)
: base(viewModel)
{
InitializeComponent();
_viewModel = viewModel;
_viewModel.PropertyChanged +=OnPropertyChanged;
}
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(MyViewModel.IsLoading))
{
if (_viewModel.IsLoading)
{
Progress.StartAnimation();
}
else
{
Progress.StopAnimation();
}
}
}
}
You could put a boolean property in your view model to track if the loading has been completed, after that the property will be set to true.
public class MyViewModel
{
public bool IsLoadComplete { get; set; }
public MyViewModel()
{
this.LoadDataIntoGridView();
}
}
Then in your codebehind you can start a Task to track changes in that property of the DataContext:
public MyView(MyViewModel vm)
{
InitializeComponent();
Progress.StartAnimation();
Task.Run(() =>
{
var dataContext = DataContext as MyViewModel;
while (true)
{
if (dataContext.IsLoadComplete)
break;
Task.Delay(100);
}
Dispatcher.BeginInvoke(new Action(() => { Progress.StopAnimation(); }));
});
}
You have to use Dispatcher.BeginInvoke to queue the call in the UI thread. Of course this is not a ready-to-production solution. You may provide Datacontext until View has been constructed in which case you must refactor, also you may keep track of the task you have just started and may be support cancellation with a CancellationToken. This is only a sample
I am trying to get the text of a label to update on the front of end of my app.
At the moment Im using Message Centre to send a notification up to the view model and increment a number that should update on the label in the view.
Im using Xamarin Forms and PCL.
I can get the number to log out in the debug so I know the message centre is working. But its not updating the view.
the relevant Xaml:
<Label Text="{Binding counter}"
Grid.Row="0"/>
The code behind:
public partial class DriverDashboardView : ContentPage
{
private DriverDashboardViewModel driverdashboardviewmodel;
public DriverDashboardView()
{
InitializeComponent();
this.Title = "Driver's Dashboard";
BindingContext = driverdashboardviewmodel = new DriverDashboardViewModel();
dataList.ItemTapped += DataList_ItemTapped;
}
private void DataList_ItemTapped(object sender, ItemTappedEventArgs e)
{
DisplayAlert("Route Information","Various Data","OK");
}
protected async override void OnAppearing()
{
base.OnAppearing();
await driverdashboardviewmodel.GetLabelInfo();
}
}
The View Model:
public class DriverDashboardViewModel:BaseViewModel,INotifyPropertyChanged
{
private int messageCounter { get; set; }
public string counter { get { return messageCounter.ToString(); }
set {
if (Equals(value, messageCounter)) return;
messageCounter = Convert.ToInt32(value);
OnPropertyChanged(nameof(counter));
} }
public DriverDashboardViewModel()
{
MessagingCenter.Subscribe<App>((App)Application.Current, "Increase", (variable) => {
messageCounter++;
});
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
And the relevant section that implements the message centre:
Foregroundmessages.cs:
MessagingCenter.Send((App)Xamarin.Forms.Application.Current, "Increase");
As stated the messaging centre works fine. It gets as far as the view model but doesnt update the counter variable to the view. I have tried setting the counter as an int and a string hence the conversion in the get and set.
I also tried observable collection but that seemed redundant because its a single variable not a collection or list.
Any ideas?
your code is updating the private messageCounter property, not the public counter property that you are binding to. Updating messageCounter does not cause PropertyChanged to fire.
MessagingCenter.Subscribe<App>((App)Application.Current, "Increase", (variable) => {
messageCounter++;
});
I am trying to get the content of a TextBox updated using Binding in a MVVM environment. When a Button receive focus, it passes a value, and that value should be reflected in the TextBox. I seem to have the first part right, however seems to be struggling at passing the value..
I know the question about MVVM has been asked before (including by myself), but I really cannot get it, for some reasons..
So I start with my model:
public class iText : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _text;
public string Text
{
get { return _text; }
set
{
_text = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Text)));
}
}
I then continue with my ViewModel:
private iText _helper = new iText();
public iText Helper
{
get { return _helper; }
set
{
_helper = value;
}
}
The XAML page:
<Page.Resources>
<scan:ModelDataContext x:Key="ModelDataContext" x:Name="ModelDataContext"/>
</Page.Resources>
<TextBox Text="{Binding Helper.Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
I then try to update the Text from MainPage.cs
public sealed partial class MainPage : Page
{
public MainPageViewModel iText { get; set; }
public MainPage()
{
InitializeComponent();
iText = new MainPageViewModel();
}
private void btn_GotFocus(object sender, RoutedEventArgs e)
{
var str = "test"
iText.Helper.Text = str;
}
I could really appreciate if someone could tell me what I do wrong, and where. Thanks so much in advance.
In your MainPage constructor, try setting the datacontext to your ViewModel.
Something like...
public MainPage()
{
InitializeComponent();
iText = new MainPageViewModel();
this.dataContext = iText;
}
Why does my textbox fail to update when I try to update it from another class?
I've instantiated the MainWindow class in my Email class, but when I try to do
main.trending.Text += emailText;
Am I doing something wrong?
You should bind your data.
Model
public class YourData : INotifyPropertyChanged
{
private string _textBoxData;
public YourData()
{
}
public string TextBoxData
{
get { return _textBoxData; }
set
{
_textBoxData = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("TextBoxData");
}
}
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
XAML Binding
Set data context in Codebehind
this.DataContext = YourData;
Bind Property
<TextBox Text="{Binding Path=Name2}"/>
See #sa_ddam213 comment. Dont do something like MainWindow main = new MainWindow(); inside Email class. Instead, pass the MainWindow object you already have.
Following codes will work:
public class MainWindow
{
public void MethodWhereYouCreateEmailClass()
{
Email email = new Email;
email.Main = this;
}
}
public class Email
{
public MainWindow main;
public void MethodWhereYouSetTrendingText()
{
main.trending.Text += emailText;
}
}
But I dont say that is best practice. I just try to keep it close to your existing code i guess.