UWP Frame Navigation - c#

I create my MainPage in xaml and it has a Frame that I replace its content navigating to another pages.
Here is my frame inside my MainPage:
<SplitView.Content>
<Frame x:Name="contentFrame" x:FieldModifier="public"/>
</SplitView.Content>
I my button click I change it content:
private void createResume_Click(object sender, RoutedEventArgs e)
{
contentFrame.Navigate(typeof(CreateResume));
}
Until now, it works perfect. And the frame content will have the CreateResume.xaml page:
<Grid Background="Black">
<Grid.RowDefinitions>
<RowDefinition Height="150"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Full Name:" Foreground="White" FontSize="20" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="5" />
<TextBox Grid.Column="1" x:Name="fullName" PlaceholderText="Type your full name here" Width="250" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="5" />
<TextBlock Grid.Row="1" Text="Email:" Foreground="White" FontSize="20" HorizontalAlignment="Right" Margin="5" />
<TextBox Grid.Row="1" Grid.Column="1" x:Name="email" PlaceholderText="Type your email here" HorizontalAlignment="Left" Width="250" Margin="5" />
<TextBlock Grid.Row="2" Text="City:" Foreground="White" FontSize="20" HorizontalAlignment="Right" Margin="5" />
<TextBox Grid.Row="2" Grid.Column="1" x:Name="city" PlaceholderText="Type your city here" HorizontalAlignment="Left" Width="250" Margin="5" />
<TextBlock Grid.Row="3" Text="State:" Foreground="White" FontSize="20" HorizontalAlignment="Right" Margin="5" />
<TextBox Grid.Row="3" Grid.Column="1" x:Name="state" PlaceholderText="Type your state name here" HorizontalAlignment="Left" Width="250" Margin="5" />
<Button Grid.Row="4" Content="Save and Continue" Background="White" Foreground="DarkBlue" FontSize="20" HorizontalAlignment="Right" Click="Button_Click" />
</Grid>
Inside the CreateResume.xaml, I click on my button and I try to call another page to replace the frame content:
MainPage mainPage = new MainPage();
mainPage.contentFrame.Navigate(typeof(EducationInfo));
At this point I get an error: "An unhandled exception of type 'System.AccessViolationException' occurred"
I made the frame public, so why do I get the Access Violation Exception?

The mainPage is the new page but it dont show in Window.
If you want to Navigate to other page that you should talk to mainPage that you want to navigate and make the mainPage to navigate to other page.
The good way is use MVVM.
The first: you can bind MainPage to MainViewModel and the MainViewModel have to sub viewModel as CreateResumeViewModel and EducationInfoViewModel
I think you can write the ViewModel in the App.xaml
The code is in the App.xaml.Resource
<Application
x:Class="MehdiDiagram.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MehdiDiagram"
RequestedTheme="Light">
<Application.Resources>
<local:ViewModel x:Key="ViewModel"></local:ViewModel>
</Application.Resources>
</Application>
And you can bind the ViewModel to MainPage.
<Page
x:Class="MehdiDiagram.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MehdiDiagram"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
DataContext="{StaticResource ViewModel}"
mc:Ignorable="d">
And Bind the CreateResumeViewModel to CreateResume.
For ViewModel have two property that the one is CreateResumeViewModel.
Like the MainPage that you can bind the CreateResumeViewModel property to CreateResume.
DataContext="{Binding Source={StaticResource ViewModel},Path=CreateResumeViewModel}"
The CreateResumeViewModel have an event that call to Navigate to other page.
The ViewModel also have an event that call to Navigate to other page.
The code is in ViewModel:
class ViewModel
{
public ViewModel()
{
CreateResumeViewModel.NavigateToPage += (sender, type) =>
{
NavigateToPage?.Invoke(sender, type);
};
}
public event EventHandler<Type> NavigateToPage;
public CreateResumeViewModel CreateResumeViewModel{ get; set; }=new CreateResumeViewModel;
}
The code is in MainPage.
public MainPage()
{
this.InitializeComponent();
ViewModel = (ViewModel) DataContext;
ViewModel.NavigateToPage += ViewModel_NavigateToPage;
}
private void ViewModel_NavigateToPage(object sender, Type e)
{
Frame.Navigate(e);
}
You can use the NavigateToPage event in CreateResumeViewModel when it should navigate page.
See:https://github.com/lindexi/UWP/tree/master/uwp/src/Framework

