How to load content properly inside a ModernWindow using mvvm - c#

At our company, we're used to develop our applications using WinForms,
Now we decided to switch to WPF-MVVM with Caliburn.Micro and Modern UI.
The thing we're trying to reach is to have a small application that has:
- 1 Modern Window
- 2 Pages inside that Modern window
the goal is to have a button inside that page that navigates the Modern Window to the second page with parameters.
I've been working trying to understand how to work this out, I succeeded with the Window (without the MUI), but when it comes to MUI, it's not really giving me the result we want.
So far, All I did, is
Create a new MUI Project
Add the Caliburn.Micro to the project
Change the App.xaml to
<Application x:Class="MuiWithCaliburn01.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MuiWithCaliburn01">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<local:AppBootstrapper x:Key="bootstrapper" />
<local:ModernContentLoader x:Key="ModernContentLoader" />
</ResourceDictionary>
<ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/ModernUI.xaml" />
<ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/ModernUI.Light.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Create the Bootstrapper Class
public class AppBootstrapper : BootstrapperBase
{
static AppBootstrapper()
{
}
public AppBootstrapper()
{
Initialize();
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor();
}
}
Create the ModernContentLoader Class
public class ModernContentLoader : DefaultContentLoader
{
protected override object LoadContent(Uri uri)
{
var content = base.LoadContent(uri);
if (content == null)
return null;
var vm = Caliburn.Micro.ViewModelLocator.LocateForView(content);
if (vm == null)
return content;
if (content is DependencyObject)
{
Caliburn.Micro.ViewModelBinder.Bind(vm, content as DependencyObject, null);
}
return content;
}
}
ModernWindowView.xaml & ModernWindowViewModel.cs
< mui:ModernWindow x:Class="MuiWithCaliburn01.ModernWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mui="http://firstfloorsoftware.com/ModernUI"
ContentLoader="{StaticResource ModernContentLoader}">
< mui:ModernWindow.MenuLinkGroups>
< mui:LinkGroupCollection>
< mui:LinkGroup DisplayName="Hello">
< mui:LinkGroup.Links>
< mui:Link Source="Child1View.xaml" DisplayName="Click me">< /mui:Link>
< /mui:LinkGroup.Links>
< /mui:LinkGroup>
< /mui:LinkGroupCollection>
< /mui:ModernWindow.MenuLinkGroups>
< /mui:ModernWindow>
class ModernWindowViewModel : Conductor.Collection.OneActive
{
public ModernWindowViewModel()
{
//this function is doing nothing in the ModernWindow, but it works great in the Window.
ActivateItem(new Child1ViewModel());
}
}
And finally, the Child1View.xaml
<UserControl x:Class="MuiWithCaliburn01.Child1View"
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"
xmlns:cal="http://www.caliburnproject.org"
xmlns:model="clr-namespace:MuiWithCaliburn01"
d:DataContext="{x:Type model:Child1ViewModel}"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Button cal:Message.Attach="ClickMe" Width="140" Height="50">Hello World</Button>
</Grid>
</UserControl>
and Child1ViewModel.cs
public class Child1ViewModel : Conductor<IScreen>
{
public void ClickMe()
{
MessageBox.Show("Hello");
}
}
My question is, step 6, why does the function do nothing? and if my way is wrong can anybody direct me to a better way?
And if it's the best approach, how can I navigate from the function ClickMe to another View.

As for your first question about why does the function do nothing, I think it may have to do with the hierarchy of your project. Using MUI this is the main (and only) window for one of my applications
<mui:ModernWindow x:Class="namespace.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"
Title="Window Title" IsTitleVisible="True"
ContentSource="/Pages/Home.xaml"
Style="{StaticResource MyModernWindow}">
<mui:ModernWindow.TitleLinks>
<mui:Link DisplayName="settings" Source="/Pages/SettingsPage.xaml" />
</mui:ModernWindow.TitleLinks>
in my project hierarchy, i have my project root (CSPROJ file), MainWindow.xaml then a Pages folder. Inside my pages folder i have my SettingsPage.xaml. The source attribute in my mui:Link tag points to the realitive path of my main window to my settingsPage.xaml file. MUI will then load and display that path in the content provider that is put in your main window for you by the MUI ModernWindow class default style template. No additional code is needed on your part to navigate (until you want complex sub view navigation).
my settingsPage.xaml file is a normal user control with the grid having a style assigned to the ContentRoot static resource style as it also will contain additional views/pages.
Mui source can be found on GitHub at Mui GithubLink. Here you can download the sample program, who's code is found in the same repository under app Link here for covience.
I am not familiar with Caliburn.Micro so i'm not sure how the two integrate together, such as requirements of Caliburn.Micro to function. I do know how MUI integrates with MVVM light and there are many examples of this found on the internet in my research before hand.

Related

WPF: Problem with display xaml view inherits from UserControl

