I'm new to the MVVM pattern, but I understand some of it. The problem I currently have is that I want to open a page when a button is pressed, using the MVVM pattern. When one of the six buttons is pressed, a command can give me the name of the button that is pressed. My problem is that I don't know how to set the frame's content when the button is pressed.
<StackPanel>
<Button Content="Page 1" x:Name="Page1"
Command="{Binding SimpleCommand, Source={StaticResource ViewModelBase}}"
CommandParameter="{Binding Name, ElementName=Page1}"/>
<Button Content="Page 2" x:Name="Page2"
Command="{Binding SimpleCommand, Source={StaticResource ViewModelBase}}"
CommandParameter="{Binding Name, ElementName=Page2}"/>
</StackPanel>
Above is the XAML code right now. The simplecommand is just to write out the name on the button
<Frame x:Name="MainFrame" Grid.Column="1" Grid.Row="1"
Content="{Binding Name, Converter={StaticResource Converter}, ElementName=Page1}"
NavigationUIVisibility="Hidden"/>
Above is the Frame that i want to change the content. On compile time i can set the page that it should open. I want to set the content on run time, where i use the button name.
The converter is just the IValueConverter, where i set what page it should display.
The way I have approached this was not by using a frame but using a ContentPresenter. You can always insert the ContentPresenter inside of your Frame. Bear in mind that Frame doesn't inherit DataContext so I would avoid using it.
To start of let's create a BaseViewModel be our starting point for views.
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Now that we have the base let's create a MainViewModel:
public class MainViewModel : BaseViewModel
{
private BaseViewModel selectedViewModle;
public BaseViewModel SelectedViewModel
{
get { return selectedViewModle; }
set { selectedViewModle = value; OnPropertyChanged(nameof(SelectedViewModel)); }
}
}
At this point our MainViewModel has a property with SelectedViewModel this is what we are going to use for our navigation.
Assumption
I am assuming that you have a working knowledge about commands and how to use them.
Here is a code example of a method for your Navigate command:
void navigate(object parameter)
{
SelectedViewModel = new DetailsViewModel();
}
And here is the code for DetailsViewModel:
public class DetailsViewModel : BaseViewModel
{
//your code with properties and methods here
}
Now let's set up the view:
<UserControl ...>
<Grid>
<ContentPresenter Content="{Binding .}"/>
</Grid>
</UserControl>
Now in the Resources tag for your UserControl include a DataTemplate:
<DataTemplate DataType="{x:Type vm:DetailsViewModel}">
<Grid .../>
</DataTemplate>
At this point you will have the content of the data template presented for you on the screen.
Related
I am witting a new WPF application using C# with the help of Prism 6. and the MVVM design pattern.
I have a main windows with a Top, Right, and a Center region. On the top region I have a toolbar, when a user clicks "Show Message" button, I show a view called "Message" in the center region. I am able to do that using RegionManager.RequestNavigate method to show the "Message" view which is working fine.
However, my "Message" view have multiple tabs. When the user clicks on the TabControlItems, I want to be able to show different views in the tab-Content.
Here is how my Message view look like. The idea here is to have a collection of ViewModels, and display the tabs according to the collection.
<TabControl ItemsSource="{Binding ViewModelCollection}"
Background="Transparent">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<prism:InvokeCommandAction Command="{Binding TabSelectionChangedCommand}"
CommandParameter="{Binding ViewName}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding TabTitle}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ContentControl prism:RegionManager.RegionName="{x:Static foundation:RegionNames.TabContentRegionName}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
Then in my MessageViewModel I have the following code
public class MessageViewModel : BindableBase
{
public ObservableCollection<TabBasedNavigationAwareViewModel> ViewModelCollection { get; set; }
public DelegateCommand<string> ChangeTabContent { get; set; }
public MessageViewModel(IUnitOfWork unitOfWork, IPassportManager passportManager, ICoreRegionManager regionManager, IUnityContainer container)
: base(unitOfWork, passportManager, regionManager)
{
ViewModelCollection = new ObservableCollection<TabBasedNavigationAwareViewModel>();
ViewModelCollection.Add(container.Resolve<FirstViewModel>());
ViewModelCollection.Add(container.Resolve<SecondViewModel>());
ChangeTabContent = new DelegateCommand<string>(HandleChangeContent, CanChangeContent);
}
protected bool CanChangeContent(string viewName)
{
return true;
}
protected void HandleChangeContent(string viewName)
{
IRegion region = RegionManager.Regions[RegionNames.TabContentRegionName];
region.RequestNavigate(new Uri("Modules.Messages.Views." + viewName, UriKind.Relative));
}
public override void OnNavigatedTo(NavigationContext navigationContext)
{
ChangeTabContent.Execute("FirstView");
}
}
The problem is when the application starts I get an error
The region manager does not contain the TabContent region.
I clearly understand the error and why it is happening. But not sure how to solve it. May be Regions is the wrong way to do when using tab-controls inside a main region. I also tried to call the following code from the MessageViewModel constructor RegionManager.RegisterViewWithRegion(RegionNames.TabContentRegionName, typeof(MessageView));
What is the correct way to manage/display the correct view when the user click on the tabs?
Please note that I am using Fody.PropertyChanged package so it automatically notify when the property changed.
UPDATED
I tried to remove regions from view, now I get the tabs and the content screen is showing the FirstViewModel full name instead of the corresponding view.
Here is my code without regions
public class MessageViewModel : BindableBase
{
public ObservableCollection<TabBasedNavigationAwareViewModel> ViewModelCollection { get; set; }
public MessageViewModel(IUnitOfWork unitOfWork, IPassportManager passportManager, ICoreRegionManager regionManager, IUnityContainer container)
: base(unitOfWork, passportManager, regionManager)
{
ViewModelCollection = new ObservableCollection<TabBasedNavigationAwareViewModel>();
ViewModelCollection.Add(container.Resolve<FirstViewModel>());
ViewModelCollection.Add(container.Resolve<SecondViewModel>());
}
}
Here is the view
<TabControl ItemsSource="{Binding ViewModelCollection}"
Background="Transparent">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding TabTitle}" />
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
Also add some DataTemplates for your tab view models to a resource dictionary nearby
<DataTemplate DataType="{x:Type FirstViewModel}">
<TextBlock Text="{Binding SomeContent}"/>
</DataTemplate>
I created a user control that looks like a tile. Created another user control named TilePanel that serves as the default container of the tiles. And lastly, the very UI that looks like a Window start screen. I used RelayCommand to bind my TileCommands
Here are the codes:
Tilev2.xaml
<UserControl x:Class="MyNamespace.Tilev2"
Name="Tile"....
>
...
<Button x:Name="btnTile" Style="{StaticResource TileStyleButton}" Command="{Binding ElementName=Tile, Path=TileClickCommand}" >
</Button>
</UserControl>
Tilev2.xaml.cs
public partial class Tilev2 : UserControl
{
public Tilev2()
{
InitializeComponent();
}
//other DPs here
public ICommand TileClickCommand
{
get { return (ICommand)GetValue(TileClickCommandProperty); }
set { SetValue(TileClickCommandProperty, value); }
}
// Using a DependencyProperty as the backing store for TileClickCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TileClickCommandProperty =
DependencyProperty.Register("TileClickCommand", typeof(ICommand), typeof(Tilev2));
}
}
Then I created a TilePanel user control as the container of the tiles
TilePanel.xaml
<UserControl x:Class="MyNamespace.TilePanel"
...
>
<Grid>
<ScrollViewer>
<ItemsControl Name="tileGroup"
ItemsSource="{Binding TileModels}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local2:Tilev2 TileText="{Binding Text}"
TileIcon="{Binding Icon}"
TileSize="{Binding Size}"
TileFontSize="{Binding FontSize}"
Background="{Binding Background}"
TileCaption="{Binding TileCaption}"
TileCaptionFontSize="{Binding TileCaptionFontSize}"
TileClickCommand="{Binding TileCommand}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</UserControl>
TilePanel.xaml.cs
public partial class TilePanel : UserControl
{
public TilePanel()
{
InitializeComponent();
DataContext = new TilePanelViewModel();
}
public TilePanelViewModel ViewModel
{
get { return (TilePanelViewModel)this.DataContext; }
}
}
My ViewModel for TilePanel
TilePanelViewModel.cs
public class TilePanelViewModel : ViewModelBase
{
private ObservableCollection _tileModels;
public ObservableCollection<TileModel> TileModels
{
get
{
if (_tileModels == null)
_tileModels = new ObservableCollection<TileModel>();
return _tileModels;
}
}
}
Then my Tile model
TileModel.cs
public class TileModel : BaseNotifyPropertyChanged
{
//other members here
ICommand tileCommand { get; set; }
//other properties here
public ICommand TileCommand
{
get { return tileCommand; }
set { tileCommand = value; NotifyPropertyChanged("TileCommand"); }
}
}
}
This is my StartScreen View where TilePanels with tiles should be displayed...
StartScreen.xaml
<UserControl x:Class="MyNamespace.StartMenu"
... >
<Grid>
<DockPanel x:Name="dockPanel1" Grid.Column="0" Grid.Row="1" Margin="50,5,2,5">
<local:TilePanel x:Name="tilePanel"></local:TilePanel>
</DockPanel>
</Grid>
</UserControl>
StartScreen.xaml.cs
public partial class WincollectStartMenu : UserControl, IView<StartMenuViewModel>
{
public WincollectStartMenu()
{
InitializeComponent();
}
public StartMenuViewModel ViewModel { get { return (DataContext as StartMenuViewModel); } }
private void UserControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
ViewModel.Tile = tilePanel.ViewModel.TileModels;
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
return;
}
}
In my start screen ViewModel, I used ObservableCollection Tile
and use Tile.Add(tile); to populate my start screen with Tiles inside the TilePanel...
StartMenuViewModel.cs
TileModel tile = new TileModel() { Text = "Testing1", FontSize = 11, Size = TileSize.Medium, Background = (SolidColorBrush)new BrushConverter().ConvertFromString("#039BE5"), Tag="Something" };
tile.TileCommand = new RelayCommand(
p => Tile_TileClick(tile.Tag),
p => true
);
temp.Add(tile);
Now the problem is, if I add a new code below, tile = new TileModel() {...}
tile.TileCommand = new RelayCommand(...), even if I clicked on the first tile, my Tile_TileClick() will get the second tile's info (or the last tile inserted)...
Am I doing something wrong? Or Im doing everything wrong...?
This is not direct answer to your question, but hopefully it will give you few thoughts.
Ok, first of all, don't name your usercontrol like this:
<UserControl x:Class="MyNamespace.Tilev2" Name="Tile"/>
because the name can be easily overriden when using the usercontrol somewhere:
<local:Titlev2 Name="SomeOtherName" />
and the binding inside Tilevs with ElementName won't work: Command="{Binding ElementName=Tile, Path=TileClickCommand}"
Second, what's the point of Tilev2 usercontrol? Why don't just put the button directly to the DataTemplate inside TilePanel class?
If you need to reuse the template, you can put the template to resource dictionary.
If you need some special presentation code in the Tilev2 codebehind or you need to use the Tilev2 without viewmodel, it's better to create custom control instead of usercontrol in this case. it has much better design time support, and writing control templates it's easier (Triggers, DataTriggers, TempalteBinding, etc). If you used custom Control insead UserControl, you wouldn't have to write {Binding ElementName=Tile, Path=TileClickCommand}, or use RelativeSource, etc.
Third, it seems like you forced MVVM pattern where you can't really take advantage of it. Point of MVVM is separate application logic from presentation. But your Tile and TilePanel usercontrols are just presentation. You application logic could be in StartScreen which is concrete usage of TileName.
I would create custom controls called TilePanel (potentionally inherited from ItemsControl, Selector or ListBox) and if needed also for Tile. Both controls should not be aware of any viewmodels. There's absolutelly no need for that.
Take ListBox as an example. ListBox does not have viewmodel but can be easily used in MVVM scenarios. Just because ListBox it is not tied to any viewmodel, it can be databound to anything.
Just like ListBox creates ListBoxItems, or
Combobox creates ComboBoxItems, or
DataGrid creates DataGridRows or
GridView (in WinRT) creates GridViewRow, your TilePanel could create Tiles.
Bindings to tile specific properties, like Icon or Command could be specified in TilePanel.ItemContainerStyle orusing simillar appriach like DisplayMemberPath, resp ValueMemberPath in ListBox.
final usage could the look like:
<TilePanel ItemsSource="{Bidning ApplicationTiles}" />
or
<TilePanel>
<Tile Icon=".." Command=".." Text=".." />
<Tile Icon=".." Command=".." Text=".." />
</TilePanel>
Last, the name `TilePanel' evoked that it is some kind of panel like StackPanel, WrapPanel, etc. In other words, it is FrameworkElement inherited from Panel.
TilesView would be more suitable name for the control than TilePanel. The -View postfix is not from MVVM, it just follows naming convention -GridView, ListView...
Saw the problem...
To pass a parameter from button, I used CommandParameter so I could use it in switch-case scenario to know which button was clicked. But still, param was still null...
<Button x:Name="btnTile" Style="{StaticResource TileStyleButton}" CommandParameter="{Binding}" Command="{Binding Path=TileClickCommand, ElementName=Tile}" >
</Button>
TileCommand = new MyCommand() { CanExecuteFunc = param => CanExecuteCommand(), ExecuteFunc = param => Tile_TileClick(param)}
After 2 whole damn days, I changed it:
From this:
<UserControl Name="Tile"...>
<Button x:Name="btnTile" Style="{StaticResource TileStyleButton}" CommandParameter="{Binding Tag, ElementName=Tile}" Command="{Binding Path=TileClickCommand, ElementName=Tile}" >
</Button>
</UserControl>
To this:
<UserControl Name="Tile"...>
<Button x:Name="btnTile" Style="{StaticResource TileStyleButton}" CommandParameter="{Binding}" Command="{Binding Path=TileClickCommand, ElementName=Tile}" >
</Button>
</UserControl>
My first post does error because CommandParameter does not know where to get its DataContext so I replaced it to CommandParameter={Binding} so it will get whatever from the DataContext.
I have an issue with switching views in a WPF MVVM app.
When clicking on menu items defined in the main view, switching works fine.
When clicking on a button in a child view, switching does not work as expected.
If I set contentcontrol in child view (where the button is) as well as parent view,
the child view gets displayed mixed with previous displayed view, a button from one view and background from the one I want to switch to.
Without it, the debugger shows something happening, similar steps in the ViewModelBase class to what happened when choosing from the menu mentioned above but no visual changes in the window.
I have commands in a ViewmodelBase (that all viewmodels inherit from either directly or through a mainviewmodel) class that gets called from bindings such as in the XAML above.
CurrentViewModel is a property in ViewModelBase that is used to determine which view gets displayed. In the constructor of ViewModelBase i set commands for example:
CategoryVMCommand = new RelayCommand(() => ExecuteCategoryVMCommand());
(RelayCommand from the line above comes from the MVVM light framework,
although its not necessary for the solution to use that framework)
I found many tutorials and answers for similar problems, but couldnt get any of them to work. For example I tried, without success, using IOC for a similar problem in the below link:
MVVM Main window control bind from child user control
Here are some of the code involved and description of what Im doing:
Main Window:
<Grid>
<ContentControl Content="{Binding CurrentViewModel}" />
<DockPanel Margin="0,0,0,50">
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="_Open" Command="{Binding CategoryVMCommand}"/>
<MenuItem Header="_Close"/>
<MenuItem Header="_Save"/>
</MenuItem>
<MenuItem Header="_New">
<MenuItem Header="_Create" Command="{Binding MainControlVMCommand}"/>
</MenuItem>
</Menu>
<StackPanel></StackPanel>
</DockPanel>
</Grid>
</Window>
Then I select Menu item New, the following view is displayed:
<UserControl x:Class="WpfApplication1.MainControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<Grid>
<!--<ContentControl Content="{Binding CurrentViewModel, Mode=OneWay}" />-->
<TextBlock HorizontalAlignment="Left" Margin="10,20,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="39" Width="144" FontSize="24"><Run Language="en-gb" Text="TITLE"/><LineBreak/><Run Language="en-gb"/></TextBlock>
<Button Content="Open category" HorizontalAlignment="Left" Margin="10,136,0,0" VerticalAlignment="Top" Width="153" Height="63" Command="{Binding CategoryVMCommand}" />
<Button Content="Create new category" HorizontalAlignment="Left" Margin="10,218,0,0" VerticalAlignment="Top" Width="153" Height="63"/>
<ListBox HorizontalAlignment="Left" Height="145" Margin="293,136,0,0" VerticalAlignment="Top" Width="201" Background="#FFDDDDDD"/>
<TextBlock HorizontalAlignment="Left" Margin="293,107,0,0" TextWrapping="Wrap" Text="Recently Used" VerticalAlignment="Top" FontSize="18"/>
</Grid>
</UserControl>
button open category clicked, and Currentviewmodel set code executes (depending on ContenControl in MainControl view being commented out or not either
return or assigned), then The ExecuteCategoryCommand get executed. Then the line with the expected command in ViewModelBase constructor executes, although
either no change or the mixed result i mentioned originally
ViewModelBase class:
namespace ViewModel
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ViewModelBase _currentViewModel;
public ICommand CategoryVMCommand { get; private set; }
public ICommand MainControlVMCommand { get; private set; }
protected void NotifyPropertyChanged( String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public ViewModelBase()
{
MainControlVMCommand = new RelayCommand(() => ExecuteMainControlVMCommand());
CategoryVMCommand = new RelayCommand(() => ExecuteCategoryVMCommand());
}
public ViewModelBase CurrentViewModel
{
get
{
return _currentViewModel;
}
set
{
if (_currentViewModel == value)
return;
_currentViewModel = value;
NotifyPropertyChanged("CurrentViewModel");
}
}
protected void ExecuteCategoryVMCommand()
{
CurrentViewModel = null;
CurrentViewModel = new CategoryVM();
}
protected void ExecuteMainControlVMCommand()
{
CurrentViewModel = null;
CurrentViewModel = new MainControlVM();
}
}
}
So my question is how can I click the button in the child view, send command from ViewModelBase, set CurrentViewModel, and successfully switch views within one window without any visual remains of the previously displayed view?
Thanks for any help.
I want to change UserControls on button clicks (I'm not going to complicate here, so I'll only mention important parts). So idea was to bind ViewModels of those UserControls to ContentControl, and than associate them Views using DataTemplates.
Here's the code:
<Window x:Class="Project.MainWindow">
<Window.Resources>
<DataTemplate DataType="{x:Type UserControl:ViewUserControlViewModel}" >
<UserControl:ViewUserControl/>
</DataTemplate>
<DataTemplate DataType="{x:Type UserControl:EditUserControlViewModel}" >
<UserControl:EditUserControl/>
</DataTemplate>
</Window.Resources>
<Grid>
<ContentControl DataContext="{Binding UserControlViewModel}" />
<Button Content="View" Click="ChangeToView()"/>
<Button Content="Edit" Click="ChangeToEdit()"/>
</Grid>
</Window>
ViewModel:
public class MainWindowViewModel : DependencyObject
{
public DependencyObject UserControlViewModel
{
get { return (DependencyObject)GetValue(UserControlViewModelProperty); }
set { SetValue(UserControlViewModelProperty, value); }
}
public static readonly DependencyProperty UserControlViewModelProperty =
DependencyProperty.Register("UserControlViewModel", typeof(DependencyObject), typeof(MainWindowViewModel), new PropertyMetadata());
public MainWindowViewModel()
{
UserControlViewModel = new EditUserControlViewModel();
}
}
But theres a problem. When I start project, I only see buttons but not any UserControls. What did I do wrong?
If your Window.DataContext is properly set to MainWindowViewModel this should do the job
<ContentControl Content="{Binding UserControlViewModel}" />
When doing mvvm your viewmodel should implement INotifyPropertyChanged and not inherit from DependencyObject.
public class MainWindowViewModel : INotifyPropertyChanged
{
private object _currentWorkspace; //instead of object type you can use a base class or interface
public object CurrentWorkspace
{
get { return this._currentWorkspace; }
set { this._currentWorkspace = value; OnPropertyChanged("CurrentWorkspace"); }
}
public MainWindowViewModel()
{
CurrentWorkspace= new EditUserControlViewModel();
}
//todo: to switch the workspace, create DelegeCommand/RelayCommand and set the CurrentWorkspace
//if you don't know about these commands let me know and i post it
public ICommand SwitchToViewCommand {get{...}}
public ICommand SwitchToEditCommand {get{...}}
}
xaml: you should set the Content Property to your CurrentWorkspace.
<ContentPresenter Content="{Binding UserControlViewModel}" />
<Button Content="View" Comamnd="{Binding SwitchToViewCommand}"/>
<Button Content="Edit" Comamnd="{Binding SwitchToEditCommand}"/>
! Don't forget to set the DataContext for your window to your MainWindowViewModel instance.
First of all you should post the code of your UserControl since (in your code snippet above) it's responsible for displaying some data.
Second you are not binding anything in your code.
Third your implementation of the ViewModel is wrong. You don't need to subclass a DependencyObject but instead implement the INotifyPropertyChanged interface in order to establish a ViewModel that is capable of notifying your View.
Fourth I don't know what you are doing with
<ContentControl DataContext="{Binding UserControlViewModel}" />
maybe you can explain further ?
Fifth when implementing the MVVM patterm (what you currently not do) you should avoid using events like the click event and instead use Commands.
(I know that's not a real answer yet, but I don't wanted to write in comment syntax)
Ok, so I've been grinding away for hours now and still can't figure out why my data in my ViewModel is not being bound to my XAML in my main page. I even started an new project and implemented it fine the same way so I'm thinking it might have to do with namespaces or something I'm less familiar with.
When my application launches I create a global ViewModel in App.cs which I use to bind data to my XAML view.
public HomeViewModel ViewModel { get; private set; }
private void Application_Launching(object sender, LaunchingEventArgs e)
{
ViewModel = new HomeViewModel();
(App.Current as App).RootFrame.DataContext = (App.Current as App).ViewModel;
}
Then the HomeViewModel looks something like this:
public class HomeViewModel : INotifyPropertyChanged
{
/***View Model***/
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public HomeViewModel()
{
PropertyChanged = new PropertyChangedEventHandler(delegate { });
}
public Profile CurrentProfile; /*EDIT: Missing {get;set;} Which is necessary for
*any property, including ones below that I
*referenced in the XAML
*/
public string NotificationImage;
public ButtonPanelPath UniversalButtonPath;
public void setProfile(Profile p)
{
CurrentProfile = p;
NotifyPropertyChanged("CurrentProfile");
}
.
.
....rest of access methods and properties
Now when my program runs I am 100% sure that the data in HomeViewModel is getting updated and the NotifyPropertyChanged method is being called every time a new field is "set".
And this class is bound to the RootFrame right? So shouldn't I be able to access these fields in my main page's xaml? This is an example of part of the xaml in a stack panel in the main grid:
<Border BorderThickness="5" BorderBrush="Aqua" CornerRadius="20">
<StackPanel Name="profileInfo" DataContext="{Binding CurrentProfile}">
<TextBlock Text="{Binding FirstName}" Name="profileName" FontSize="26"
FontWeight="Bold" HorizontalAlignment="Center" />
<StackPanel Orientation="Horizontal">
<StackPanel>
<TextBlock Text="{Binding Level}" Name="userLevel" FontSize="32"
Margin="10,0,0,0"/>
<TextBlock Text="{Binding LevelName}" Name="levelName" FontSize="26"
Margin="10,0,0,0"/>
<TextBlock Text="{Binding PointsNeeded}" Name="pointsBar"
Margin="10,0,0,0"/>
</StackPanel>
<Image x:Name="levelIcon" Source="{Binding PictureUrl}"
Margin="15,0,0,0"/>
</StackPanel>
</StackPanel>
</Border>
So here Level, LevelName, PointsNeeded and PictureUrl are all public fields in Profile (or CurrentProfile which is the specific instance of Profile I'm referencing). I tried Profile.[field] but that didn't work either. If anyone could tell me what I'm missing to complete the binding it would be greatly appreciated.
By the way the namespaces are as follows if that means anything
-MainPage is in MyApp.src.pages
-App is in MyApp
-HomeViewModel is in MyApp.src.classes
Thanks in advance for your helpful solutions/comments, if you'd like more data/info please just ask.
The binding you are looking for is {Binding Proptery.SubProperty}.
So in your case for example {Binding CurrentProfile.Level}.
You are having an instance of your "HomeViewModel" in the DataContext, so you can access all of its propteries. If there is a complex type as a property, you have to access the property, the instance of the complex type not the type, to access its "sub"-properties.
Hope it helps.