Related

WPF Navigation Header MVVM

I need tips from you guys, I hope someone can help me.
I want to make a WPF application which has a navigation header.
By navigation header I mean: I want to have a grid on top that contains buttons and when you click on the buttons, the bottom grid should show a completely different view. These views can also contain buttons and when clicking on these buttons only the lower grid should be updated and the top should remain as it is.
Also i want to use MVVM in my application.
below in the code you could better understand what I mean
`
<Window x:Class="WpfApp1.MainWindow"
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"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Red"> <!--this should be the header for the application-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="View 1" Margin="4"/>
<Button Grid.Column="1" Content="View 2" Margin="4"/>
</Grid>
<Grid Grid.Row="1" Background="LightBlue">
<Label Content="View 1/ View 2 Content" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Grid>
</Window>
`
enter image description here
In addition to what Yannick pointed out for the visibility converter, I would do the following.
Create two additional "UserControl" classes (similar xaml markup as your window, but have each user control draw just what IT is to represent. This way, if you need to move the stuff around, you fix that one control. It still resides within your outer main window. For example.
<Window x:Class="NavigationHeader.MainWindow"
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"
xmlns:local="clr-namespace:NavigationHeader"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConv" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Red">
<!--this should be the header for the application-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="View 1" Margin="4" Command="{Binding View1Command}"/>
<Button Grid.Column="1" Content="View 2" Margin="4" Command="{Binding View2Command}"/>
</Grid>
<local:MyFirstControl
Grid.Row="1"
Background="LightCoral"
Visibility="{Binding View1Visibility,
Converter={StaticResource BoolToVisConv}}" />
<local:MySecondControl
Grid.Row="1"
Background="LightBlue"
Visibility="{Binding View2Visibility,
Converter={StaticResource BoolToVisConv}}" />
</Grid>
</Window>
<UserControl x:Class="NavigationHeader.MyFirstControl"
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"
xmlns:local="clr-namespace:NavigationHeader"
mc:Ignorable="d" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0"
Content="View 1" FontSize="24"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="1"
Text="my content" Width="100" Margin="10"/>
<Button Grid.Row="2" Grid.Column="2"
Content="Ok" Width="50" />
</Grid>
</UserControl>
<UserControl x:Class="NavigationHeader.MySecondControl"
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"
xmlns:local="clr-namespace:NavigationHeader" >
<StackPanel>
<Label Content="View 1"
FontSize="24"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBox Text="my content" Width="100" Margin="10"/>
<Button Content="Ok" Width="50" Margin="10"/>
</StackPanel>
</UserControl>
Notice the main window is referencing two more classes you would create as a user control MyFirstControl and MySecondControl. This can help keep your clutter in each respective control vs bloating the main control up and worrying about different formats such as one using a grid, and the other using a stack panel, docking panel, or whatever other type control you want to display.
I've used the community toolkit nuget package for the following. This implements inpc for me and generates some code using attributes.
The basic principle of what follows is called viewmodel first navigation. You should be able to find examples out there on the web explain more fully if you like.
To navigate this switches out a viewmodel instance which is then datatemplated into the view, with the viewmodel as datacontext.
Mainwindow
<Window.Resources>
<DataTemplate DataType="{x:Type local:AlphaViewModel}">
<local:AlphaView/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:BetaViewModel}">
<local:BetaView/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:GammaViewModel}">
<local:GammaView/>
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Red">
<!--this should be the header for the application-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Command="{Binding NavigateViewModelCommand}"
CommandParameter="{x:Type local:AlphaViewModel}"
Content="Alpha" Grid.Column="0" Margin="4"/>
<Button Command="{Binding NavigateViewModelCommand}"
CommandParameter="{x:Type local:BetaViewModel}"
Content="Beta" Grid.Column="1" Margin="4"/>
</Grid>
<Grid Grid.Row="1" Background="LightBlue">
<ContentPresenter Content="{Binding CurrentViewModel}"/>
</Grid>
</Grid>
Notice how viewmodel types are associated with usercontrols. Where an alphaviewmodel is presented to the view, it will be datatemplates with an alphaview.
Buttons bind to a command and pass a type as a parameter.
The contentpresenter is where that viewmodel will be presented to the view.
That's bound to CurrentViewModel.
MainWindowViewModel
using CommunityToolkit.Mvvm.Input;
namespace WpfVMFirst
{
public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty]
private object? currentViewModel = new GammaViewModel();
[RelayCommand]
private void NavigateViewModel(Type type)
{
var vm = Activator.CreateInstance(type);
CurrentViewModel = null;
CurrentViewModel = vm;
}
}
}
NavigateViewModel will become that NavigateViewModelCommand due to code generation.
It takes the type I mentioned above and is going to generically instantiate a viewmodel from that.
If you wanted to retain state between navigations, you could cache in a dictionary and re-use a viewmodel if it was already there.
Seting the currentviewmodel to null forces re templating. If you navigate to the same viewmodel it will force a new instance of the view usercontrol.
One of my usercontrols has a button of it's own:
Beta:
<Grid Background="Blue">
<TextBlock Text="Beta"/>
<Button HorizontalAlignment="Right"
Content="Gamma"
VerticalAlignment="Top"
Command="{Binding DataContext.NavigateViewModelCommand, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{x:Type local:GammaViewModel}"/>
</Grid>
</UserControl>
Click that button and the view is navigated to gamma.
That command works because it's using relativesource to look up the visual tree to the window, then use the command out the window's datacontext
Other viewmodels and usercontrols are pretty minimal. I have nothing in the alpha, beta and gamma viewmodels since this is just for demo purposes.
AlphaView
<Grid Background="Red">
<TextBlock Text="Alpha"/>
</Grid>
That wiring up connecting viewmodel to view type can be put into a resource dictionary merged in app.xaml.
In "real" apps the viewmodels are likely to have all sorts of functionality in them and it's usual to dependency inject those. The instantiation would be a bit more sophisticated.
As is reading any data such viewmodels require.
It's common to have an IGetData interface they implement with a GetData asynchronous task so they can be instantiated using a minimal CTOR and the data then retrieved using that abstracted method.
This is a mainstream commercial pattern which I've used and seen used successfully in real world single window apps.
Here is a begining :
Encapsulate each view in a Grid and manage their visibility in the View Model. A simple solution if you are starting with MVVM.
THE MAIN VIEW
<Window x:Class="NavigationHeader.MainWindow"
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"
xmlns:local="clr-namespace:NavigationHeader"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConv" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Red">
<!--this should be the header for the application-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="View 1" Margin="4" Command="{Binding View1Command}"/>
<Button Grid.Column="1" Content="View 2" Margin="4" Command="{Binding View2Command}"/>
</Grid>
<Grid Grid.Row="1" Background="LightCoral" Visibility="{Binding View1Visibility, Converter={StaticResource BoolToVisConv}}">
<StackPanel>
<Label Content="View 1" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBox Text="my content" Width="100" Margin="10"/>
<Button Content="Ok" Width="50" Margin="10"/>
</StackPanel>
</Grid>
<Grid Grid.Row="1" Background="LightBlue" Visibility="{Binding View2Visibility, Converter={StaticResource BoolToVisConv}}">
<Label Content="View 2" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Grid>
</Window>
THE MAIN VM
For the View Model you need to install the Nuget's Package CommunityToolkit.Mvvm as the Main VM needs these namespaces:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
public class MainVM : ObservableObject
{
private bool myView1Visibility;
private bool myView2Visibility;
public MainVM()
{
myView1Visibility = false;
myView2Visibility = false;
}
public bool View1Visibility
{
get { return myView1Visibility; }
set
{
if (value == myView1Visibility) return;
myView1Visibility = value;
OnPropertyChanged(nameof(View1Visibility));
}
}
public bool View2Visibility
{
get { return myView2Visibility; }
set
{
if (value == myView2Visibility) return;
myView2Visibility = value;
OnPropertyChanged(nameof(View2Visibility));
}
}
RelayCommand myView1Command;
RelayCommand myView2Command;
public RelayCommand View1Command
{
get
{
if (myView1Command == null)
myView1Command = new RelayCommand(View1CommandAction);
return myView1Command;
}
}
public RelayCommand View2Command
{
get
{
if (myView2Command == null)
myView2Command = new RelayCommand(View2CommandAction);
return myView2Command;
}
}
private void View1CommandAction()
{
View2Visibility = false;
View1Visibility = true;
}
private void View2CommandAction()
{
View1Visibility = false;
View2Visibility = true;
}
}
Instanciate the VM in the Main's View code behind:
public partial class MainWindow : Window
{
private readonly MainVM myMainVM;
public MainWindow()
{
InitializeComponent();
myMainVM = new MainVM();
DataContext = myMainVM;
}
}

