How can i share same ViewModel between two views in WPF? - c#

I have this view:
<Window x:Class="Ohmio.Client.PruebasView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Ohmio.Client"
Title="Pruebas" Height="284" Width="626">
<Window.DataContext>
<local:PruebasViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Content="Create View"/>
<Button Grid.Row="1" Content="Create child View" Click="Button_Click_1"></Button>
<ContentPresenter x:Name="ContentPrt" Grid.Row="2" Margin="5"></ContentPresenter>
</Grid>
My idea is to load a second view(child view) in the content presenter. Just for testing i'm doing this from code-behind:
this.ContentPrt.Content = new ModalViewModel();
So my question is: How can I make the new view(the one load on contentPresenter) share the same dataContext with PruebasView? (In this case, PruebasViewModel)
Thanks!

If I understood your question correctly, it's simple. Just pass PruebasViewModel to ContentPresenter as the data context.
<ContentPresenter x:Name="ContentPrt" DataContext={Binding} Grid.Row="2" Margin="5"></ContentPresenter>

I suppose that ModalViewModel is your child view class. So when you add it to the content presenter, your View becomes a part of your Visual Tree, so it automatically shares the DataContext of the main window.
Pratically WPF makes of the job for you: the content presenter's content will "see" the PruebasViewModel by its own.
EDIT
I did not read that you are using Caliburn Micro, but the idea does not change.

Related

How to add a grid view under Master-Detail detail page in Xamarin Forms?

I'm trying to add a grid view at the bottom of the screen containing 'Current Playing' information about a media being played in a media player. The problem is that I want this view to be there no matter what is the page visible.
The main layout is a Master-Detail page for the navigation menu panel, where the detail page should contain everything.
The detail page can be a content page, a navigation page (mostly) or a modal content page. However, if I might only choose one, I would choose it to be a navigation page.
So, simply I want to do something like this:
<MasterDetailPage.Detail>
<ContentPage>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Page x:Name="viewPort" Grid.Row="0">
<!--This page source is dynamically set from the code behind...-->
</Page>
<Grid Grid.Row="2">
<!--Here should be the rest of my grid structure...-->
</Grid>
</Grid>
</ContentPage>
</MasterDetailPage.Detail>
But wrapping a page inside another view/page is not possible, I tried also modifying the Master-Detail page control template to add that grid at the bottom of the detail page and display whatever page above it, but no luck in finding the original template or even setting a template for Master-Detail layout...
I'm new to Xamarin but somewhat experienced with c# and xaml, any help is really appreciated.
You could use ContentPresenter with control template.
Create a control template in App.xaml> Application.Resources> ResourceDictionary.
<!-- Grid Template -->
<ControlTemplate x:Key="GridTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="0" />
<Label
Grid.Row="1"
BackgroundColor="Accent"
Text="Grid Template" />
</Grid>
</ControlTemplate>
And then use it in detail page.
ControlTemplate="{StaticResource GridTemplate}"
I have uploaded the project on GitHub for your reference.
https://github.com/WendyZang/Test/tree/master/ControlTemplate_ContentPresenter/MasterDetailPageDemo
Updated:
For data binding of control template, you could use TemplateBinding.
Create a AppViewModel:
public class AppViewModel
{
public string Name { get; set; } = "Name_A";
public AppViewModel()
{
}
}
App.xml:
<ControlTemplate x:Key="GridTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="0" />
<Label Grid.Row="1" BackgroundColor="Accent" Text="{TemplateBinding BindingContext.Name}" />
</Grid>
</ControlTemplate>
Set the binding in each page which use the control template.
this.BindingContext = new AppViewModel();

Cannot add different controls to GRID panel in C#

