Silverlight Custom Control in F# DefaultStyleKey - silverlight

Wondering how to accomplish setting the Style xaml with the code in F#. The code is simple enough:
this.DefaultStyleKey <- typeof<MyControl>
In a C# project the build options allow you to mark the XAML as a resource custom build command of: MSBuild:Compile
I don't see it in the properties panel, so I tried to add it by hand to the project file myself...
Any ideas? The application loads - the custom control has no output (but the code executes).
Thanks
UPDATE:
I checked the manifests and the resource was included as expected between my project and the project I am porting... Looking for a next step.
UPDATE 2:
Well it may be included in the manifest OK - but it is not being "compiled" as the C# version of the project throws an error in the build process when I malform the XML while the F# version allows the malformed XML to be brought into the application.
UPDATE 3:
Loading the XAML is fine now (i guess) however I am having some issues with the properties of the control:
static member ItemsProperty : DependencyProperty =
DependencyProperty.Register(
"Items",
typeof<MyMenuItemCollection>,
typeof<MyMenu>,
null);
member this.Items
with get () : MyMenuItemCollection = this.GetValue(MyMenu.ItemsProperty) :?> MyMenuItemCollection
and set (value: MyMenuItemCollection) = this.SetValue(MyMenu.ItemsProperty, value);
The problem occurs on access:
for menuItem in this.Items do
let contentElement: FrameworkElement = menuItem.Content
where I get a null pointer exception on this.Items; however I have it initialized in the constructor:
do
this.Items <- new CoolMenuItemCollection()

The C# style of compilation of XAML files is not supported by the F# tools for Visual Studio, so there is no way to get the same behavior as in C#. I think you have two options:
Create a C# project with XAML files and reference F# library which implements the core functionality (or reference C# library from F# and load user interface from the C# library in your F# application)
Use XamlReader object (see MSDN) and load the XAML file (embedded in resources in the simple way) programmatically. You won't get any of the C#-compiler generated features (e.g. named properties for all objects with x:Name), but otherwise, it should work in the usual way.

Related

MVVM / PRISM: Where should dialog box strings be stored?