Changing the ContentControl.Content stacks the content on top of each other

I have a MainWindow with a couple of radio buttons, a ContentControl and a button to change the content of ContentControl.
I also have a UserControl1 with a label on it. When I click the button on MainWindow to change the ContentControl.Content to UserControl1, it shows the label on top of the radio buttons I have from MainWindow. How can I change this so it acts like a page and does not stack each control on top of each other?
MainWindow.xaml:
<Window x:Class="Test.MainWindow"
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"
xmlns:local="clr-namespace:Test"
mc:Ignorable="d"
Title="Test" WindowStartupLocation="CenterScreen" Width="968" Height="560" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Height="540" Margin="0,10,-6,-19" Width="968">
<StackPanel Height="74" Margin="731,446,0,0" VerticalAlignment="Top" Width="229" Orientation="Horizontal" HorizontalAlignment="Left">
<Button Content="Back" MinWidth="100" Margin="10,20,0,0"/>
<Button Content="Next" MinWidth="100" Margin="10,20,0,0" Click="NextBtnClick"/>
</StackPanel>
<RadioButton x:Name="RadioBtn1" Content="Radio1" HorizontalAlignment="Center" Margin="312,130,95,0" VerticalAlignment="Top" Height="76" Width="561" FontSize="48" FontWeight="Bold" GroupName="1"/>
<RadioButton x:Name="RadioBtn2" Content="Radio2" HorizontalAlignment="Center" Margin="312,232,95,0" VerticalAlignment="Top" Height="76" Width="561" FontSize="48" FontWeight="Bold" GroupName="1"/>
<ContentControl x:Name="contentControl" Grid.Row="1"/>
</Grid>
</Window>
MainWindow.xaml.cs:
private void NextBtnClick(object sender, RoutedEventArgs e)
{
if (RadioBtn2.IsChecked == true)
{
this.contentControl.Content = new UserControl1();
}
}
After clicking the next button, I get the controls from UserControl1 stacked on top of the radio buttons.
I'm quite new to WPF so any help would be greatly appreciated. Navigating through the docs is a nightmare because I'm not sure how to tackle this problem.
You can trying to use Grid panel without defining rows and column definitions. As per your code, you are trying define the panel layout by hardcoded Margin, Width and Height. That's why contorls are rendered on top of each other.
I've changed the Grid code to define the Row Definitions so that controls are stacked on row basis. So when you click on Button the ContentContrl is loaded to last Row so (which is defined as Height="*" via RowDefinition to take the remaining space)
You can read about WPF Panels and Grid layout at internet. This can be a good start.
<Window x:Class="Test.MainWindow"
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"
xmlns:local="clr-namespace:Test"
mc:Ignorable="d"
Title="Test" WindowStartupLocation="CenterScreen" Width="968" Height="560" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10 10 10 10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions?
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Left">
<Button Content="Back" MinWidth="100" />
<Button Content="Next" MinWidth="100" Click="NextBtnClick"/>
</StackPanel>
<RadioButton Grid.Row="1" x:Name="RadioBtn1" Content="Radio1" HorizontalAlignment="Center" VerticalAlignment="Top" FontWeight="Bold" GroupName="1"/>
<RadioButton Grid.Row="2" x:Name="RadioBtn2" Content="Radio2" HorizontalAlignment="Center" FontSize="48" FontWeight="Bold" GroupName="1"/>
<ContentControl x:Name="contentControl" Grid.Row="3"/>
</Grid>
</Window>

