Call method on Window Loaded Event in F# with WPF - wpf

I am getting a XAMLParseException when trying to load a xaml component with a Loaded event. I am not quite sure how write the method signature for the handled event. C# examples are clear but I'm not sure how to convert this to the F# version. I will include my first attempt below.
ViewModel code:
let theWindow = Application.LoadComponent(new Uri("/MyApp;component/MyWindow.xaml", UriKind.Relative)) :?> Window
XAML Header:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:MyApp.Converters;assembly=MyApp"
xmlns:local="clr-namespace:MyApp;assembly=MyApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
x:Name="_theWindow"
WindowStartupLocation="CenterOwner"
Title="My App - Popup Window"
Loaded="Window_Loaded"
Icon="MyApp;component/icons/MyApp.ico"
Width="484.667" Height="215.333"
Left="100" Top="100">
F# method:
member x.Window_Loaded (sender : object, eventArgs : RoutedEventArgs) = // Do stuff

When using FsXaml.Wpf v.3.1.3 I had...
StartupUri="MainWindow.xaml"
...in my app.xaml file. I removed it and used this in my App.fs file to open MainWindow.xaml...
[<STAThread>]
[<EntryPoint>]
let main argv =
Wpf.installSynchronizationContext ()
Views.MainWindow()
|> App().Run
...which matches the WpfMvvmAgent demo. That resolved the XamlParseException above for me.

Related

Can MahApps.Metro be used in MvvmCross?

I was trying to use Mahapps Metro inside a WPF project using MvvmCross mvvm framework.
Both seem to use custom window control. Is there a way to use both in a project?
Metro window:
<mah:MetroWindow x:Class="TipCalc.WPF.MainWindow"
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
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:TipCalc.WPF"
xmlns:views="clr-namespace:MvvmCross.Platforms.Wpf.Views;assembly=MvvmCross.Platforms.Wpf"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="800">
<Grid>
</Grid>
</mah:MetroWindow>
MvvmCross Window:
<views:MvxWindow x:Class="TipCalc.WPF.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:TipCalc.WPF"
xmlns:views="clr-namespace:MvvmCross.Platforms.Wpf.Views;assembly=MvvmCross.Platforms.Wpf"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="800">
<Grid>
</Grid>
</views:MvxWindow>
The application runs either way. But with the Metro window in place, the rest of the application doesn't get set up(ie.-children views). With the MvvmCross window in place, the application works as usual but is not designed or colored.
Since multi inheritance is not supported in C#, this is not possible out of the box.
But a look at the source code of MvxWindow shows it's no big class. So a potential solution could be creation of your own window. This window, let's call it MvxMetroWindow, could collect both functionalities by inheriting from MetroWindow and aditionally all the source code of MvxWindow added (copied from the original source code) by yourself.
This would look like this:
using System;
using System.Windows;
using MahApps.Metro.Controls;
using MvvmCross;
using MvvmCross.Binding.BindingContext;
using MvvmCross.Platforms.Wpf.Views;
using MvvmCross.ViewModels;
using MvxApplication = MvvmCross.Platforms.Wpf.Views.MvxApplication;
namespace TipCalc.WPF
{
public class MvxMetroWindow : MetroWindow, IMvxWindow, IMvxWpfView, IDisposable
{
private IMvxViewModel _viewModel;
private IMvxBindingContext _bindingContext;
private bool _unloaded = false;
//... Further implemenetation of original MvxWindow
}
}
The custom window finally can be used like this:
<local:MvxMetroWindow x:Class="TipCalc.WPF.MainWindow"
xmlns:local="clr-namespace:TipCalc.WPF"
...

Run method missing in xaml class

I am using F# and XAML in order to create a GUI but unfortunately after creating the type for the xaml I don't have a run method available. What am I missing here?
code :
module Program
open FsXaml
open System
type App = XAML<"App.xaml">
[<STAThread>]
[<EntryPoint>]
let main argv =
let app = App()
app.Run()
App.xaml should contain an Application, not a window:
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
this will provide a Run method. Make sure you add a xaml file "MainWindow.xaml" with a window defined in it.

adding WindowsFormsHost control to MainWindow causes to crash the exe