I'm building an application using PRISM and MVVM. I have a view model that needs to display a non-modal dialog box to the user indicating an operation is in progress. I'm using essentially an abstracted IDialogService.
My question is: where should I store the strings for the title and the message shown in this dialog box? The view model's logic causes the dialog box to be displayed and determines when it should be closed. Hence, I have code that looks like this in my view model:
let! closeDlgAction =
dialogSvc.ShowDialogModeless (
"Opening File",
"Please wait while your selected file is opened.") |> Async.AwaitTask
I'm thinking about localization scenarios. WPF has its own mechanism for providing localization through resource dictionary, etc. It seems like these strings belong in a resource dictionary, but the view model shouldn't have a dependency on WPF resource directories - especially because the same view model is going to be used on a Xamarin Forms application later.
The best solution that comes to mind is to use a service that abstracts the resource library away (e.g. IDialogStringService), but I wonder if there's a better or more preferred approach?
You shouldn't use resource dictionaries (xaml) to store text. Instead you have to use Resources (*.resx). In VS:
Right click on project
Add -> New Item...
Find "Resources File" template, type name, and click Add
Opt. Open this file (special editor will opened) and on top bar switch Access Modifier to Public, if you want get access to text from another project or from XAML. Add some key\value strings.
Right click on resource file and click Run Custom Tool. New class will generated with static properties with names based on your keys from Step 4.
How to use (if file has name Localizations.resx and has string with key "AppTitle")
From code:
let! closeDlgAction =
dialogSvc.ShowDialogModeless (
Localizations.AppTitle,
"Please wait while your selected file is opened.") |> Async.AwaitTask
From xaml:
<Window
x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="{x:Static Localizations.AppTitle}"/>
*.resx file and *.cs file that is generated both don't depend on any WPF assemblies, so you can use them in different assemblies: in shared view models, from wpf views and from xamarin views. Just put you *.resx file in separate netstandard assembly and refer to it where do you need it from
Cons of this way:
resx generates class with strings and each string is public property, so static code analyze works
You don't have add new abstraction level
You can ref strings from code files or from XAML
I liked Vadim's answer, and I have used that approach before. If my View Models lived in the same project as the WPF project, that would be the best solution.
However, my View Models are in a different library (and a different language) and will be shared between a Prism MVVM WPF project and a Prism MVVM Xamarin Forms project. I could still use resources in the View Model library, but then localization concerns would exist separately in both the WPF project (for the Views) and the View Model library. IMO the localization concern should be centralized.
As such, I decided to abstract the resources behind a service. Implementing the resource service turned out to be more straightforward than I thought. To use an indexer intuitively, I defined a "resource container object" that is returned by IResourceService, as seen below:
public struct ResourceContainer
{
private readonly Func<string, string> _resourceGetter;
public string this[string resourceId] => _resourceGetter(resourceId);
public ResourceContainer(Func<string, string> resourceGetter) => _resourceGetter = resourceGetter;
}
public interface IResourceService
{
ResourceContainer Resources { get; }
}
And the service implementation in the WPF library is as follows:
public class ResourceService : IResourceService
{
public ResourceService()
{
Resources = new ResourceContainer((s) => Application.Current.Resources[s] as string);
}
public ResourceContainer Resources { get; }
}
In the WPF layer's XAML resource directory:
<s:String x:Key="FileOpenDialogTitle">Opening File</s:String>
<s:String x:Key="FileOpenDialogMessage">Please wait while your selected file is opened.</s:String>
And, finally, the View Model consumes this service by requesting IResourceService on its constructor, and is used as follows:
let! closeDlgAction =
dialogSvc.ShowDialogModeless (
resourceSvc.Resources.["FileOpenDialogTitle"],
resourceSvc.Resources.["FileOpenDialogMessage"]) |> Async.AwaitTask
This approach will ultimately require implementing the resources twice - once for the WPF project and once for the XF project, but I have to implement the Views twice, anyway. At least the localization concerns are centralized in both cases (or perhaps a shared resource library can be used between both projects).
EDIT: This technique could also leverage Vadim's suggestion by putting the localization resource (.resx) in the WPF project as well, and either having the XAML resource directory reference the static resources, or have the ResourceService return the resource directly. Having the resources in .resx format may make sharing them between multiple projects more straightforward.

The type 'Window' does not support direct content

I have a WPF solution built with VS 2015 composed of several projects. Suddenly I started receiving a warning in design mode stating the following:
The type 'Window' does not support direct content.
I understand how some controls do not support direct content, but System.Windows.Window should. I get the same warning with UserControl, and as far as I know, any other control that typically supports direct content.
Everything compiles and runs fine, but having the blue underlines through all of my XAML is bothersome. Has anyone else come across this?
Below is a screenshot:
Make sure you reference System.Xaml. Clean and rebuild the project. Works on VS 2015 Update 1.
At least in a WPF IronPython project, adding the System.Xaml reference to the project solved the problem for me:
An important thing to note here is that adding seemingly any reference will make the problem go away temporarily -- until Visual Studio is restarted. System.Xaml, on the other hand, appears to keep the problem at bay. I even tried removing the reference, whereafter the problem returned upon restarting Visual Studio.
For me this error was happening because I added a WPF Window to a class library project.
For some reason (unknown by me), Visual Studio doesn't give us the option to select the WPF Window template from the "Add New Item..." dialog box if the project was not created as a WPF Application. Instead, it only offers the option to add a WPF User Control. Because of that, I selected the User Control template for the new item, and then edited the source code to make the XAML to become a Window object rather than a User Control.
<!-- The new item was created as an UserControl, but what I needed was a Window object. -->
<UserControl>
...
</UserControl>
<!-- Changed it to Window and made other necessary adjustments. -->
<Window>
...
</Window>
The problem was actually in the code-behind. Since it was created as an User Control, the window partial class was inheriting from UserControl, like the following:
public partial class MyWindow : UserControl
{
public MyWindow ()
{
InitializeComponent();
}
}
To fix it I just had to remove the inheritance, making my window class inherith from nothing, like this:
public partial class MyWindow
{
public MyWindow ()
{
InitializeComponent();
}
}
After removing the inheritance, Visual Studio didn't show the error "The type 'Window' does not support direct content." anymore.
on behalf of #mark Richman I edited the Itemtemplate to automatically Reference "System.Xaml".
Just in case some is interested:
can be found in: "[VS InstallDir]\Common7\IDE\ItemTemplates\VisualBasic\WPF\[InputLocale]\WPFWindow"
BR,
Daniel
Add System.Xaml and UIAutomationProvider references to your project, after that clear solution and then build again
in Visual studio 2019 :
I searched for ( System.Xaml.dll )
and I added it as a reference
its worked well
found it in this location:
" C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.8 "