how to update multiple user controls in same window WPF MVVM

I have a scenario that i am having four user controls in a window(like address, Skills, Personal info and General info each user control is having their own controls like textbox labels etc....) each user control having their own View Model
ex: General Info Control having A combo box which has list of persons and a text box Age, and text box Gender
Address is having 3 text boxes Street, Area, City
Skills control having 2 Text boxes Soft Skills and Tech Skills
so when user selects a particular person from the combo box then it has to update all the user controls with that particular person data
Main Window
<Window x:Class="CTSWpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:View="clr-namespace:CTSWpfApplication.View"
xmlns:localViewModel="clr-namespace:CTSWpfApplication.ViewModel"
Title="MainWindow" Height="600" Width="1000">
<Window.Resources>
<DataTemplate DataType="{x:Type localViewModel:PersonViewModel}">
<View:PersonVorw/>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20*"/>
<RowDefinition Height="20*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20*"/>
<ColumnDefinition Width="20*"/>
</Grid.ColumnDefinitions>
<View:PersonVorw Grid.Row="0" Grid.Column="0" DataContext="{Binding PersonViewModel}"/>
<View:AddressView Grid.Row="0" Grid.Column="1"/>
<View:SkillsView Grid.Row="1" Grid.Column="0"/>
<View:PersonalInfoView Grid.Row="1" Grid.Column="1"/>
</Grid>
User Control PersonGeneralInfo(View)
<UserControl x:Class="CTSWpfApplication.View.PersonVorw"
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:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="500">
<Grid DataContext="{Binding PersonGenModel}">
<Grid.RowDefinitions>
<RowDefinition Height="40*"/>
<RowDefinition Height="20*"/>
<RowDefinition Height="20*"/>
<RowDefinition Height="20*"/>
<RowDefinition Height="20*"/>
<RowDefinition Height="20*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20*"/>
<ColumnDefinition Width="30*"/>
<ColumnDefinition Width="20*"/>
</Grid.ColumnDefinitions>
<ComboBox Height="25" Width="150" Grid.Column="1" Name="NameSelection" ItemsSource="{Binding ListFirstName}" SelectedValuePath="Key" DisplayMemberPath="Value" SelectedItem="{Binding MySelectedItem}">
</ComboBox>
<Label Height="25" Width="100" Content="First Name" Grid.Row="1" Grid.Column="0" />
<Label Height="25" Width="100" Content="Middle Name" Grid.Row="1" Grid.Column="1"/>
<Label Height="25" Width="100" Content="Last Name" Grid.Row="1" Grid.Column="2"/>
<TextBox Height="25" Width="120" Grid.Column="0" Grid.Row="2" Name="TxTFirstName" Text="{Binding FirstName}"/>
<TextBox Height="25" Width="120" Grid.Column="1" Grid.Row="2" Name="TxTMiddleName" Text="{Binding MiddleName}"/>
<TextBox Height="25" Width="120" Grid.Column="2" Grid.Row="2" Name="TxTLastName" Text="{Binding LastName}"/>
<Label Height="25" Width="100" Content="Age" Grid.Row="3" Grid.Column="0"/>
<Label Height="25" Width="100" Content="Gender" Grid.Row="4" Grid.Column="0"/>
<TextBox Height="25" Width="120" Grid.Column="1" Grid.Row="3" Name="TxTAge" Text="{Binding Age}"/>
<TextBox Height="25" Width="120" Grid.Column="1" Grid.Row="4" Name="TxTGender" Text="{Binding Gender}"/>
<Button Name="BtNPerson" Height="25" Width="100" Content="Clenter code hereick to Add" Grid.Row="5" Grid.Column="2" />
</Grid>
can any one Help me on to achieve this in the best way
Please excuse me if you fine any mistakes in my post
thanks in advance
You will have to notify other ViewModels when change occurs. This article explains the patterns that can be followed to achieve the result.
You can set up a MainViewModel that creates your other ViewModels.
Create a property in each of you ViewModels called SelectedComboBoxItem.
Bind your ComboBox's SelectedItem in the MainViewModel to a command that sets
the SelectedComboBoxItem of each of the other ViewModels.
To be honest I don't know if it will work, but make sure to have INotifyPropertyChanged implemented in all of the ViewModels and their properties.
Example:
public class MainViewModel : ViewModelBase
{
private YourInfoItem _selectedComboBoxItem;
private ViewModel1 SkillsInfoVM = new ViewModel1();
private ViewModel2 PersonalInfoVM = new ViewModel2();
private ViewModel3 GeneralInfoVM = new ViewModel3();
public YourInfoItem selectedComboBoxItem
{
get {return _selectedComboBoxItem; }
set
{
_selectedComboBoxItem = value;
PropertyChanged(nameof(selectedComboBoxItem));
}
}
public MainViewModel()
{
SelectedComboBoxItemChanged = new RelayCommand(SetSelectedComboBoxItem);
}
public ICommand SelectedComboBoxItemChanged { get; private set; }
public void SetSelectedComboBoxItem()
{
SkillsInfoVM.selectedComboBoxItem = this.selectedComboBoxItem;
PersonalInfoVM.selectedComboBoxItem = this.selectedComboBoxItem;
GeneralInfoVM.selectedComboBoxItem = this.selectedComboBoxItem;
}
}
In the end you just bind the SelectedComboBoxItem to your TextBoxes in the XAML code e.g:
<TextBox Text="{Binding SelectedComboBoxItem.FirstName, UpdateSourceTrigger=OnPropertyChanged, Mode=TwoWay}"/>
and so on.
This does require you to have an object that contains all the information you want to show, you can do that by creating a class containing all the info, similar to this:
public class Info
{
public string FirstName;
public string LastName;
public string Address;
...
}