I'm completely new to XAML and WPF and I cannot add other type of control (like TextBox or Label) to grid after adding a button. Could you please explain me where do I make a mistake (I guess it should be some simple mistake by a newbie guy).
I've created an app in C# using Win Forms and decided to create the same app using WPF, which I never used before, so that I can learn something new. I'm not good in C# FYI. I started new project with WPF application in Visual Studio, created 2 columns and 4 rows for a grid and started adding some controls to it. Unfortunately, I cannot make a working app with buttons and another type of control on same grid. It looks like grid would allow me to add only 1 type of controls, which for me makes no sense and I couldn't find any information about such restriction. Simple XAML code included.
<Window x:Class="AjStock_WPF_3.CSVToSQL"
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:AjStock_WPF_3"
mc:Ignorable="d"
Title="CSVToSQL" Height="450" Width="800" MinHeight="200" MinWidth="250">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="*" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Button Grid.Column="0" Grid.Row="0">
<Button.Name>GetCSVFile</Button.Name>
<Button.Content>Get CSV file</Button.Content>
<Button.Margin>10</Button.Margin>
<Button.VerticalContentAlignment>Center</Button.VerticalContentAlignment>
<Button.HorizontalContentAlignment>Center</Button.HorizontalContentAlignment>
<Button.FontWeight>Bold</Button.FontWeight>
<Button.FontSize>14</Button.FontSize>
<Button.BorderThickness>2</Button.BorderThickness>
</Button>
<TextBox Grid.Column="1" Grid.Row="0">
<TextBox.VerticalContentAlignment>Center</TextBox.VerticalContentAlignment>
<TextBox.HorizontalContentAlignment>Center</TextBox.HorizontalContentAlignment>
<TextBox.Margin>10</TextBox.Margin>
</TextBox>
</Grid>
Expected result would be a window with controls like this:
Button | TextBox
Label | TextBox
Button | TextBox
Button | Button
Error that I'm receiving:
CS0029 Cannot implicitly convert type
'System.Windows.Controls.TextBox' to
'System.Windows.Controls.Button' AjStock_WPF_3 D:\OneDrive\Microsoft
Visual
Studio\source\repos\AjStock_WPF_3\AjStock_WPF_3\obj\Debug\CSVToSQL.g.cs 104 Active
You need to remove
<Button.Name>GetCSVFile</Button.Name>
and replace with
<Button Grid.Column="0" Grid.Row="0" Name="GetCSVFile">
Not sure why this is required as when the textbox is removed, leaving just the button, it compiles. It's probably related to the mapping of x:Name but not 100% sure.

How to prevent the Content of a UserControl from being overridden?