Converting WPF application to UserControl for use in WinForms application via ElementHost

I'm trying to convert this WPF application to WPF UserControl so I could use it in WinForms application via ElementHost. I'm new to WPF and have never even touched it prior to this attempt so I might be going about it completely the wrong way.
I got the UserControl project to compile, however, my StaticResources get underlined in VS with message "The resource 'x' could not be resolved". I've tried moving the xamls with the needed x:Key elements up one level (the same level as the UserControl Dijagram.xaml), but it still cannot resolve them.
In the WinForms app, when trying to add the UserControl through designer by selecting hosted content in ElementHost tasks I get the following error:
An error occured trying to create an object of type
'DijagramLC.Dijagram'. Make sure the type has a default constructor.
(even though default constructor exists).
However, if I add it in codebehind, like this:
wpfUserControl = new Dijagram();
elementHost1.Child = wpfUserControl;
Controls.Add(elementHost1);
the code compiles but throws this runtime error: "System.Windows.Markup.XamlParseException: 'Provide value on 'System.Windows.StaticResourceExtension' threw an exception.' Line number '20' and line position '4'. ---> System.Exception: Cannot find resource named 'MyToolbar'. Resource names are case sensitive."
I've tried with and without App.xaml and adding ResourceDictionary elements for problematic xamls, but basically, I have no idea what I'm doing :)
I've uploaded the code to my SkyDrive and would really appreciate it if someone could take a look and tell me what I'm doing wrong:
https://skydrive.live.com/redir.aspx?cid=21be1f8e850e85cc&resid=21BE1F8E850E85CC!353
I hate jumping in blindly to new techonoly like this, but I have had no choice this time, and need to know if my requirement is even achievable this way.
You are probably getting the error because you use resources from a resource dictionary which is not loaded. Loading a resource dictionary in the hosting application will probably solve the issue:
// When hosting a WPF usercontrol inside an element host,
// application resources are not loaded, so we need to load them manually.
var resources = new ResourceDictionary
{
Source = new Uri("/UNIT4.MKB.GUI.XAML.Dashboard.Resources;component/resources.xaml", UriKind.Relative)
};
// Check for null reference
if (Application.Current != null)
{
//Merge the loaded ResourceDictornairy with the dummy application Resources.
Application.Current.Resources.MergedDictionaries.Add(resources);
}
The problem is, you need THE default constructor like this:
public CreatedPollsUC()
{
InitializeComponent();
}
If you have any other code in the constructor, the error occures:
public CreatedPollsUC()
{
InitializeComponent();
// ... more code
}
So if you want to use further code in the constructor, you need to apply the control first to the element host. Then you can edit the constructor.

Silverlight 4 Equivalent to WPF "x:static"