WPF XAML Using Mouse Action Event

I am learning the WPF 4.5 Unleashed book. When I tried to incorporate Mouse Action Event such as MouseEnter or MouseDoubleClick for the Button by typing the code manually, the compiler told me it could not find the reference for the Mouse Action Event. However, when I use the double Tab shortcut, everything works well. What could possibly be the issue? I have bold the trouble code below.
<Window x:Class="WpfApplicationLearning0001.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="513.265" Width="748.469">
<DockPanel>
<Menu DockPanel.Dock="Top">
</Menu>
<StackPanel Name="ButtonBar" Orientation="Horizontal" DockPanel.Dock="Right">
<StackPanel.LayoutTransform>
<RotateTransform Angle="90">
</RotateTransform>
</StackPanel.LayoutTransform>
**<Button Name="Panel1Button" MouseEnter="Panel1Button_MouseEnter">
Toolbox
</Button>**
</StackPanel>
<Grid Background="White" Margin="0,0,2,3">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Background="Black" Foreground="White" HorizontalContentAlignment="Center" Content= "Start Page"/>
<GroupBox Grid.Row="1" Grid.Column="0" Background="White" Foreground="Black" Header="Start" />
<GroupBox Grid.Row="2" Grid.Column="0" Background="White" Foreground="Black" Header="Recent" />
<GroupBox Grid.Row="3" Grid.Column="0" Background="White" Foreground="Black" Header="Option" />
<GroupBox Grid.Row="1" Grid.Column="1" Grid.RowSpan="3" Background="White" Foreground="Black" Header="Get Start">
<ListBox>
<ListBoxItem>Article number1</ListBoxItem>
<ListBoxItem>Article number2</ListBoxItem>
<ListBoxItem>Article number3</ListBoxItem>
<ListBoxItem>Article number4</ListBoxItem>
</ListBox>
</GroupBox>
</Grid>
</DockPanel>
The double click not only puts it in the XAML code, put it also creates the code behind in the .cs file of:
private void Panel1Button_MouseEnter(object sender, MouseEventArgs e)
{
}
Until you add the code behind yourself, if you are doing it manually, then the error is correct. In addition, when manually coding be sure to include (object sender, MouseEventArgs e) in the function call or it may not recognize it as a valid function call to the MouseEvent.