Hello i have this Viw in XAML
<local:JedenViewBase x:Class="Firma.View.FakturaView"
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:Firma.View"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary Source="MainWindowResource.xaml" />
</UserControl.Resources>
<Grid>
.....
</Grid>
</local:JedenViewBase>
And that is class this view
namespace Firma.View
{
public partial class FakturaView : JedenViewBase
{
public FakturaView()
{
InitializeComponent();
}
}
}
And that is JedenViewBase class
namespace Firma.View
{
public class JedenViewBase : UserControl
{
static JedenViewBase()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(JedenViewBase), new FrameworkPropertyMetadata(typeof(JedenViewBase)));
}
}
}
I have problem because view in XAML dont display, i dont know why? JedenViewBase class inherits from UserControl. When i UserControl in view everything works. What i should do?
<UserControl x:Class="Firma.View.FakturaView"
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:Firma.View"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary Source="MainWindowResource.xaml" />
</UserControl.Resources>
<Grid>
...
</Grid>
</UserControl>
View FakutraView when i use UserControl
I try rebuild app etc. and i still have problem
You've created a custom control.
That's unlikely to be a good idea and this should probably just be a user control.
The reason you get no view is this.
static JedenViewBase()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(JedenViewBase), new FrameworkPropertyMetadata(typeof(JedenViewBase)));
}
I recommend you remove that. Change
<local:JedenViewBase
To user control.
Make this just a user control.
Alternatively. Read up on custom controls. Put your ui definition in generic xaml.
I also wonder why this has it's own resources. They will be in memory for each instance. If whatever is in that resource dictionary is unique to this control maybe that's not a bad idea. in which case the naming seems strange.

C# MVVM Prism questions

I try to understand C# prism framework, and make a little project. I meet some problem with misunderstanding Prism concept. I will explain what i want to do, what i try, my code:
I want to make a simple application like a test with 5 random question. You select difficult of test after you press start. On the same window your page is change with first question. Select right answer , next and you go on the second page with second question. From the second question you have 2 buttons(prev and next) , next next next, finish and you have a message like "you got x/5 points".
I have a similar aplication but the framework use is Caliburn.
First Application
I want to put all questions in xaml file now.
What i try:
I follow documentation, youtube tutorials for 2 days.
I create 2 folders: View and ViewModel. Create MainPage.xaml like a window in View and in ViewModel i create MainPageViewModel, in file MainPage.cs i create one instance like:
MainPageViewModel main = new MainPageViewModel();
After this i create a button i test the button and work.
Now I want to create a Page to connect with MainPageViewModel window. In the page i want to create another button and i want to check if is work. But this is the step how can't create.
After follow few tutorials, i can't make this. Not work to connect on the xaml file MainPageViewModel.
MainPage:
<Window x:Class="Aplicatie2._0.View.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"
xmlns:prism="http://prismlibrary.com/"
xmlns:local="clr-namespace:Aplicatie2._0.View"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
Title="{Binding Title}" Height="450" Width="800">
<Window.DataContext>
</Window.DataContext>
<Grid>
</Grid>
</Window>
Error MC3063: Property 'DataContext' does not have a value. Line 14 Position 30.
MainPageViewModel:
using Prism.Mvvm;
using Prism.Navigation;
using Prism.Commands;
namespace Aplicatie2._0.ViewModel
{
class MainPageViewModel : BindableBase
{
private string _Title = "Test";
public string Title
{
get
{
return _Title;
}
set
{
SetProperty(ref _Title, value);
}
}
}
}
App.xaml:
<prism:PrismApplication x:Class="Aplicatie2._0.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
xmlns:local="clr-namespace:Aplicatie2._0">
<Application.Resources>
</Application.Resources>
</prism:PrismApplication>
App.xaml.cs:
using Prism.Modularity;
using Prism.Ioc;
using System.Windows;
using System.ComponentModel;
using Prism.Unity;
using Aplicatie2._0.View;
namespace Aplicatie2._0
{
public partial class App : PrismApplication
{
protected override Window CreateShell()
{
return Container.Resolve<MainPage>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<MainPage>("MainPage");
}
}
}
1)How can i create multiple page and how can connect with main window?(If i call page1 i want to be clear, to create button and Radiobutton on the page)
2)How can i connect ViewModel file with View file on xaml, without create instance?
3)How can i create one question in xaml like:
Question: This is first question
[] Answer1
[] Answer2
[] Answer3
If you can to give me an example it's perfect, but make it simple.

AvalonDock 3: Data bound title of anchorable is shown in designer, but not when running program

