I recently started studying about MVVM, in which I'm now looking at the Caliburn.Micro framework. Unfortunately I could only see very old content and the framework documentation is outdated. I'm using Caliburn 4.0.173, which no longer has the ActivateItem method that was replaced by ActivateItemAsync, follow the code below: ShellViewModel.cs.
ShellViewModel.cs
public async void LoadPageOne()
{
await ActivateItemAsync(new FirstChildViewModel(), CancellationToken.None);
}
public async void LoadPageTwo()
{
await ActivateItemAsync(new SecondChildViewModel(), CancellationToken.None);
}
ShellView.Xaml
<!-- Row 5 -->
<Button x:Name="LoadPageOne" Grid.Row="5" Grid.Column="1"> Load First Page</Button>
<Button x:Name="LoadPageTwo" Grid.Row="5" Grid.Column="2"> Load Second Page</Button>
<!-- Row 6 -->
<ContentControl Grid.Row="6" Grid.Column="1" Grid.ColumnSpan="5" x:Name="ActiveItem"/>
In the video he is using dotnet framework 4.6 and caliburn in 3.2, while I am using dotnet 6. Even adding everything I tried to find, even on github, the usercontrol screen does not change. Could someone tell me where I'm letting it go? I'm a junior programmer and I wanted to understand about this problem, instead of having to change everything to a previous version.
I tried this and it works.
If you want to use built in IoC and want to add messaging between view models you can check out my sample project.
ViewModels:
using Caliburn.Micro;
using System.Threading.Tasks;
namespace CaliburnMicroDemo.ViewModels;
public class ShellViewModel : Conductor<IScreen>
{
public async Task LoadPageOneAsync()
{
await ActivateItemAsync(new FirstChildViewModel());
}
public async Task LoadPageTwoAsync()
{
await ActivateItemAsync(new SecondChildViewModel());
}
}
public class FirstChildViewModel : Screen
{
}
public class SecondChildViewModel : Screen
{
}
ShellView.xaml:
<Window x:Class="CaliburnMicroDemo.Views.ShellView"
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"
Title="Shell Window" Height="450" Width="800">
<DockPanel>
<Button x:Name="LoadPageOneAsync" Content="Load First Page" DockPanel.Dock="Top"/>
<Button x:Name="LoadPageTwoAsync" Content="Load Second Page" DockPanel.Dock="Top"/>
<ContentControl x:Name="ActiveItem" DockPanel.Dock="Bottom"/>
</DockPanel>
</Window>
FirstChildView.xaml:
<UserControl x:Class="CaliburnMicroDemo.Views.FirstChildView"
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"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="1"/>
</Grid>
</UserControl>
SecondChildView.xaml:
<UserControl x:Class="CaliburnMicroDemo.Views.SecondChildView"
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"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="2"/>
</Grid>
</UserControl>
Related
I am a newbie to WPF and am trying to create a simple test app, while maintaining an MVVM architecture.
So I split the application into two distinct projects: Tomato.UI (which contains the xaml files) and Tomato.ViewModels (which contains the classes to manage the interaction with the view).
For now I only have two files for one window: MainWindow.xaml and MainWindowViewModel.cs
In addition I added a reference to Tomato.ViewModels from Tomato.UI
So this is the MainWindow.xaml, where I've created a reference to the ViewModels namespace and where a Button is bound to a function on the MainWindowViewModel.cs file:
<Window x:Class="Tomato.UI.MainWindow"
xmlns:ViewModels="clr-namespace:Tomato.ViewModels"
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"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Button
Content="START"
Click="ViewModels:MainWindowViewModel.ButtonStartClick"
HorizontalAlignment="Center" Margin="344,304,343.6,70" VerticalAlignment="Center" Width="106" Height="46">
</Button>
</Grid>
</Window>
In the related ViewModel class I have the following code
using System;
using System.Windows;
using System.Windows.Input;
using Tomato.Utils;
namespace Tomato.ViewModels
{
public class MainWindowViewModel
{
public ICommand ButtonStartClick { get; set; }
public MainWindowViewModel()
{
ButtonStartClick = new RelayCommand(new Action<object>(ButtonStart));
}
private void ButtonStart(object sender)
{
MessageBox.Show("Starting now!");
}
}
}
But when I try to execute the code I get this error that I can't solve:
Severity Code Description Project File Line Suppression State
Error CS1061 'MainWindow' does not contain a definition for 'ButtonStartClick' and no accessible extension method 'ButtonStartClick' accepting a first argument of type 'MainWindow' could be found (are you missing a using directive or an assembly reference?) Tomato.UI C:\Projects_personal\TomatoTimer\TomatoTimer\MainWindow.xaml 26 Active
A heartfelt thanks to anyone who is able to direct me on the right path :)
You only have to make a binding Command="{Binding ButtonStartClick}"
Click is an eventhandler, not command.
<Button Content="START"
Command="{Binding ButtonStartClick}"
HorizontalAlignment="Center" Margin="344,304,343.6,70"
VerticalAlignment="Center" Width="106" Height="46">
</Button>
Check you have setted correctly the DataContext for the Window (not for the button, the button inherits the datacontext of the parent if not setted).
I am a newbie to WPF and am trying to create a simple test app, while maintaining an MVVM architecture
Unfortunately, so far you're doing it wrong. :)
With the syntax you've tried to use the XAML, the property would have to be static, accessible through the type name itself. But the way you've declared your view model class, you need to reference a property path on binding markup, for a data context object that has been instantiated.
Note that currently, your XAML also doesn't declare a view model object. That can be done in a variety of ways, but the most straightforward would be to set the Windows.DataContext property.
Putting that all together, you get something like this:
<Window x:Class="Tomato.UI.MainWindow"
xmlns:ViewModels="clr-namespace:Tomato.ViewModels"
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"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<ViewModels:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Button
Content="START"
Command="{Binding ButtonStartClick}"
HorizontalAlignment="Center" Margin="344,304,343.6,70" VerticalAlignment="Center" Width="106" Height="46">
</Button>
</Grid>
</Window>
The View needs to bind to the view model instance in the DataContext, which, in this case, can all be done in XAML
<Window x:Class="Tomato.UI.MainWindow"
xmlns:ViewModels="clr-namespace:Tomato.ViewModels;assembly=Tomato.ViewModels"
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"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<ViewModels:MainWindowViewModel /> <!-- Set DataContext to View Model-->
</Window.DataContext>
<Grid>
<Button
Content="START"
Command="{Binding ButtonStartClick}" <!-- Bind to command -->
HorizontalAlignment="Center" Margin="344,304,343.6,70"
VerticalAlignment="Center" Width="106" Height="46" />
</Grid>
</Window>
I'm trying to create a ScrollViewer with some customizations. Like this:
UserControl1.xaml:
<UserControl x:Class="MyApp.Control.UserControl1"
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"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="300">
<UserControl.Template>
<ControlTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="0" Content="{Binding ElementName=uc, Path=DynamicUserControl}" />
<Rectangle Grid.Row="1" Fill="#88ff0000" />
</Grid>
</ControlTemplate>
</UserControl.Template>
</UserControl>
UserControl1.xaml.cs:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public static readonly DependencyProperty DynamicUserControlProperty = DependencyProperty.Register("DynamicUserControl", typeof(object), typeof(UserControl1), new PropertyMetadata(null));
public object DynamicUserControl
{
get { return GetValue(DynamicUserControlProperty); }
set { SetValue(DynamicUserControlProperty, value); }
}
}
TestForm.xaml (Using the UserControl1):
<Window x:Class="MyApp.TestForm"
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:MyApp.Control"
mc:Ignorable="d"
Title="TestForm" Height="200" Width="500">
<Grid Background="{StaticResource AimDarkGradBg01}">
<local:UserControl1>
<local:UserControl1.DynamicUserControl>
<Button>Click me</Button>
</local:UserControl1.DynamicUserControl>
</local:UserControl1>
</Grid>
</Window>
But the problem is no matter what content I put in the local:UserControl1.DynamicUserControl, nothing is rendered.
Anyone can help me?
The problem is actually you binding expression. The correct binding should be like:
UserControl1.xaml:
<UserControl x:Class="MyControls.UserControl1"
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:MyControls"
mc:Ignorable="d"
x:Name="uc">
<Grid>
<ScrollViewer>
<WrapPanel>
<!-- Dynamic Content -->
<ContentPresenter Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type control:UserControl1}}, Path=DynamicUserControl}"/>
</WrapPanel>
</ScrollViewer>
<Canvas>
<!-- Some Code -->
</Canvas>
</Grid>
</UserControl>
If you noticed I removed your definition of the template, in which case you don't need it. You can simply just put your code inside the user control.
The other files are correct. Fix what I told you above and you're good to go.
I have a modern window in WPF/C# application, in which I added a modern frame:
<mui:ModernWindow x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mui="http://firstfloorsoftware.com/ModernUI"
WindowStartupLocation="CenterScreen"
Style="{StaticResource EmptyWindow}">
<Window.Resources>
</Window.Resources>
<Grid>
<Menu x:Name="menu" Height="62" VerticalAlignment="Top" >
<MenuItem x:Name="miHome" Header="Home" Click="MenuItem_Home" IsChecked="True" Width="60" FontSize="14" />
<MenuItem x:Name="miClients" Header="Clients" FontSize="14" Click="MenuItem_Clients" Width="65"/>
<MenuItem x:Name="miSuppliers" Header="Suppliers" FontSize="14" Click="MenuItem_Suppliers" Width="81"/>
<MenuItem x:Name="miReports" Header="Reports" FontSize="14" Click="MenuItem_Reporting" Width="71"/>
</Menu>
<mui:ModernFrame Margin="0,75,10,10" x:Name="frame">
</mui:ModernFrame>
</Grid>
I have MenuItems in my application, when I click on Suppliers item, I fill the frame with a usercontrol, like this:
frame.Source = new Uri("/Pages/Suppliers.xaml", UriKind.Relative);
Where Suppliers.xaml design is:
<UserControl
x:Class="MyApp.LinksBar.Suppliers"
xmlns:MyApp="clr-namespace:MyApp"
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:mui="http://firstfloorsoftware.com/ModernUI"
mc:Ignorable="d"
d:DesignHeight="575" d:DesignWidth="905">
<UserControl.Resources>
</UserControl.Resources>
<Grid Name="Grid">
<mui:ModernButton x:Name="btnmakePayment" Content="Make Payment" Click="btnMakePayment_Click" Grid.Row="2" HorizontalAlignment="Right" VerticalAlignment="Top"/>
</Grid>
</UserControl>
When I click on "Make Payment" button, I navigate to another UserControl (MakePayment.xaml):
private void btnMakePayment_Click(object sender, RoutedEventArgs e)
{
NavigationCommands.GoToPage.Execute(new Uri("/Actions/MakePayment.xaml", UriKind.Relative), this);
}
MakePayment.xaml design is:
<UserControl
xmlns:local="clr-namespace:MyApp.Actions" x:Class="MyApp.Actions.MakePayment"
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:mui="http://firstfloorsoftware.com/ModernUI" xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:MyApp="clr-namespace:MyApp"
mc:Ignorable="d"
Loaded="MakePayment_Loaded"
d:DesignHeight="600" d:DesignWidth="866" >
<UserControl.Resources>
</UserControl.Resources>
<Grid DataContext="{StaticResource makePaymentViewSource}" Name="Grid">
<Grid.RowDefinitions>
</Grid.RowDefinitions>
<Label Content="Total" VerticalContentAlignment="Center" HorizontalAlignment="Left" VerticalAlignment="Top"/>
// More design code here ...
</Grid>
</UserControl>
Here comes my question:
I need to pass parameters from Suppliers UserControl to MakePayment UserControl.
How to programmatically pass the parameters in Suppliers and read them in MakePayment?
Thank you.
If you can bind one to the other, that is what you should be doing. By far, the easiest way to make two UserControls "communicate" (or share properties that both can do stuff with) is to define a DependencyProperty on each and bind them two-way.
This way, both always have access to the same value and both can do stuff with it.
Take my own control as an example:
<UserControl x:Class="MyControls.MasterContainerControl"
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:MyControls"
mc:Ignorable="d"
x:Name="masterContainerControl">
<local:ContainerControl SomeProperty="{Binding ElementName=masterContainerControl, Path=SomeProperty}">
<local:ContainerControl.Another>
<local:AnotherControl SomeProperty="{Binding ElementName=masterContainerControl, Path=SomeProperty"/>
</local:ExplorerBase.AddressBar>
<local:ContainerControl.Some>
<local:SomeControl SomeProperty="{Binding ElementName=masterContainerControl, Path=SomeProperty"/>
</local:ContainerControl.Some>
</local:ContainerControl>
</UserControl>
This, of course, all assumes MasterContainerControl, ContainerControl, AnotherControl, and SomeControl all have a DependencyProperty called SomeProperty, and then the bindings seal the deal.
Note: Make sure the default values are defined in MasterContainerControl because those will override the values MasterContainerControl binds to.
If I misunderstood your issue, please let me know.
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Height="833.831" Width="1351">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Unloaded="Unlaoded" Margin="-47,0,0,0" HorizontalAlignment="Right" Width="1398">
<WebView x:Name="WebView" LoadCompleted="WebView_LoadCompleted" Height="814" VerticalAlignment="Top" Margin="-55,10,10,0" Grid.RowSpan="2" HorizontalAlignment="Right" Width="1396" RenderTransformOrigin="0.506,0.695"
/>
<ProgressRing x:Name="ProgressRing1"
Margin="642.019,405,671.173,378.647"
Height="50.353" Width="84.808"
Foreground="BlueViolet"
UseLayoutRounding="False" d:LayoutRounding="Auto"
>
<ProgressRing.RenderTransform>
<CompositeTransform Rotation="1.006"/>
</ProgressRing.RenderTransform>
</ProgressRing>
</Grid>
</Page>
hello all i am new to this forum and also i am new in uwp programming. I am in a desperate position and i need some help. I can't make the above webview responsive in all platforms(desktop,windows phone). I load webview from the code from local app and i can't make it adaptive in all platforms. Can anyone help me make it work from xaml.
Did i need to put
<RelativePanel .../>
in xaml code.
You should not use fixed values for Width and Height. Take a look at the following links:
Arranging UI Elements and
Layout with Absolute and Dynamic Positioning
to have an idea of how positioning works in XAML.
I think you created the UI using the designer, that's why you got those values.
Following is a simple example where the web view is filling all the space from the page:
XAML
<Page
x:Class="Stack1.MainPage"
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">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<WebView
x:Name="WebView"
LoadCompleted="WebView_LoadCompleted"
Source="https://www.google.com"/>
<ProgressRing x:Name="ProgressRing"
Foreground="BlueViolet"
IsActive="True"
Width="100"
Height="100"
>
</ProgressRing>
</Grid>
C# code behind
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void WebView_LoadCompleted(object sender, NavigationEventArgs e)
{
ProgressRing.Visibility = Visibility.Collapsed;
}
}
The ProgressRing will be visible until the web-view content will be loaded (use of LoadCompleted event)
Related to Adaptive UI you can take a look at this video.
If your embedded website URL source is responsive, below code changes will help to you fit your website for all screen sizes. Auto layout size and alignment will help you to fit all screen sizes.
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Unloaded="Unlaoded">
<WebView x:Name="WebView" LoadCompleted="WebView_LoadCompleted" />
<ProgressRing x:Name="ProgressRing1"
Height="50.353" Width="84.808"
Foreground="BlueViolet"
UseLayoutRounding="False" d:LayoutRounding="Auto" />
</Grid>
</Page>
Say I have these two User Controls. How would I pass data entered in the TextBox from ControlOneto the TextBox in ControlTwo when the Button in ControlOne is clicked?
<UserControl x:Class="Project.ControlOne"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBox x:Name="MyTextBox" HorizontalAlignment="Center" VerticalAlignment="Center" Width="100" />
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="Send" Click="Button_Click" />
</StackPanel>
</Grid>
</UserControl>
...
namespace Project
{
public partial class ControlOne : UserControl
{
public ControlOne()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
}
}
}
<UserControl x:Class="Project.ControlTwo"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBox x:Name="MyTextBox" HorizontalAlignment="Center" VerticalAlignment="Center" Width="100" />
</StackPanel>
</Grid>
</UserControl>
Your two user controls should have no knowledge of each other (unless one contains the other). That's why you can't "pass data" between them. The idea behind a user control is that you can drop it anywhere as many times as needed. If ControlOne knew about ControlTwo, what would happen if you used them separately? Or had three ControlTwos in the same place?
The layer which contains both of them should be the one to read a value from one and set it to the other. If you want it to happen on the button press, you should look into event handling so the parent can know when the control's button is pressed.