How can i update view model when model change. First solution that i found was subscribe in ViewModel for PropertyChangedEvent of Model. But is it good way? Maybe it exist better way to Notify ViewModel?
Xaml:
<Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="{Binding SomeValue}"/>
<Label Grid.Row="1" Content="{Binding Second}"/>
</Grid>
</Grid>
Code:
namespace WpfApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
public class ViewModel : INotifyPropertyChanged
{
Model model = new Model();
public ViewModel()
{
model.PropertyChanged += (o, e) =>
{
PropertyChanged(this, new PropertyChangedEventArgs(e.PropertyName));
};
}
public int SomeValue
{
get
{
return this.model.SomeValue;
}
set
{
this.model.SomeValue = value;
}
}
public int Second
{
get
{
return this.model.Second;
}
set
{
this.model.Second = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class Model : INotifyPropertyChanged
{
private int someValue;
public int SomeValue
{
get
{
return this.someValue;
}
set
{
this.someValue = value;
this.RaisePropertyChanged("SomeValue");
}
}
private int second;
public int Second
{
get
{
return this.second;
}
set
{
this.second = value;
this.RaisePropertyChanged("Second");
}
}
public Model()
{
Action Test = new Action(WorkAsync);
IAsyncResult result = Test.BeginInvoke(null,null);
}
public void WorkAsync()
{
while(true)
{
System.Threading.Thread.Sleep(3000);
SomeValue += 1;
Second += 1;
RaisePropertyChanged("SomeValue");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
}
Your model does not necessarily need to implement INotifyPropertyChanged, a pure MVVM approach would be to implement INotifyPropertyChanged in the View Model and expose only properties of which the view requires of the Model.
In your case, it'll look like this:
public class Model
{
public int SomeValue { get; set; }
}
public ViewModel : INotifyPropertyChanged
{
private Model _model = new Model();
public int SomeModelValue
{
get { return _model.SomeValue; }
set
{
_model.SomeValue = value;
//Notify property changed
}
}
...
}
And your view will bind to SomeModelValue:
<TextBox Text="{Binding SomeModelValue}" ... />
The benefit of this approach is that your view model is not exposing the entire model to the view, and only properties of the model that need to be exposed will be seen by the view. It also allows your model to remain relatively dumb.
create a raisepropertychanged method/call it
enforce two way binding on the control
look here
and here
and here is best
xaml two way binding
Related
In my view, I have a ListBox with some templated items that contain buttons.
<ListBox x:Name="MyListBox" ItemTemplate="{DynamicResource DataTemplate1}"
ItemsSource="{Binding MyItems}">
</ListBox>
And the template for generated items:
<DataTemplate x:Key="DataTemplate1">
<StackPanel Orientation="Horizontal">
<Button Width="50" Click="Button_Click" />
</StackPanel>
</DataTemplate>
When user clicks a button on one of those ListBox items, I want to send the index of that ListBox item to my ViewModel.
So figured to use Binding as it seems to be the way in MVVM. But I'm struggling to set up a binding in code between two properties.
My View code is as follows:
public partial class ItemView : UserControl
{
ViewModel.ItemViewModel VM;
public ItemView()
{
InitializeComponent();
VM = new ViewModel.ItemViewModel();
this.DataContext = VM;
}
private int clickedItemIndex;
public int ClickedItemIndex { get => clickedItemIndex; set => clickedItemIndex = value; }
private void Button_Click(object sender, RoutedEventArgs e)
{
var ClickedItem = (sender as FrameworkElement).DataContext;
ClickedItemIndex = MyListBox.Items.IndexOf(ClickedItem);
}
}
I get the index and set it to ClickedItemIndex property,
I also have property in my ViewModel:
public int SomeInt { get; set; }
Now how do I set up a binding between these two properties?
I'm quite new to MVVM and still learning it. So, maybe this not the correct approach. But I need to have a way for each individual listbox item to be able to call upon an effect in more global viewmodel. For example, if I wanted to have a "Remove" button on each of the listbox items, I would somehow need to send the index to the viewmodel and call the removeItem method with index as the parameter. Or is there a better way to do similar things?
I have a sample app created just for this scenario. I know it seems a lot of code at first glance. Copy this code in your project, that will help debug and get a hang of it(MVVM, databinding, commands and so on).
usercontrol.xaml
<UserControl x:Class="WpfApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.Resources>
<DataTemplate DataType="{x:Type local:Model}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path=Name}"/>
<Button Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.UpdateCommand}"
CommandParameter="{Binding}"
Content="Update"/>
<Button Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.RemoveCommand}"
CommandParameter="{Binding}"
Content="Remove"/>
</StackPanel>
</DataTemplate>
</Grid.Resources>
<ListBox ItemsSource="{Binding Models}">
</ListBox>
</Grid>
usercontrol.cs
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
View model
public class ViewModel : INotifyPropertyChanged
{
private Models _Models;
public Models Models
{
get { return _Models; }
set { _Models = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Models)));
}
}
public ViewModel()
{
Models = new Models();
UpdateCommand = new Command(o => true, UpdateItem);
RemoveCommand = new Command(o => true, RemoveItem);
}
void RemoveItem(object item)
{
Model m = (item as Model);
Models.Remove(m);
}
void UpdateItem(object item)
{
Model m = (item as Model);
m.Name = m.Name + " updated";
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public ICommand UpdateCommand { get; private set; }
public ICommand RemoveCommand { get; private set; }
}
Icommand implementation
public class Command : ICommand
{
private readonly Func<object, bool> _canExe;
private readonly Action<object> _exe;
public Command(Func<object,bool> canExecute,Action<object> execute)
{
_canExe = canExecute;
_exe = execute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return _canExe(parameter);
}
public void Execute(object parameter)
{
_exe(parameter);
}
}
Model and a collection of models
public class Models : ObservableCollection<Model>
{
public Models()
{
Add(new Model ());
Add(new Model ());
Add(new Model ());
Add(new Model ());
}
}
public class Model : INotifyPropertyChanged
{
static int count = 0;
public Model()
{
Name = "Model "+ ++count;
}
private string _Name;
public string Name
{
get { return _Name; }
set { _Name = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Name)));
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
You don't need to use a Button in order to select the item. When you click/tap on the item it will get automatically selected.
Then simply bind ListBox.SelectedIndex to your view model property SomeInt and it will update on every selection.
Data binding overview in WPF
You can also get the item itself by binding ListBox.SelectedItem to your view model.
You can handle new values by invoking a handler from the property's set method:
ViewModel.cs
class ViewModel : INotifyPropertyChanged
{
private int currentItemIndex;
public int CurrentItemIndex
{
get => this.currentItemIndex;
set
{
this.currentItemIndex = value;
OnPropertyChanged();
// Handle property changes
OnCurrentItemIndexChanged();
}
}
private MyItem currentItem;
public MyItem CurrentItem
{
get => this.currentItem;
set
{
this.currentItem = value;
OnPropertyChanged();
}
}
protected virtual void OnCurrentItemIndexChanged()
{
// Handle the new this.CurrentItemIndex value
}
// Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
ItemView .xaml
<UserControl>
<UserControl.DataContext>
<ViewModel />
</UserControl.DataContext>
<ListBox ItemsSource="{Binding MyItems}"
SelectedIndex="{Binding CurrentItemIndex}"
SelectedItem="{Binding CurrentItem}" />
</UserControl>
Is there a proper way to create a C#/WPF ViewModel containing subViewModel ?
Objective is:
I have a MainWindow. That window is use to read/create images. There is a button on that windows who switch between 2 UserControl one with IHM used to read image, the other one used to create.
The MainWindow has a MainWindowViewModel with :
command switch
image length
application parameters
I want that both UserControls can acces to MainWindowViewModel field/properties and have they own commands.
Construction will be something like this:
public partial class ReadUserControl : UserControl
{
public ReadUserControl()
{
InitializeComponent();
DataContext = MainViewModel.ReadViewModel;
}
}
public partial class CreateUserControl : UserControl
{
public CreateUserControl()
{
InitializeComponent();
DataContext = MainViewModel.CreateViewModel;
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = MainViewModel;
}
}
For example, if a MainViewModel contain a field ImageWidth setting ImageWidth in CreateUserControl change the value for ReadUserControl.
I hope to have been clear, I don't know how design my MainViewModel to achieve this result
EDIT1:
I've created the MainWindowViewModel as a Singleton but i'm still unable to get MainViewModel.CreateViewModel and MainViewModel.ReadViewModel
public class MainWindowViewModel : ViewModelBase
{
private static MainWindowViewModel _instance = null;
public static MainWindowViewModel Instance
{
get
{
if (_instance == null)
_instance = new MainWindowViewModel();
return _instance;
}
}
private MainWindowViewModel()
: base()
{
}
#region CreateViewModel
/* How to create ? */
#endregion
#region ReadViewModel
/* How to create ? */
#endregion
}
Your example will work. At least if you have made your MainViewModel a Singleton.
A more professional approach might be an Constructor-Injection like this.
public partial class ReadUserControl : UserControl
{
public ReadUserControl(MainViewModel vm)
{
InitializeComponent();
DataContext = vm.ReadViewModel;
}
}
With such DependencyInjections you can achieve a higher level of abstraction, since your UserControls can be generalized. (They will all have the same Constructor)
On the other hand, you give every such UserControl the ability, to manipulate the MainViewModel, not aware of side-effects.
In your special case, it would be more safe, to pass only the needed parameters to the UserControl, instead of giving them a bunch of informations, they will never need.
public partial class ReadUserControl : UserControl
{
public ReadUserControl(Icommand command, int imageLength, AppParams appParams)
{
InitializeComponent();
...
// Do with your Constructorparameters what ever you have to
}
}
Edit:
Here a small, dumb implementation of how it could be done:
Code
public class MainViewModel : INotifyPropertyChanged {
private INotifyPropertyChanged _selectedViewModel;
public MainViewModel() {
var cmd = new RelayCommand(x => {
MessageBox.Show("HelloWorld");
}, x => true);
this.RVM = new ReadViewModel(cmd);
this.WVM = new WriteViewModel(cmd);
this.SelectedViewModel = WVM;
}
private ICommand _switchViewModelCommand;
public ICommand SwitchViewModelCommand => this._switchViewModelCommand ?? (this._switchViewModelCommand = new RelayCommand(x => {
if (this.SelectedViewModel == RVM) {
this.SelectedViewModel = WVM;
return;
}
this.SelectedViewModel = RVM;
}));
public INotifyPropertyChanged SelectedViewModel {
get {
return this._selectedViewModel;
}
set {
if (Equals(value, this._selectedViewModel))
return;
this._selectedViewModel = value;
this.OnPropertyChanged();
}
}
public ReadViewModel RVM {
get; set;
}
public WriteViewModel WVM {
get; set;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ReadViewModel : INotifyPropertyChanged {
public ReadViewModel(ICommand sayHelloCommand) {
this.HelloCommand = sayHelloCommand;
}
public ICommand HelloCommand {
get;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class WriteViewModel : INotifyPropertyChanged {
public WriteViewModel(ICommand sayHelloCommand) {
this.HelloCommand = sayHelloCommand;
}
public ICommand HelloCommand {
get;
}
public ICommand HelloMoonCommand => new RelayCommand(x => { MessageBox.Show("Hello Moon"); });
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid Height="200">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<ContentControl Content="{Binding SelectedViewModel, UpdateSourceTrigger=PropertyChanged}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:ReadViewModel}">
<StackPanel>
<Button Content="Say Hello world" Command="{Binding HelloCommand}"></Button>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:WriteViewModel}">
<StackPanel>
<Button Content="Say Hello world" Command="{Binding HelloCommand}"></Button>
<Button Content="Say Hello Moon" Command="{Binding HelloMoonCommand}"></Button>
</StackPanel>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
<Button Content="Switch VM" Command="{Binding SwitchViewModelCommand}" Grid.Row="1"/>
</Grid>
You can pass in the MainViewModel as DataContext for your user control and set the data context of elements as Read/Create model
something like
<Grid> <!--using MainWindowViewModel as data context-->
<Grid DataContext="{Binding Path=CreateViewModel}"> <!--using CreateViewModel as data context-->
.....
</Grid>
<Grid>
I want to create master page in mvvm. I created a viewbox that it's name is container for showing my usercontrols and I have two classes, RelayCommand and ViewModel.
Here is my code:
public class ViewModel
{
MainWindow objMainWindow = new MainWindow();
UserControls.History objHistory = new UserControls.History();
UserControls.NewItem objNewItem = new UserControls.NewItem();
UserControls.SideEffect objSideEffect = new UserControls.SideEffect();
public ViewModel()
{
OpenCommand = new RelayCommand(Open);
}
private ICommand openCommand;
public ICommand OpenCommand
{
get { return openCommand; }
set { openCommand = value; }
}
public void Open(object sender)
{
if (sender.ToString() == "btnHistory")
{
objMainWindow.Container.Child = objHistory;
}
if (sender.ToString() == "btnNewItem")
{
}
if (sender.ToString() == "btnSideEffect")
{
}
}
}
And this is my RelayCommand:
public class RelayCommand:ICommand
{
public RelayCommand(Action<object> _action)
{
actionCommand = _action;
}
private Action<object> actionCommand;
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
if (parameter !=null)
{
actionCommand(parameter);
}
else
{
actionCommand("Null");
}
}
}
but when I run solution I faced with NullRefrenceException when it wanted to show my child of container.
I don't know how to make this work.
Your MainWindow instantiates when your program starts. So you shouldn't instantiate it again in your ViewModel (i.e. this line: MainWindow objMainWindow = new MainWindow();). You should use DataBinding instead.
Here is a sample code that gives you an idea:
First define a property of type FrameworkElement in you ViewModel and set it's value to your desired UserControl in the Open method.
ViewModel:
public class ViewModel : INotifyPropertyChanged
{
FrameworkElement _myUc;
public FrameworkElement MyUserControl
{
get
{
return _myUc;
}
set
{
_myUc= value;
OnPropertyChanged("MyUserControl");
}
}
public ViewModel()
{
OpenCommand = new RelayCommand(Open);
}
public void Open(object sender)
{
if (sender.ToString() == "btnHistory")
{
MyUserControl = objHistory;
}
}
// rest of your view model ...
}
Then instantiate your ViewModel as the DataContext of your MainWindow in the Constructor.
MainWindow:
public ViewModel MyViewModel { get; set; }
public MainWindow()
{
InitializeComponent();
MyViewModel = new ViewModel();
DataContext = MyViewModel;
}
And Finally use a ContentControl (instead of ViewBox) [see my note] and bind it's Content to the MyUserControl property of your ViewModel.
XAML:
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ContentControl Grid.Row="0" Content="{Binding MyUserControl}" x:Name="Container"/>
<Button Grid.Row="1" Name="btnHistory" Content="ShowHistory" Command="{Binding OpenCommand}" />
</Grid>
This way each time MyUserControl changes, the ContentControl shows your desired UserControl.
Note that Child property of ViewBox is not a DependencyProperty and thus not bind-able.
I'm having a great trouble with understanding how button command works. I have something like this
{Binding TxtBox} gets value from model, let's say it's "aaa". I would like click the button and the value should appear in the second textbox (the one with {Binding TxtBox2}).
This is my xaml:
<TextBox Text="{Binding TxtBox, Source={StaticResource viewModel}}" />
<TextBox Text="{Binding TxtBox2, Source={StaticResource viewModel}}" />
<Button Command="{Binding ClickCommand}"/>
This is my ViewModel:
public class CommandHandler : ICommand
{
private Action _action;
private bool _canExecute;
public CommandHandler(Action action, bool canExecute)
{
_action = action;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action();
}
}
Do I really need this CommandHandler class? I copied the code from the net.
public string TxtBox
{
get { return Model.TxtBoxValue; }
set { Model.TxtBoxValue = value; }
}
public string TxtBox2 { get; set; }
private ICommand _clickCommand;
public ICommand ClickCommand
{
get
{
return _clickCommand ?? (_clickCommand = new CommandHandler(() => MyAction(), _canExecute)); // I believe that when the button is clicked MyAction() is triggered, right?
}
}
private bool _canExecute = true;
public void MyAction()
{
this.TxtBox2 = this.TxtBox; // should something like this work? Because right now it doesn't
}
The second textbox's binding never gets notified that it's bound property is changed. When you set this.TxtBox2 you should fire the propertychanged event for that property so the binding will be updated.
See think link for everything on bindings
I don't know if you are using prism as mvvm framework but that comes with the DelegateCommand class. I don't think there is a simple/lightweight implementation in the .net framework. See this link for the mvvm framework and the delegate command
The View reacts to binding changes through PropertyChanged events, of which you have none. Have anything that binds to the View implement INotifyPropertyChanged and then fire events when props change, and you're all set for your bindings to work (one way or two way).
Change your model to look like this and it should work for you.
public class MyViewModel : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged = null;
protected virtual void RaisePropertyChanged(string propName)
{
if(PropertyChanged != null)
{
Task.Run(() => PropertyChanged(this, new PropertyChangedEventArgs(propName)));
}
}
#endregion
public string TxtBox
{
get { return Model.TxtBoxValue; }
set
{
Model.TxtBoxValue = value;
RaisePropertyChanged("TxtBox");
}
}
// presuming TxtBox2Value is in Model...else use a field
public string TxtBox2
{
get { return Model.TxtBox2Value; }
set
{
Model.TxtBox2Value = value;
RaisePropertyChanged("TxtBox2");
}
}
private ICommand _clickCommand;
public ICommand ClickCommand
{
get
{
return _clickCommand ?? (_clickCommand = new CommandHandler(() => MyAction(), _canExecute)); // I believe that when the button is clicked MyAction() is triggered, right?
}
}
private bool _canExecute = true;
public void MyAction()
{
this.TxtBox2 = this.TxtBox; // should something like this work? Because right now it doesn't
}
}
IMO - it is better to have your Model implement INotifyPropertyChanged and then bind directly to it rather than wrap it in your ViewModel. If Model : INotifyPropertyChanged, then your ViewModel now looks like this:
public class MyViewModel
{
// fire prop changed event here if this model will be swapped out after the ctor...otherwise don't worry about it
public Model Model { get; set; }
private ICommand _clickCommand;
public ICommand ClickCommand
{
get
{
return _clickCommand ?? (_clickCommand = new CommandHandler(() => MyAction(), _canExecute));
}
}
private bool _canExecute = true;
public void MyAction()
{
Model = new Model();
Model.TxtBox2 = "Some new value";
}
}
...and your xaml changes to this:
<TextBox Text="{Binding Model.TxtBox, Source={StaticResource viewModel}}" />
<TextBox Text="{Binding Model.TxtBox2, Source={StaticResource viewModel}}" />
<Button Command="{Binding ClickCommand}"/>
I have a simple object (which is globally initiated in App.xaml.cs):
public class now_playing : INotifyPropertyChanged
{
// notify
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string p)
{
Debug.WriteLine(p + ": notify propertychanged");
PropertyChangedEventHandler handler = PropertyChanged;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
// artist
public string artist
{
get
{
return _artist;
}
set
{
_artist = value;
NotifyPropertyChanged("artist");
}
}
private string _artist;
// album
public string album
{
get
{
return _album;
}
set
{
_album = value;
NotifyPropertyChanged("album");
}
}
private string _album;
// track title
public string tracktitle
{
get
{
return _tracktitle;
}
set
{
_tracktitle = value;
NotifyPropertyChanged("tracktitle");
}
}
private string _tracktitle;
}
Whenever I change the values, the class does notify (I see the debug).
So I guess the problems lies in my XAML or the code behind.
Page code:
public sealed partial class nowplaying : Page
{
// artistdata
public string artist { get { return App.nowplaying.artist; } }
// albumdata
public string album { get { return App.nowplaying.album; } }
// trackdata
public string tracktitle { get { return App.nowplaying.tracktitle; } }
public nowplaying()
{
this.InitializeComponent();
this.DataContext = this;
}
}
XAML:
<Grid Margin="50">
<TextBlock Text="{Binding tracktitle}" Foreground="White" FontSize="40"/>
<TextBlock Foreground="#dcdcdc" FontSize="20" Margin="0,50,0,0">
<Run Text="{Binding artist}"/>
<Run Text=" - "/>
<Run Text="{Binding album}"/>
</TextBlock>
</Grid>
Why does the UI not update when I change values?
Stack trace:
Music.exe!Music.App.InitializeComponent.AnonymousMethod__6(object sender = {Music.App}, Windows.UI.Xaml.UnhandledExceptionEventArgs e = {Windows.UI.Xaml.UnhandledExceptionEventArgs}) Line 50 C#
Music.exe!play_music.MessageReceivedFromBackground(object sender = null, Windows.Media.Playback.MediaPlayerDataReceivedEventArgs e = {Windows.Media.Playback.MediaPlayerDataReceivedEventArgs}) Line 57 C#
UPDATE: problem solved! I had to use a dispatcher when calling the propertychanged event:
CoreDispatcher dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
if (PropertyChanged != null)
{
await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
this.PropertyChanged(this, new PropertyChangedEventArgs(p));
});
}
You "loose" the change notification in the properties in the Page as these properties do not have any change notifiaction.
Try using now_playing directly:
public sealed partial class nowplaying : Page
{
public now_playing NowPlaying { get { return App.nowplaying; } }
public nowplaying()
{
this.InitializeComponent();
this.DataContext = this;
}
}
and
<Run Text="{Binding NowPlaying.artist}"/>
Otherwise you need to implement INotifiyPropertyChanged in nowplaying and forward the events from now_playing.
You actually binding to artist, album and tracktitle Of nowplaying class which does implement INotifyPropertyChanged