I'm using WPF in F# via FsXaml. The MainWindow works, until I add a WindowsFormsHost control, at which point it will crash with the following error when executed:
Unhandled Exception: System.Xaml.XamlObjectWriterException: Cannot create unknown type '{http://schemas.microsoft.com/winfx/2006/xaml/presentation}WindowsFormsHost'.
at System.Xaml.XamlObjectWriter.WriteStartObject(XamlType xamlType)
at System.Xaml.XamlWriter.WriteNode(XamlReader reader)
at FsXaml.InjectXaml.from$cont#37(String file, Object root, Stream resStream, Unit unitVar)
at FsXaml.InjectXaml.from(String file, Object root)
at Program.Win.InitializeComponent()
at Program.Win..ctor()
Is there anything I need to add the xaml or the app to recognize the winformshost? The C# generated xaml works in a C# app. The F# app works if there is no winformshost inside it. The difference between the C# and F# xamls is the x-local namespace reference.
The MainWindow.xaml:
<Window
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="MainWindow" Height="350" Width="525">
<Grid>
<Button x:Name="button" Content="Button" HorizontalAlignment="Left" Height="124" VerticalAlignment="Top" Width="217"/>
<WindowsFormsHost HorizontalAlignment="Left" Height="123" Margin="49,171,0,0" VerticalAlignment="Top" Width="394"/>
</Grid>
</Window>
The App.xaml
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
Program.fs:
open System
open System.Windows
open FsXaml
open Microsoft.FSharp.Control
open System.Windows.Forms
open System.Windows.Forms.Integration
open FSharp.Charting
open FSharp.Charting.ChartTypes
type App = XAML<"App.xaml">
type Win = XAML<"MainWindow.xaml">
[<STAThread>]
[<EntryPoint>]
let main _ =
let app = App()
let win = Win()
win.button.Content <- "Click!"
win.button.MouseRightButtonDown.Add (fun _ -> MessageBox.Show("OK") |> ignore)
app.Run win |> ignore
0
Try explicitly adding the namespace (using clr-namespace), the same way you would for the winforms controls themselves - just use System.Windows.Forms.Integration. I assume that isn't included in the default XAML namespace :)
xmlns:wfi="clr-namespace:System.Windows.Forms;assembly=WindowsFormsIntegration"

Catel + Orchestra MahApps - Property 'Owner' is not found on the object

I'm using Catel + Orchestra.MahApps to build my application.
I'm trying to get custom Dialog working, and right now I'm stuck.
I have created SimpleDataWindow:
<orchestra:SimpleDataWindow x:Class="OrtMan.ViewModule.Photos.Views.NewPhotoWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:catel="http://catel.codeplex.com"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:orchestra="https://github.com/orcomp/orchestra"
xmlns:viewModels="clr-namespace:OrtMan.ViewModule.Photos.ViewModels"
d:DataContext="{d:DesignInstance viewModels:NewPhotoWindowViewModel}"
mc:Ignorable="d">
<Grid>
<TextBlock Text="aaa" />
</Grid>
</orchestra:SimpleDataWindow>
Then I'm trying to show it from my ViewModel like this:
var uiservice = ServiceLocator.Default.ResolveType<IUIVisualizerService>();
var showDialog = uiservice.ShowDialog<NewPhotoWindowViewModel>();
if (showDialog == true)
{
...
}
The result is that:
- Error in Catel logs: Property 'Owner' is not found on the object 'NewPhotoWindow', probably the wrong field is being mapped
- Dialog shows but without content
- it automatically returns true as dialogResult
I have tried with multiple IUIVisualizerService methods: Show/ShowDialog and also with async. Always same problem.
Am I doing something wrong?
If I remember correctly, all the dialogs inside MahApps.Metro are async. This means you should use the async methods of the IUIVisualizerService to show the dialogs.

XAML Namespace Beginning with a Number

I have inheritted Button and am trying to add it to my main window.
It doesn't show up in the Toolbox. I have tried rebuilding several times.
I have tried adding xmlns:dc="clr-namespace:123Letters and xmlns:dc="clr-namespace:123Letters;assembly=123Letters to my MainWindow.
My MainWindow is:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="MainWin"
Title="123 Letters">
</Window>
My WeatherStationButton is:
<Button x:Class="WeatherStationButton"
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>
</Grid>
</Button>
and
Public Class WeatherStationButton
Inherits Button
Public Property WeatherStation As tblWeather
End Class
This is super simple stuff. I believe it's because XAML doesn't allow numbers in the first part of namespaces, but I can not find any reference to that anywhere, so I am asking if I am doing something wrong or is this one of XAML's "features"?
Just realized I could add my answer.
If your project name is 123Letters, you need to add an underscore before the first number when referencing it in XAML like, _123Letters.
Your clr-namespace declaration would then be:
xmlns:dc="clr-namespace:_123Letters"
and you could add your inherited button to your MainWindow like this:
<dc:WeatherStationButton x:Name="btnWS" />

Resources