I'm a new to the MVVMCross package, and C# for that matter. I've spent the better part of the day trying to figure out what I'm not understanding reading the documentation on presenters and navigation, etc. in order to try to understand, but I'm missing something.
I originally created a WPF app not implementing MVVM and now I wanted to convert, but I'm struggling with this part. I want to have a Main Menu that is part of a grid in a "MainWindow" like shell where the remaining portion of the page (and grid column 2) are used to display a nested view.
Ultimately, I’m just trying to reproduce the same layered controls in the original WPF application. In that app there is a content control Which takes up most of the form whose content property is set to a different form depending on the users selection.
MainWindow.xaml.cs
public partial class MainWindow : MvxWindow
{
public MainWindow(IMvxNavigationService navService)
{
InitializeComponent();
DataContext = new MainViewModel(navService);
//content.Content = new AdminMenuView();
}
}
MainViewModel.cs
private MvxViewModel _nextMenuContent;
public MainViewModel(IMvxNavigationService navService)
{
_navService = navService;
MoveMenuCommand = new MvxCommand(MoveMenu);
ChildViewModel = new AdminMenuViewModel();
GoToAdminMenu = new MvxCommand(SelectAdminMenu);
}
MainView.xaml
<ContentControl Content="{Binding ChildViewModel}"/>
***The grid and columns are all working fine
MainView.xaml.cs
public partial class MainView : MvxWpfView
{
public MainView()
{
InitializeComponent();
}
}
AdminMenuModel.cs
public class AdminMenuViewModel : MvxViewModel
{
private readonly IMvxNavigationService _navService;
public AdminMenuViewModel()
{
Initialize();
}
public override void Prepare()
{
base.Prepare();
}
public override async Task Initialize()
{
await base.Initialize();
}
}
AdminMenuModel.xaml.cs
public partial class AdminMenuView : MvxWpfView
{
public AdminMenuView()
{
InitializeComponent();
}
public new AdminMenuViewModel ViewModel
{
get { return base.ViewModel as AdminMenuViewModel; }
set { base.ViewModel = value; }
}
}
When I call the AdminMenuViewModel it runs, but all I get in the content control is either a blank screen if I Bind the "ChildViewModel" to the DataContext property of the content control and a string of the path to the AdminMenuViewModel if I bind it to the content property.
You have to set MainViewModel as DataContext of your main window
public MainWindow(IMvxNavigationService navService)
{
DataContext = new MainViewModel(navService);
InitializeComponent();
}
Related
I have a WPF application and here is the application structure:
Views
MainWindow.xaml, ABC.xaml (all with .cs files)
ViewModels
MainWindowVM.cs, ABCVM.cs
I have a Button in MainWindow.xaml (bound to MainWindowVM.cs) that calls a function, SampleFunction() in MainWindowVM.cs when being clicked and the SampleFunction() then creates a new instance of ABC.xaml (bound to ABCVM.cs) and open a new window of ABC.xaml using Show() function.
How can I make sure that clicking the Button in MainWindow would not open another new window of ABC.xaml when the old window is still there, or not create another new instance of ABC.xaml?
MainWindow.xaml.cs
public partial class MainWindow : Window
{
/*...Some other codes...*/
private MainWindowVM _VM = new MainWindowVM();
public MainWindowVM MainWindowVM
{
get { return _VM; }
set { _VM= value; }
}
public MainWindow()
{
InitializeComponent();
this.DataContext = MainWindowVM;
}
private void SomeControl_MouseLeftButtonUp(object sender,MouseButtonEventArgs e)
{
MainWindowVM.SampleFunction();
}
}
MainWindowVM.cs
public class MainWindowVM
{
/*...Some other codes...*/
public void SampleFunction()
{
ABC abc= new ABC();
abc.Show();
}
}
ABC.xaml.cs
public partial class ABC: Window
{
/*...Some other codes...*/
private static ABCVM _abcVM= new ABCVM();
public ABCVM ABCVM { get { return _abcVM; } set { _abcVM = value; } }
public ABC()
{
InitializeComponent();
this.DataContext = ABCVM;
}
}
Use ShowDialog() instead of Show().
Then you have to close the ABC.xaml first, before you can make something on the MainWindow. So you can't open a second ABC.xaml Window.
You can write code to check whether a window type object exists or not.
for each(Window win in Application.Current.Windows)
{
string windowType = win.GetType().ToString();
if (!windowType.Equals(nameSpace + "." + ABC))
{
ABC abc= new ABC();
abc.Show();
}
}
I have a WPF application which shows a Folder's contents in a Treeview in the MainWindowView. Now I have a new window where the user can change the location and press reload. Now I want to update the treeview in my MainWindowView as soon as the user presses the Reload button.
I am using an ObservableCollection object which is binded to the treeview. But I am not able to update the collection from the Change location window.
I want to know how to update the ObservableCollection of the MainWindowView from a different window. If I am doing any changes in the MainWindowView, then it immediately reflects in the TreeView
I am using MVVM architecture.
Is there any relationship between the MainWindow and the ChangeLocationWindow?
How does the ChangeLocationWindow show out, Show() or ShowDialog()? Check the following solution, any problems, let me know.
MainWindowViewModel:
public class MainWindowViewModel
{
public static MainWindowViewModel Instance = new MainWindowViewModel();
public ObservableCollection<string> Contents = new ObservableCollection<string>();
public string Location
{
get { return _location; }
set
{
if (_location != value)
{
_location = value;
ReloadContents();
}
}
}
private MainWindowViewModel()
{
}
private void ReloadContents()
{
// fill test data
Contents.Add("Some test data.");
}
private string _location;
}
MainWindowView:
{
public MainWindowView()
{
InitializeComponent();
MyListBox.ItemsSource = MainWindowViewModel.Instance.Contents;
var changeLocationWindow = new ChangeLocationWindow();
changeLocationWindow.Show();
}
}
ChangeLocationWindow:
public partial class ChangeLocationWindow : Window
{
public ChangeLocationWindow()
{
InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
MainWindowViewModel.Instance.Location = "Test";
}
}
The best approach to your problem is using Messaging pattern to send notifications to main viewmodel from another one about new changes.
Checkout the link for more details,
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;
}
I have a AppViewModel, that contains a menu on Top of the Window. On the AppViewModel construct, I'm showing a UserControl. In this UserControl I have a button, that calls another viewmodel (UserControl).
The idea is to keep the menu and working on the content of window. So, I have 1 window and 2 UserControls. This is correct?
How can I call another ViewModel from a button that is inside of a UserControl? Or, I have to call it from the Window? But the button it's inside of the UserControl!
My code:
class AppViewModel : Conductor<object>
{
private bool _MenuIsVisible;
public bool MenuIsVisible
{
get { return _MenuIsVisible; }
set
{
if (_MenuIsVisible != value)
{
_MenuIsVisible = value;
NotifyOfPropertyChange(() => MenuIsVisible);
}
}
}
public AppViewModel()
{
MenuIsVisible = true;
_ShowTutorial();
}
private void _ShowTutorial()
{
ActivateItem(new FirstViewModel());
}
}
public class FirstViewModel : Screen
{
protected override void OnActivate()
{
base.OnActivate();
}
}
On the FirstViewModel I have a button that needs to call SecondViewModel.
To navigate from the first ViewModel to the second ViewModel you could have a method in the first ViewModel like this:
public void NavigateToSecond()
{
var conductor = this.Parent as IConductor;
conductor.ActivateItem(new SecondViewModel());
}
The parent refers to the conductor which will take care of navigating for you.
I have spent a couple hours trying to figure out this ONE problem. Here's what is happening:
I am trying to bind a Title to my XAML file from my ViewModel. All of the code executes (I checked using breakpoints/watch), but the binding doesn't actually work. I am very new to development and especially MVVM, so I am having a hard time figuring this out. Relevant code:
App.Xaml.Cs
private static MainPageViewModel _mainPageViewModel = null;
public static MainPageViewModel MainPageViewModel
{
get
{
if (_mainPageViewModel == null)
{
_mainPageViewModel = new MainPageViewModel();
}
return _mainPageViewModel;
}
}
MainPageModel
public class MainPageModel : BaseModel
{
private string _pageTitle;
public string PageTitle
{
get { return _pageTitle; }
set
{
if (_pageTitle != value)
{
NotifyPropertyChanging();
_pageTitle = value;
NotifyPropertyChanged();
}
}
}
MainPageViewModel
private void LoadAll()
{
var page = new MainPageModel();
page.PageTitle = "title";
MainPageViewModel
public MainPageViewModel()
{
LoadAll();
}
MainPage.Xaml.Cs
public MainPage()
{
InitializeComponent();
DataContext = App.MainPageViewModel;
}
MainPage.Xaml
<Grid x:Name="LayoutRoot">
<phone:Panorama Title="{Binding PageTitle}">
Do I need a using statement in the Xaml too? I thought I just needed to set the data context in the MainPage.Xaml.Cs file.
I'm pretty sure I've posted all of the relevant code for this. Thanks everyone!!
The problem is here, in the view model class:
private void LoadAll()
{
var page = new MainPageModel();
page.PageTitle = "title";
All you've done here is create a local object "page" -- this will not be accessible anywhere outside the local scope. I suppose what you meant to do is make "page" a member of "MainPageViewModel":
public class MainPageViewModel
{
public MainPageModel Model { get; private set; }
private void LoadAll()
{
_page = new MainPageModel();
_page.PageTitle = "title";
}
}
This way, you'll be able to bind to the "PageTitle" property -- but remember, it's a nested property, so you'll need:
<phone:Panorama Title="{Binding Model.PageTitle}">