|
Member 12880595 wrote: public MainWindowViewModel()
{
homeVM = new HomeViewModel();
Member 12880595 wrote: public HomeViewModel()
{
...
MwVm = new MainWindowViewModel();
So MainWindowViewModel creates a new HomeViewModel , which creates a new MainWindowViewModel , which creates a new HomeViewModel , which creates...
A classic case of infinite recursion.
Change your code to pass the current MainWindowViewModel instance to each of the child viewmodels:
public MainWindowViewModel()
{
homeVM = new HomeViewModel(this);
addEditVM = new AddEditViewModel(this);
notesVM = new NotesViewModel(this);
statsVM = new StatsViewModel(this);
...
}
...
public HomeViewModel(MainWindowViewModel mwVm)
{
MwVm = mwVm;
...
}
...
public AddEditViewModel(MainWindowViewModel mwVm)
{
MwVm = mwVm;
...
}
...
public NotesViewModel(MainWindowViewModel mwVm)
{
MwVm = mwVm;
...
}
...
public StatsViewModel(MainWindowViewModel mwVm)
{
MwVm = mwVm;
...
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thank you, it works!
But, how can i make the view change?
Assuming i have a MainWindowViewModel property in each "lower" ViewModel class, should i bind my contextmenu buttons to it, and RaisePropertyChanged, and add a call in the setter to the method i use in the MainViewModel to Display my AddEditView?
|
|
|
|
|
The simplest option is to call the method directly, since it's public:
public void ViewChange()
{
MwVm.DisplayAddEditView();
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
I have tried, to call the method, by having a MainWindowViewModel property, and call ViewChangeMethod() in the setter, but it doesnt work;
public HomeViewModel(MainWindowViewModel mwvm)
{
TaskList = new ObservableCollection<Models.Task>(tDC.Tasks);
MwVm = mwvm;
}
public MainWindowViewModel MwVm
{
get { return _mwVm; }
set {if(value != null)
_mwVm = value;
RaisePropertyChanged();
ViewChange();
}
}
<ListView x:Name="LstVviewTaskList" Height="181" Width="120" Margin="10,35,270,0" VerticalAlignment="Top" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" ItemsSource="{Binding TaskList}" SelectedItem="{Binding SelectedTask,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Add Task" Background="AliceBlue" Command="{Binding MwVm, UpdateSourceTrigger=PropertyChanged}"/>
<MenuItem Header="Edit Task" Background="AliceBlue" Command="{Binding MwVm, UpdateSourceTrigger=PropertyChanged}"/>
<MenuItem Header="Remove Task" Background="AliceBlue" Command="{Binding MwVm, UpdateSourceTrigger=PropertyChanged}"/>
</ContextMenu>
</ListView.ContextMenu>
What should i make sure i checked/have to check, in this case?
If i bind a contextmenu item(located in my HomeView) to a MainWindow Button, and the command associated with it, should i specify the datacontext in xaml?
|
|
|
|
|
That code makes no sense.
Firstly, when you create the new HomeViewModel , you're immediately trying to switch the view to the AddEditViewModel . Since you haven't created that viewmodel at this point, it's not going to work.
MainWindowViewModel.ctor
⇒ HomeViewModel.ctor
⇒ HomeViewModel.MwVm.set
⇒ HomeViewModel.ViewChange
⇒ MainWindowViewModel.DisplayAddEditView
Secondly, the MainWindowViewModel is not an ICommand . You can't use it as the Command property in the context menu.
Commanding Overview[^]
Introduction to WPF Commands[^]
Using WPF commands[^]
Implementing a custom WPF Command[^]
Take a step back and think about what you're trying to do.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Ok, i will try and rethink the project(or at least the view changing&commanding part).
Thank you for helping me!
|
|
|
|
|
I have a static class called AppCore. It contains a reference to the currently logged in user:
public static class AppCore
{
public static UserEntity CurrentUser { get; private set; }
public static void Login()
{
}
}
I want to to display the CurrentUser.FullName on the main widnow:
<TextBlock Text="{Binding Source={x:Static local:AppCore.CurrentUser}, Path=FullName, Mode=TwoWay}"/>
When I log in, I don't see the user's name. I suspect its because I can't implemenet I NotifyPropertyChanged in a static class.
Is there a way to do this that I'm not seeing?
Thanks
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
If you're using .NET 4.5 or higher, you can:
What's New in WPF Version 4.5 - Binding to static properties[^]
public static class AppCore
{
public static UserEntity CurrentUser { get; private set; }
public static event EventHandler CurrentUserChanged;
public static void Login()
{
CurrentUserChanged?.Invoke(null, EventArgs.Empty);
}
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
How does that get the UI to refresh? The event is raised, but so what? I need the bound value in the UI to update
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Read the link:
The data binding engine recognizes when the property's value changes if a static event is raised.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
You know, I read that and my mind glossed right over it.
So I now have:
<TextBlock Text="{Binding Source={x:Static local:AppCore.CurrentUser}, Path=FullName, Mode=TwoWay}"/>
and in AppCore:
public static class AppCore
{
public static event EventHandler CurrentUserChanged;
public static UserEntity CurrentUser { get; private set; }
public static bool Login(CredentialEntity credentials)
{
var loggedIn = false;
LoginResponse response = _appSecurity.Login(credentials);
if (response.Result == Result.Success)
{
CurrentUser = response.User;
CurrentUserChanged?.Invoke(null, EventArgs.Empty);
loggedIn = true;
}
return loggedIn;
}
}
when I log in, the Full name doesn't appear in the UI. Output Windows doesn't reveal anything.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
It's probably the x:Static markup extension. Try changing the binding to:
<TextBlock Text="{Binding Path=(local:AppCore.CurrentUser.FullName), Mode=TwoWay}"/>
WPF 4.5: Binding and change notification for static properties - Pete Brown's 10rem.net[^]
EDIT: This blog seems to confirm it:
It does not work with the x:Static extension
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
ya I tried that already. I get "Nested types are not supported: AppCore.Currentuser"
I read a blog post about WPF getting confused with all the '.'s.. something about confusion between the nesting and property attributes.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Did you try surrounding the path with brackets?
Path=(local:AppCore.CurrentUser.FullName)
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Yes
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
OK. How about binding the DataContext to the user, and then binding the Text to the name?
<TextBlock DataContext="{Binding Path=(local:AppCore.CurrentUser)}" Text="{Binding Path=FullName, Mode=TwoWay}"/>
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
SUCCESS!
I followed the Second Approach on that blog you posted and it worked!
public static class AppCore
{
public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged;
public static UserEntity CurrentUser { get; private set; }
private static string _FullName;
public static string FullName
{
get { return _FullName; }
set
{
if (_FullName != value)
{
_FullName = value;
NotifyStaticPropertyChanged("FullName");
}
}
}
private static void NotifyStaticPropertyChanged(string propertyName)
{
if (StaticPropertyChanged != null)
StaticPropertyChanged(null, new PropertyChangedEventArgs(propertyName));
}
public static bool Login(CredentialEntity credentials)
{
var loggedIn = false;
LoginResponse response = _appSecurity.Login(credentials);
if (response.Result == Result.Success)
{
CurrentUser = response.User;
FullName = response.User.FullName;
loggedIn = true;
}
return loggedIn;
}
}
Thanks for your help & patience!!
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
What's the best way to make a Chess board using WPF and MVVM?
On startup I want to create an 8x8 grid of Squares.
Right now I added all 64 Sqaures to a <grid> in the XAML. But to make this work with MVVM I'll need some form of binding.
Not sure of how to architect this.
Anyone?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Kevin Marois wrote: What's the best way to make a Chess board using WPF and MVVM? I asked myself the same question before working on StockChess[^] and I'm guessing you've figured out by now that the approach you've mentioned will not get you the result you want. If you want it to be MVVM friendly you will just have to create an items control that uses a Grid for its ItemsPanelTemplate . If you use an items control that enables you to select an item then even better, like a ListBox .
"As beings of finite lifespan, our contributions to the sum of human knowledge is one of the greatest endeavors we can undertake and one of the defining characteristics of humanity itself"
|
|
|
|
|
I have a MetroTabControl that I want to use to display several RDP connections using the TabItems, the problem that I`m having is, after I establish the first RDP connection, If I switch tabItem, the view goes out of scope and I loose the connection in that TabItem (so each time I switch tabitem the view goes out of scope). I wanted to maintain the connection alive in each TabItem and control the close of the view with the CloseTabCommand using the tabitem CloseButton.
In this sample the RemoteClients is an Observable collection of an objectClass that each TabItem will bind to
e.g. ObservableCollection<RdpClient>RemoteClients{get; set;}
The SelectedRemoteClient represents the current selected object (RdpClient).
RemoteDesktopBaseControlView is the view that each TabItem will have and has all the bindings for the RdpClient object
<Grid>
<controls:MetroTabControl VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding RemoteClients, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedRemoteClient, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
CloseTabCommand="{Binding CloseTabCommand}" >
<controls:MetroTabControl.Resources>
<DataTemplate x:Key="contentTemplate" x:Shared="False">
<local:RemoteDesktopBaseControlView />
</DataTemplate>
</controls:MetroTabControl.Resources>
<controls:MetroTabControl.ItemContainerStyle>
<Style TargetType="{x:Type controls:MetroTabItem}">
<Setter Property="Header" Value="{Binding ViewTitle, UpdateSourceTrigger=PropertyChanged}" />
<Setter Property="controls:MetroTabItem.ContentTemplate" Value="{StaticResource contentTemplate}"/>
<Setter Property="controls:MetroTabItem.CloseButtonEnabled" Value="True"/>
<Setter Property="controls:MetroTabItem.CloseTabCommandParameter" Value="{Binding}" />
<Setter Property="controls:ControlsHelper.HeaderFontSize" Value="16" />
<Setter Property="controls:ControlsHelper.HeaderMargin" Value="4" />
</Style>
</controls:MetroTabControl.ItemContainerStyle>
</controls:MetroTabControl>
</Grid>
Any Ideas how to fix this?
|
|
|
|
|
I have no idea what MetroTabControl is (other than a TabControl), but it sounds like it inherits the problem from the standard TabControl whereby switching tabs closes the view and creates a new one. If this is the case, you'll need to put in a version of the fix described here[^].
This space for rent
|
|
|
|
|
Hi, you`re right the controls:MetroTabControl is just a stylized version of the TabControl, removing the "controls:Metro" and leaving the <tabcontrol the="" behavior="" is="" same.="" i="" try="" extension="" but="" not="" working="" still="" same="" and="" it="" leaks="" memory.="" created="" tabcontrolex.cs="" add="" <style="" targettype="{x:Type local:TabControlEx}"> in the <usercontrol.resources> for the view but no change... do I need to do something else?
Thank you
|
|
|
|
|
|
I'm creating a chess game.
The board is made up of a grid of user controls called BoardSqaure:
<UserControl x:Class="Chess.UI.WPF.Controls.BoardSquare"
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:Chess.UI.WPF.Controls"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300">
<ContentPresenter Content="{Binding Piece}"/>
</UserControl>
and
namespace Chess.UI.WPF.Controls
{
public partial class BoardSquare : UserControl
{
public BoardSquare()
{
InitializeComponent();
}
public static readonly DependencyProperty PieceProperty =
DependencyProperty.Register("Piece",
typeof(PieceBase),
typeof(BoardSquare),
new PropertyMetadata(null));
public PieceBase Piece
{
get { return (PieceBase)GetValue(PieceProperty); }
set { SetValue(PieceProperty, value); }
}
}
}
The DP Piece will hold an instance of PieceBase, which can be King, Queen, Rook.. etc.
To load the board in the code behind I'm trying to do
private void SetupBoard()
{
BoardSquare square = board.Children.Cast<BoardSquare>().First(e => Grid.GetRow(e) == 0 && Grid.GetColumn(e) == 0);
square.Piece = new RookBlack();
square = board.Children.Cast<BoardSquare>().First(e => Grid.GetRow(e) == 0 && Grid.GetColumn(e) == 1);
square.Piece = new BishopBlack();
.
.
.
}
However the pieces never shows up.
What am I doing wrong here?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
modified 5-Dec-16 17:08pm.
|
|
|
|
|
Kevin Marois wrote: BoardSquare square = board.Children.Cast<BoardSquare>().First(e => Grid.GetRow(e) == 0 && Grid.GetColumn(e) == 0);
square.Piece = new RookBlack();
square = board.Children.Cast<BoardSquare>().First(e => Grid.GetRow(e) == 0 && Grid.GetColumn(e) == 1);
square.Piece = new BishopBlack();
Well first off the bishop doesn't go next to the rook In all seriousness though, I see nothing wrong with the code you've posted. Could you edit with all relevant Queen code? I'm assuming the other pieces are displaying properly?
|
|
|
|