I'm new to Windows 10 app development. I'm trying to embed my custom UserControl in a page in my application. For some reason, the content is being completely replaced by whatever I put inside it in the XAML page. To give a better explanation, here is the code:
AppView.xaml (the control)
<UserControl
x:Class="Sirloin.AppView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Sirloin"
xmlns:h="using:Sirloin.Helpers">
<SplitView x:Name="splitView" DisplayMode="CompactOverlay">
<SplitView.Pane>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!--The hamburger-->
<Button Click="OnHamburgerClicked" Grid.Row="0" Style="{StaticResource MenuButtonStyle}">
<Button.DataContext>
<local:MenuItem Symbol=""/>
</Button.DataContext>
</Button>
<!--Buttons just below the hamburger-->
<ListView x:Name="topView"
Grid.Row="1"
ItemTemplate="{StaticResource ListViewItemTemplate}"/>
<!--Buttons toward the bottom of the menu-->
<ListView x:Name="bottomView"
Grid.Row="3"
ItemTemplate="{StaticResource ListViewItemTemplate}"/>
</Grid>
</SplitView.Pane>
<SplitView.Content>
<!--Where I'd like the content specified in MainPage to appear-->
<Frame x:Name="frame" Background="White"/>
</SplitView.Content>
</SplitView>
</UserControl>
MainPage.xaml
<Page
x:Class="Sirloin.Example.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="using:Sirloin"
xmlns:local="using:Sirloin.Example">
<s:AppView>
<Grid Background="White">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="Hello, world!"/>
</Grid>
</s:AppView>
</Page>
When MainPage renders in the VS designer, it's as if the contents of my user control have been completely gutted out and replaced with whatever is specified in the main page. To give you an idea, here is a screenshot of the designer:
As you can see, there is no menu or SplitView or whatever I've put in my custom control; the only thing that's present is the TextBlock I've specified in the XAML for MainPage.
Anyway, why does this happen and what can I do to fix it?
EDIT: Found the solution I was looking for here, but Peter Duniho's answer has been accepted as it provides a better explanation of what's going on.
UserControl is a subclass of Control (which is similar to WPF's ContentControl). It can have only one child. So you are explicitly overriding the content yourself. By specifying a child element for your AppView in the Page XAML, you are setting the content of the control. This takes precedence over whatever content was specified in the UserControl's own XAML.
Unfortunately, it's not very clear what it is you expected to happen. Maybe you want to provide a property for additional content, which the AppView class can use to add to its own content. Or maybe you should be allowing the client code to provide a DataTemplate and some kind of data item object (e.g. model class), which is used in a ContentPresenter or similar in the AppView XAML.
But whatever you're trying to do, you'll have to do it without using, and overriding the current value of, the implicit Content property of the UserControl in the Page XAML.

WPF UserControl Not Displaying

I deleted my previous question to rephrase appropriately, since my previous post was neither helpful nor complete, imo.
For clarity: I'm using the Prism framework and abiding by a strict MVVM pattern.
Problem: When I load a UserControl, defined in some module, ModuleA, it does not display in the Shell view. However, if I load my UserControl within an ItemsControl, the elements I have defined appear, but they are all 'squished together'.
In ModuleA, I have the following UserControl:
<UserControl ...
...>
...
<Grid>
... My Content Here ...
</Grid>
</UserControl>
Now, in my project, I have defined the Shell thusly:
<Window ...
...>
...
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10"/>
<RowDefinition Height="10"/>
<RowDefinition Height="10"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" .../>
<UserControl Grid.Row="1" prism:RegionManager.RegionName="ModuleARegion"/>
<Border Grid.Row="2" .../>
</Grid>
</Window>
Now, in this scenario, everything loads, and ModuleA is recognized, but nothing appears on the screen.
However, if I change the <UserControl Grid.Row="0" prism:RegionManger .../> to <ItemsControl Grid.Row="0" prism:RegionManager .../>, I can see the content I've laid out in my ModuleA UserControl, but the content is all 'squished together'.
Does anyone have any ideas as to why this might be happening?
The default region adaptors in Prism don't support UserControl. You need to use ContentControl, ItemsControl or a Selector based control like a ComboBox to get out of the box support or write your own region adaptor.
Note: The region adaptor is used to add and remove controls from regions of a certain type of control when you interact with its regions.

Is it possible to launch another view using XAML only when button is clicked?

I know that Binding in WPF is a really powerful feature, but I don't know if that is possible.
My window is composed of a really simple grid:
<Grid Height="593" Width="800" >
<Grid.RowDefinitions>
<RowDefinition Height="109*" />
<RowDefinition Height="484*" />
</Grid.RowDefinitions>
<Grid.Background>
<ImageBrush ImageSource="MenuBackground.png" />
</Grid.Background>
<Label Grid.Row="0"
HorizontalAlignment="Center" VerticalAlignment="Center"
FontSize="36" Foreground="Gray"
Margin="0,15,0,0">
Bindings Sandbox
</Label>
<Grid Grid.Row="1" Width="300" Height="200">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Button Grid.Row="0" Margin="5" FontSize="16">Slider and Progress Bar</Button>
<Button Grid.Row="1" Margin="5" FontSize="16">Button2</Button>
</Grid>
</Grid>
I want to know if it is possible to call another window (let's say defined in View1.xaml) without routing the Button.Click incode-behind?
You have a few options here.
Technically, you could make an attached property that does what you want. This would use code, but not in the code behind, so it provides a more reusable option.
Alternatively, you can use a Command instead of an event handler. This lets you bind to the command, and move the logic into your DataContext. (This, btw, is one of the "tools" that makes the MVVM pattern work correctly.) The Command could open your new View.

Categories

Resources