I made a class for store ViewModels
internal class Locator
{
public MainViewModel MainViewModel { get; } = new MainViewModel();
}
And added it to application resources
<Application x:Class="Marathon.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Marathon"
StartupUri="MainWindow.xaml">
<Application.Resources>
<local:Locator x:Key="Locator" x:Name="Locator"/>
</Application.Resources>
</Application>
Then bound it Locator to the Main Window
<Window x:Class="App.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"
mc:Ignorable="d"
DataContext="{Binding Source={StaticResource Locator}, Path=MainViewModel}"
Title="MainWindow" MinHeight="350" MinWidth="525">
<Grid>
<Frame Content="{Binding Page}"></Frame>
</Grid>
</Window>
It works.
When I add a binding (DataContext) to a Page. It throws an exception (System.Windows.Markup.XamlParseException, Cannot find resource named 'Locator'.).
<Page x:Class="App.Pages.StartPage"
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"
mc:Ignorable="d"
DataContext="{Binding Source={StaticResource Locator}, Path=MainViewModel}"
Title="StartPage">
<Grid>
</Grid>
</Page>
How to bind DataContext to a page?
You don't need x:Name in your App.xaml declaration of the locator instance, x:Key is sufficient
The error most occurs if and when you instantiate the Page itself in the view model.
A view model shouldn't create Page objects. Try to return a Uri instead and bind to the Source property instead:
<Window x:Class="App.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"
mc:Ignorable="d"
DataContext="{Binding Source={StaticResource Locator}, Path=MainViewModel}"
Title="MainWindow" MinHeight="350" MinWidth="525">
<Grid>
<Frame Source="{Binding Page}" />
</Grid>
</Window>
This should work:
public class MainViewModel
{
public Uri Page { get; } = new Uri("Page1.xaml", UriKind.RelativeOrAbsolute);
}
Related
I don't want to use Prism or MVVM Light solutions and would like to pass two parameters to the second window? How could I do that? I was looking for some information on this topic, but unfortunately most of them use packages...
try this:
App.xaml
<Application.Resources>
<vm:MainViewModel x:Key="YourViewModel" />
</Application.Resources>
MainWindow.xaml
<Window x:Class="ABC.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:ABC"
DataContext="{StaticResource YourViewModel}"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TextBlock Text="{Binding SomeVar}"/>
</Grid>
</Window>
SecondWindow.xaml
<Window x:Class="ABC.SecondWindow"
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:ABC"
DataContext="{StaticResource YourViewModel}"
mc:Ignorable="d"
Title="SecondWindow" Height="450" Width="800">
<Grid>
<TextBox Text="{Binding SomeVar}"/>
</Grid>
</Window>
I guess you could just send parameters in the constructor of the second window, wherever you are creating your window.
var newwin = new SecondWindow("second param is int", 42 );
newwin.Show();
And then just create an another constructor for your window:
public SecondWindow(string a, int b) : this()
{
var secondVM = (SecondViewModel)DataContext;
secondVM.IAmSendingYouTwoParams( a,b);
...
}
I have a UserControl that contain let's say a button (or any other object).
<UserControl x:Class="StackOverFlowQuestion.UserControlButton"
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:StackOverFlowQuestion"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Button
x:Name="Button1"
Content="Click me for testing"/>
</Grid>
</UserControl>
and I want to access that Button's(Or any Object) Click Event or any Event form the parent that contains the UserControl.
<Window x:Class="StackOverFlowQuestion.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:StackOverFlowQuestion"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:UserControlButton/>
</Grid>
</Window>
Thanks.
It's quite easy. Just put a public event to the UserControl (code behind) for it could be accessible from outside of UserControl and do forward the Click event from your button.
public partial class UserControlButton : UserControl
{
public event RoutedEventHandler ButtonClick;
private void UsrCtlButton_Click(object sender, RoutedEventArgs e)
{
ButtonClick?.Invoke(sender, e);
}
}
XAML of UserControl:
<Button x:Name="Button1" Content="Click me for testing" Click="UsrCtlButton_Click"/>
XAML where UserControl being used:
<local:UserControlButton ButtonClick="Some_event_handler_to_handle_Button_Click"/>
I have an user control:
<UserControl x:Class="WpfApplication2.Control1"
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:WpfApplication2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel Orientation="Horizontal" Name="StackPanelInsideUserControl">
<Label />
<TextBox Name="TextBoxInsideUserControl" Text="Initial Text" />
<Button Content="OK" />
</StackPanel>
</Grid>
And I'm trying to bind to the Text property of the TextBoxInsideUserControl TextBox from a its parent like in:
<Window x:Class="WpfApplication2.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:WpfApplication2"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:Control1 StackPanelInsideUserControl.TextBoxInsideUserControl.Text="{Binding SomeText}" />
</Grid>
How can I achieve that? Does xaml allow us to do that?
As requested, the comment as answer:
No, not really. You should define a dependency property on that UserControl, bind that to the Text of the TextBox. Then you can access the text outside of the UserControl via that dependency property.
My requirement is masterpage in windows phone 8.1 blank template, i searched in the google, they suggest the usercontrol, i applied that scenario but not working,Below is my tried sample code.
`I'm try create Application where i required to use User Control.I'm already created MainPage.xaml here code below
`
<Page
x:Class="VtDesigning.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:VtDesigning"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
</Grid>
</Page>
and usercontrol defined below
<UserControl
x:Class="VtDesigning.MyUserControl2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:VtDesigning"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<StackPanel Height="50" Background="Chocolate">
<TextBlock Text="hi hellow how are you"
FontSize="25"
Margin="0,0,154,0"/>
</StackPanel>
</Grid>
</UserControl>
How to i call this usercontrol in MainPage.xaml.
Thanks,
Venky.
Set a reference to the location of the user control and add the user control to your layout as a normal control
<Page
x:Class="VtDesigning.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:VtDesigning"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:project="using:MyProject.UserControls"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<project:MyUserControl/>
</Grid>
I'm developing an WPF (C#) application using MVVM. I've created a new project which is a simplification that focuses only on the problem I have.
In the View there is a Panel which is composed by a PanelButton which consists on two buttons and PanelDisplay.
The idea is that when orange button is pressed the PanelDisplay should change its color to orange and when green button is pressed PanelDisplay should change to green.
Code for Panel:
<UserControl x:Class="WpfApplication1.View.Panel"
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:view="clr-namespace:WpfApplication1.View"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="600">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*"/>
<ColumnDefinition Width="0.7*"/>
</Grid.ColumnDefinitions>
<view:PanelButtons Grid.Column="0"></view:PanelButtons>
<view:PanelDisplay Grid.Column="1"></view:PanelDisplay>
</Grid>
</UserControl>
The code for PanelButtons.xaml:
<UserControl x:Class="WpfApplication1.View.PanelButtons"
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:viewModel="clr-namespace:WpfApplication1.ViewModel"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<viewModel:PanelButtonsAndDisplayVM x:Key="panelButtonsAndDisplayVM"/>
</UserControl.Resources>
<Grid Background="LightGray">
<StackPanel>
<Button Width="64" Height="64"
Command="{Binding Source={StaticResource panelButtonsAndDisplayVM}, Path=PressedOrange}">Orange</Button>
<Button Width="64" Height="64"
Command="{Binding Source={StaticResource panelButtonsAndDisplayVM}, Path=PressedGreen}">Green</Button>
</StackPanel>
</Grid>
The code for PanelDisplay.xaml:
<UserControl x:Class="WpfApplication1.View.PanelDisplay"
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:viewModel="clr-namespace:WpfApplication1.ViewModel"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<viewModel:PanelButtonsAndDisplayVM x:Key="panelButtonsAndDisplayVM"/>
</UserControl.Resources>
<Grid Background="{Binding Source={StaticResource panelButtonsAndDisplayVM},Path=Color}" >
</Grid>
The problem is that PanelDisplay does not change its color, to solve this I made a singleton class that launched an event and subscribed PanelDisplay to that event and it worked, but I need two "Panels" in the MainWindow, so if I use this solution the two panels will change their color because they'll both get the same event and only one PanelDisplay should be updated.
Code for the MainWindow:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view="clr-namespace:WpfApplication1.View"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.5*"/>
<RowDefinition Height="0.5*"/>
</Grid.RowDefinitions>
<view:Panel Grid.Row="0"/>
<view:Panel Grid.Row="1"/>
</Grid>
So, how can be actualized each PanelDisplay separately? Any ideas?
Your PanelButtons.xaml and PanelDisplay.xaml do not use the same instance of PanelButtonsAndDisplayVM class because each is declaring their own instance in resources.
Instead, declare PanelButtonsAndDisplayVM instance in Panel.xaml as DataContext so it is propagated to all descendant controls:
<UserControl x:Class="WpfApplication1.View.Panel"
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:view="clr-namespace:WpfApplication1.View"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="600">
<UserControl.DataContext>
<view:PanelButtonsAndDisplayVM/>
</UserControl.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*"/>
<ColumnDefinition Width="0.7*"/>
</Grid.ColumnDefinitions>
<view:PanelButtons Grid.Column="0"></view:PanelButtons>
<view:PanelDisplay Grid.Column="1"></view:PanelDisplay>
</Grid>
</UserControl>
And use it in PanelButtons.xaml like this:
<UserControl x:Class="WpfApplication1.View.PanelButtons"
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:viewModel="clr-namespace:WpfApplication1.ViewModel"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Background="LightGray">
<StackPanel>
<Button Width="64" Height="64"
Command="{Binding PressedOrange}">Orange</Button>
<Button Width="64" Height="64"
Command="{Binding PressedGreen}">Green</Button>
</StackPanel>
</Grid>
</UserControl>
And in PanelDisplay.xaml like this:
<UserControl x:Class="WpfApplication1.View.PanelDisplay"
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:viewModel="clr-namespace:WpfApplication1.ViewModel"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Background="{Binding Path=Color}">
</Grid>
</UserControl>
You should create a separate viewmodel for each UserControl. For example you could have a PanelViewModel then as properties on that a PanelDisplayViewModel and a PanelButtonsViewModel.
A button is pressed on the PanelButtonsViewModel.
That method makes a call up to PanelViewModel to report the event.
The panel then updates the display by calling a method on the PanelDisplayViewModel.
Avoid the static resources for view models here and just use the standard DataContext on each user control and it should work out.