IsLightDismissEnabled="True" is not actually dismissing the popup

i have a pop up and i want to close it when i tap anywhere outside the pop up. i searched and everyone advised me to use the property IsLightDismissEnabled; however if i touch outside, it will only remove the pop oup leaving everything inactive with a grey like screen as if it doesnt close the pop up completely
this is my code snippet:
<Popup x:Name="logincontroler" IsOpen="False" Margin="0,190,896,276" IsLightDismissEnabled="True">
<StackPanel Height="300" Width="470" x:Name="popup" FlowDirection="RightToLeft">
<Grid Width="470" Background="White" >
<Grid.RowDefinitions>
<RowDefinition Height="70"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<RichEditBox Grid.Row="1" Height="250" TextWrapping="Wrap" FontSize="20" Name="notesPopupTextBox" FlowDirection="LeftToRight"/>
<StackPanel Grid.Row="0" Orientation="Horizontal" Background="#FFE3E3E5">
<Button Name="CanclePopupButton" Content="Cancel" Width="64" Height="64" Click="CanclePopupButton_Click" />
<Button Name="ClearNotePopupButton" Content="Clear" Width="64" Height="64" Click="ClearNotePopupButton_Click" />
<Button Name="saveNoteButton" Content="Save" Width="64" Height="64" Click="saveNoteButton_Click" />
<TextBlock FontWeight="Medium" FontSize="40" Foreground="#2a2a86" Margin="170 12 0 0">Note</TextBlock>
</StackPanel>
</Grid>
</StackPanel>
</Popup>
this is my code for the events
private void ShowButton_Click(object sender, RoutedEventArgs e)
{
logincontroler.IsOpen = true;
flipView1.IsEnabled = false;
}
private void CanclePopupButton_Click(object sender, RoutedEventArgs e)
{
logincontroler.IsOpen = false;
flipView1.IsEnabled = true;
}
Am I missing anything?
thank you in advance
Are you sure you don't have some other code in the App that you are not showing us?
There should be no Gray box behind the Popup.
I have just tested your code on an empty Windows 8.1 (XAML+C#) App and it works fine.
Try creating and Blank Windows 8.1 App and make you MainPage like this:
MainPage.xaml
<Page
x:Class="App19.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App19"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
RequestedTheme="Light">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Popup x:Name="logincontroler" IsOpen="False" Margin="0,190,896,276" IsLightDismissEnabled="True">
<StackPanel Height="320" Width="470" x:Name="popup" FlowDirection="RightToLeft">
<Grid Width="470" Background="BurlyWood" >
<Grid.RowDefinitions>
<RowDefinition Height="70"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<RichEditBox Grid.Row="1" Height="250" TextWrapping="Wrap" FontSize="20" Name="notesPopupTextBox" FlowDirection="LeftToRight"/>
<StackPanel Grid.Row="0" Orientation="Horizontal" Background="#FFE3E3E5">
<Button Name="CanclePopupButton" Content="Cancel" Width="64" Height="64" />
<Button Name="ClearNotePopupButton" Content="Clear" Width="64" Height="64" />
<Button Name="saveNoteButton" Content="Save" Width="64" Height="64" />
<TextBlock FontWeight="Medium" FontSize="40" Foreground="#2a2a86" Margin="170 12 0 0">Note</TextBlock>
</StackPanel>
</Grid>
</StackPanel>
</Popup>
<Button Content="Show Popup" HorizontalAlignment="Left" Margin="692,260,0,0" VerticalAlignment="Top" Click="ShowButton_Click"/>
</Grid>
</Page>
MainPage.xaml.cs
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace App19
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void ShowButton_Click(object sender, RoutedEventArgs e)
{
logincontroler.IsOpen = true;
}
}
}
This has to work.
And comparing this with your solution should help you find the problem. If not, just edit your question with more information. (more code)
Note: I removed the click events from your popup, they were not needed to exemplify your problem, right?

Categories

Resources