I'm working on a project that is based on an old project someone started and didn't finish. I was trying to use as much of their code as I could, so in doing so I ran into some tweaking issues.
Namely, when I put some of the old xaml in the new project there were some errors that were thrown regarding the "x:static" property and "Dynamic property."
here are the error messages themselves:
Error 1: The type 'DynamicResource' was not
found. Verify that you are not missing
an assembly reference and that all
referenced assemblies have been built.
Error 2: The type 'x:Static' was not found.
Verify that you are not missing an
assembly reference and that all
referenced assemblies have been built.
Some notable points that I think is causing the errors: the old project was programmed in VS2008, WPF, v3.5 .Net framework; whereas I am programming in VS2010, Silverlight 4, .Net framework v4.0.
I realize there are differences from WPF to Silverlight as far as xaml goes and there are plenty of differences from the different .Net framework versions and editions of Visual Studio. But I just can't seem to find a fix for this anywhere so I didn't know if there was just a library I was missing or just something I'm simply overlooking or what.
I can recreate this if need be, but like I said, I'd rather use as much of the old code as I can as long as the tweaking doesn't cause more trouble than what it's worth.
Unfortunately, you can't directly use the DynamicResource and Static keywords in a Silverlight's subset of XAML, but you can mimic their behavior. Here is the article on the topic:
{x:Type} and {x:Static} in Silverlight
In general, there is no easy way to migrate a project from WPF to Silverlight. They have very much in common, but strictly speaking are a different technologies.
Another way to achieve binding to static properties - to bind in code. Below is an example.
Main application class:
public partial class App : Application
{
public static MyViewModel MyViewModel { get; private set; }
// ...
}
Main window markup:
<TextBlock Loaded="MyTextBlockLoaded" />
Main window back-code:
public partial class MainPage : PhoneApplicationPage
{
// ...
private void MyTextBlockLoaded(object sender, RoutedEventArgs e)
{
TextBlock textBlock = ((TextBlock)sender);
if (textBlock.Tag == null)
{
textBlock.Tag = true;
Binding bind = new Binding("MyInfo");
bind.Source = App.MyViewModel;
bind.Mode = BindingMode.OneWay;
textBlock.SetBinding(TextBlock.TextProperty, bind);
}
}
}
Maybe the TextBlock.Tag approach of checking, was Binding already set or not, isn't the most elegant one, but it works.

PRISM - Creating mouseoverbehavior causes a Silverlight library to not be visible in main Silverlight app to be able to create namespace ref in xaml

Created a simple Silverlight 4 application (SimpleApp) then added a Silverlight 4 library (LibraryA). Added code to the library (LibraryA) to implement MouseOverBehavior by inheriting from CommandBaseBehavior along with the appropriate attached property class/methods. Added reference in SimpleApp to LibraryA and went to MainPage.xaml to add namespace reference but it does not show up with Intellisense. Typing the namespace manually and then adding the attached MouseOver command works as it should as far as intellisense showing my attached property name, i.e. ... commands:MouseOver.Command="{Binding MousedOver}". However when I try to run it I get a XAML parser error saying that the "Command" attached property does not exist in MouseOver. If I move my class definitions from LibraryA to SimpleApp then everything works.
I removed everything from LibraryA and just put one class with this in it:
public class MouseOverBehavior : CommandBehaviorBase<Control>
{
public MouseOverBehavior(Control element)
: base(element)
{}
}
With this simple class in LibraryA it will not show up in XAML intellisense in SimpleApp. XAML intellisense works with other libraries that I have written that don't use PRISM.
Don't know what I am missing hopefully it's something simple. I am using the latest SL4 build for PRISM change set 42969. Visual Studio 2010 RTM Professional in Windows 7 Ultimate 64-bit.
I found out that the problem was something simple. I was missing a reference to one of the PRISM libraries. I guess after looking at it for hours I just couldn't see what was missing. A day off and it finally clicked, DUH!

Resources