I am currently testing AvalonDock. I want to create the layout via MVVM.
I have the problem, that databound titles for anchorables (not for documents) are shown in the designer but missing when running the program.
I found this example and recreated a much simpler version to reproduce the problem.
Here is what I did:
Created a blank solution with a WPF application inside
Added Xceed WPF Toolkit v3.0 via Nuget
Created this very simple viewmodel:
namespace NonWorkingAvalonDock {
public sealed class MainViewModel {
public MainViewModel() {
Pages = new SimplePageViewModel[] {
new SimplePageViewModel("Foo"),
new SimplePageViewModel("Bar")
};
}
public SimplePageViewModel[] Pages { get; }
}
public sealed class SimplePageViewModel {
public SimplePageViewModel(string title) {
Title = title;
}
public string Title { get; }
}
}
Made my XAML to look like this:
<Window x:Class="NonWorkingAvalonDock.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:NonWorkingAvalonDock"
xmlns:dock="http://schemas.xceed.com/wpf/xaml/avalondock"
xmlns:dockctrl="clr-namespace:Xceed.Wpf.AvalonDock.Controls;assembly=Xceed.Wpf.AvalonDock"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:MainViewModel x:Key="ViewModel" />
</Window.Resources>
<dock:DockingManager DataContext="{StaticResource ViewModel}" AnchorablesSource="{Binding Pages}" >
<dock:DockingManager.LayoutItemContainerStyle>
<!-- you can add additional bindings from the layoutitem to the DockWindowViewModel -->
<Style TargetType="{x:Type dockctrl:LayoutItem}" >
<Setter Property="Title" Value="{Binding Model.Title}" />
</Style>
</dock:DockingManager.LayoutItemContainerStyle>
</dock:DockingManager>
</Window>
Now, in Expression blend this looks correct:
But when I run my application, I get this:
I think I am missing something, but I can't figure out what, since the example from github runs perfectly.
Followup:
I investigated the example and my code a bit more, and in the example, the author sets the data context in code behind. When I do this, it works for me, too.
Moreover, I did the following experiment: I made the Pages property privately writable, initialized it with null and used a Timer which sets the view models after one second. When I do this, I get the titles, too.

which way should i define Resource Dictionaries to keep my code clean?

I am new to WPF. My requirement is to implement the styling in a clean way. Styling includes fonts, colors, layouts, size,. etc.
Sample implementation with style is shown above. Requirement is in a window if its a form which receives input from user, common style needs to there like label has to right aligned, textbox has to be left aligned and some width and some properties and foreground property too.
My implementation
I made a separate assembly (because not only for this purpose it includes other user controls, styles, resources) which has a Layout.Xaml resource dictionary and in it all styles are defined.
Then a dependency property is created and through that the dictionary is linked as shown below.
<Window xmlns:MvvmLibsTests="clr-namespace:CreativeEye.TestConsole.MvvmLibsTests"
x:Class="CreativeEye.TestConsole.MvvmLibsTests.StyleTestView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SyleTestView" Height="408" Width="706"
WindowStartupLocation="CenterScreen"
xmlns:Styles="clr-namespace:CreativeEye.MvvmLibs.Behaviours;assembly=CreativeEye.MvvmLibs">
<!--<Grid>-->
<Grid Styles:SetLayout.Resources="{StaticResource FormLayoutStyle}">
</Grid>
</Window>
In that FormLayoutStyle has value
<s:String x:Key="FormLayoutStyle">pack://application:,,,/CreativeEye.MvvmLibs;component/Resources/Layout.xaml</s:String>
in App.Xaml of the application.
The code for dependency property is
public static readonly DependencyProperty ResourcesProperty = DependencyProperty.RegisterAttached(
"Resources",
typeof(string),
typeof(SetLayout),
new PropertyMetadata("", new PropertyChangedCallback(CallBack)));
private static void CallBack(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var layoutGridStylePath = e.NewValue;
if (layoutGridStylePath == null)
{
return;
}
var uri = new Uri((string)layoutGridStylePath, UriKind.RelativeOrAbsolute);
var grid = obj as FrameworkElement;
if (grid == null)
{
return;
}
grid.Resources.Source = uri;
}
And i achieved the result.
But i wanted to know is it a good way ?
and also i read some thing about memory leaks.
Reference links link 1, link 2.
I was more confused. I couldn't understand properly.
Can anyone please say in my implementation such memory leak problem will be der ?
Generally i use resources this way, but binding to c# code is also not at all a bad approach.
<Window x:Class="WPFDemo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="Resources/MyResourceDictionary.xaml">
</ResourceDictionary>
<ResourceDictionary
Source="Resources/OthersStyle.xaml">
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Image Source="/Images/logo.jpg"></Image>
</Grid>
</Window>

Use difference XAML pages in XBAP

How would I go about switching the main display XAML page that gets used in an XBAP. The only different is I want a larger mode and a smaller mode, but with the same controls (some hidden).
In your App.xaml.cs file, you can programmatically change which Window.xaml file you want to show on startup. Here is an over-simplified example.
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
System.Windows.Window startupWindow = null;
if(useLargeMode)
{
startupWindow = new LargeMainWindow();
}
else
{
startupWindow = new SmallMainWindow();
}
window.Show();
}
You can also do this by changing the StartupUri in your App.xaml file but that is obviously going to be harder to change at runtime.
<Application x:Class="Main.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml" /> <!-- change this -->
I've haven't tried binding to a property in the application declaration in the XAML, but VS 2010 doesn't complain about this. My concern would be that the app had it's datacontext set early enough for this to work correctly. Give it a try and let us know how it works. :)
<Application x:Class="Main.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="{Binding StartupWindow}">

Categories

Resources