Silverlight 4 Equivalent to WPF "x:static" - wpf

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.

Related

Can Prism's Regions work with MUI's IContent?

I've been tasked with upgrading and rationalising a WPF project built using ModernUI. It references Prism but doesn't actually use it anywhere - almost all code is in code-behind files under the XAML.
This is not testable or maintainable, so I'm implementing viewmodels and working my way through using Prism properly. However, obviously I can't change the look too much and frankly, a visual redesign is not in scope for me, I'm not a graphic designer.
So we're fine, up until we get to navigation. I can't find any reference or even a hint on how to use mui's IContent alongside Prism's Regions.
Can anyone offer a clue?
EDIT:
I still can't seem to get Regions working and thus lose modularity, but I have discovered that I can do navigation in an MVVM way with mui.
If anyone's interested, both MenuLinkGroups and TitleLinks are dependency properties of ModernWindow so it's actually fairly easy to construct them in the viewmodel and bind like this in the Window declaration -
TitleLinks ="{Binding TitleLinks}"
MenuLinkGroups ="{Binding MenuLinkGroups}"
and in the viewmodel -
private LinkGroupCollection _menuLinkGroups = new LinkGroupCollection();
public LinkGroupCollection MenuLinkGroups
{
get => _menuLinkGroups;
set => SetProperty(ref _menuLinkGroups, value);
}
private LinkCollection _titleLinks = new LinkCollection();
public LinkCollection TitleLinks
{
get => _titleLinks;
set => SetProperty(ref _titleLinks, value);
}
I haven't tried this with UserControl yet but I'm fairly convinced it works the same way.
I would still value Regions and thus modules. Any help is appreciated.

WPF toolbox installer for a type defined in a different assembly

I'm trying to create a VSIX installer for a WPF control.
Its supposedly easy, but the "easy" version assumes that you create the WPF control in the VSIX project.
The thing is, I've got my UserControl nestled deep within one of my DLLs, and I don't believe pulling it out is the best design. I'd like to leave it in there, but I can't seem to do this AND have the control added to the toolbox.
One option would be to move the code I need to install it to the toolbox into the control's assembly, but that would add a dependency to Microsoft.VisualStudio.Shell.Immutable.10.0.dll. The assembly is both used by someone with Visual Studio installed, and a remote server running within a service where VS isn't installed, so that's a no-go.
Another option I tried was to "trick" the toolbox installer VSIX by applying the RegistrationAttribute to proxies which would register the types defined in the other assembly. Thought it would work, but weird stuff happened.
Instead of getting two controls, I get a bunch of Border controls (the standard WPF border) in oddly named tabs, some of which echo some of my namespaces.
How can I register a WPF UserControl with the Toolbox when the control is defined in an assembly other than the VSIX?
I was able to whip up a proof of concept similar to the proxy idea that you had mentioned.
The problem that you're seeing is caused by the registration of the wrong assembly, so I created a new registration attribute called ProvideProxyToolboxControlAttribute which is used as an attribute on the proxy classes that you have in your VS integration assembly. It's almost identical to ProvideToolboxControlAttribute except that it takes the type of the actual control. Of course, this new attribute would also be in your VS assembly.
For example, say I have a toolbox control in my non-VS assembly called MyToolboxControl, I'd create a simple proxy class MyToolboxControlProxy in my VS assembly that looks like this:
[ProvideProxyToolboxControl("MyToolboxControl", typeof(NonVsAssembly.MyToolboxControl))]
public class ToolboxControlProxy
{
}
And of course, the magic happens in ProvideProxyToolboxControlAttribute, which is basically just this class (comments and parameter/error checking removed for brevity):
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
[System.Runtime.InteropServices.ComVisibleAttribute(false)]
public sealed class ProvideProxyToolboxControlAttribute : RegistrationAttribute
{
private const string ToolboxControlsInstallerPath = "ToolboxControlsInstaller";
public ProvideProxyToolboxControlAttribute(string name, Type controlType)
{
this.Name = name;
this.ControlType = controlType;
}
private string Name { get; set; }
private Type ControlType { get; set; }
public override void Register(RegistrationAttribute.RegistrationContext context)
{
using (Key key = context.CreateKey(String.Format(CultureInfo.InvariantCulture, "{0}\\{1}",
ToolboxControlsInstallerPath,
ControlType.AssemblyQualifiedName)))
{
key.SetValue(String.Empty, this.Name);
key.SetValue("Codebase", ControlType.Assembly.Location);
key.SetValue("WPFControls", "1");
}
}
public override void Unregister(RegistrationAttribute.RegistrationContext context)
{
if (context != null)
{
context.RemoveKey(String.Format(CultureInfo.InvariantCulture, "{0}\\{1}",
ToolboxControlsInstallerPath,
ControlType.AssemblyQualifiedName));
}
}
}
It seems to work well, I verified that the control is in the toolbox and that the proper registry keys were added.
Hope this helps!

Getting Silverlight MVVM working with Expression Blend design time data?

I am a big proponent of the MVVM pattern with Silverlight. Currently I wire the ViewModel up to the View by newwing up the ViewModel in the code behind of the view, thusly:
public partial class SomePage : UserControl
{
public SomePage()
{
InitializeComponent();
// New up a ViewModel and bind to layout root
var vm = new SomeViewModel();
LayoutRoot.DataContext = vm;
}
}
And then all the binding is handled in the View and all the logic is handled in the ViewModel, as the pattern intends.
However, wiring them up this way means that the designer doesn't work well, and I can't use Expression Blend design time data. I know that there are libraries such as MVVM Light that will help to get all this working, but I prefer not to bring in a library, as it is "one more thing" to have to deal with.
Is there a simple pattern for getting MVVM wired up in Silverlight while maintaining designer functionality, especially in Blend? I've done some Googling but there are so many outdated articles out there and so much confusion between WPF and Silverlight and older versions that I have a hard time figuring out which to use.
BTW I'm focused on SL4 with VS2010 if it matters.
There are a few methods you can use.
First, let Expression's Sample Data and design-time attributes (i.e. d:DataContext) take over in the designer. In your code, you would simply condition the view model binding:
if (!DesignerProperties.IsInDesignTool)
{
var vm = new SomeViewModel();
LayoutRoot.DataContext = vm;
}
Second, you can have a special design-time view model that you bind instead:
LayoutRoot.DataContext = DesignerProperties.IsInDesignTool ?
new DesignViewModel() : new MyViewModel();
Finally, another way is to manage the data within the view model. I don't like this because it spreads the responsibility across all view models, but you have more precision:
// constructor
private Widget[] _designData = new[] { new Widget("Test One"), new Widget("Test Two") };
public MyViewModel()
{
if (DesignerProperties.IsInDesignTool)
{
MyCollection = new ObservableCollection<Widget>(_designData);
}
else
{
MyService.Completed += MyServiceCompleted;
MyService.RequestWidgets();
}
}
private void MyServiceCompleted(object sender, AsynchronousEventArgs ae)
{
// load up the collection here
}
Hope that helps!
What you are looking for is "Blendibility". MVVM Light has a concept of the ViewModelLocator and I'm using it on a project with great results.
Here's a great post by Roboblob on the topic. http://blog.roboblob.com/2010/01/17/wiring-up-view-and-viewmodel-in-mvvm-and-silverlight-4-blendability-included/ This post has an example solution so it really helps in the understanding. Rob improves on the MVVM Light implementation and I think does a good job.
I've run into similar issues designing WPF applications. One trick I've learned is to declare an xmlns so you can embed an array of objects in XAML:
xmlns:coll="clr-namespace:System.Collections;assembly=mscorlib"
You can then drop an ArrayList of just about anything into the XAML:
<coll:ArrayList x:Key="questions">
<local:QuestionItem Title="FOO"></local:QuestionItem>
</coll:ArrayList>
You can then set the ItemsSource of a grid, listbox, etc to the array:
<ListBox x:Name="lstStuff" ItemsSource="{StaticResource questions}" />
This technique will allow you to "preview" the look and feel of list-style controls in the designer. It doesn't solve all problems with visual prototyping, but it goes a long way and can be adapted to several different scenarios.
You could, for example, declare your local namespace as an xmlns, then drop mocks of your ViewModel into the Resources of the window or control. I haven't tried this but theoretically you could get a complete design-time preview.

Silverlight Custom Control in F# DefaultStyleKey

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.

UserControl that has a generic class in its inheritance tree

I'm trying to create a UserControl that inherits from a generic class. It does not directly inherit from a generic class, but through an intermediate class that does not use generics. This compiles and works at runtime, but I get an error at design time.
Here's my generic parent class:
Public Class GenericParent(Of T)
Inherits UserControl
End Class
Here's my non-generic parent class:
Public Class NonGenericParent
Inherits GenericParent(Of String)
End Class
Here's my XAML:
<local:NonGenericParent x:Class="SilverlightApplication5.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SilverlightApplication5"
Width="400" Height="300">
<StackPanel>
<Button Content="Hello"/>
</StackPanel>
</local:NonGenericParent>
The IntelliSense parser gives the following errors:
The property 'Width' was not found in type 'NonGenericParent'.
The property 'Height' was not found in type 'NonGenericParent'.
The type 'NonGenericParent' does not support direct content.
It is as though IntelliSense can't see up the inheritance tree past the GenericParent class. I've tried specifying the ContentPropertyAttribute directly on the SilverlightApplication5.Page class, the NonGenericParent class, and it does not work.
I've read that the TypeArguments attribute is not supported in Silverlight 2.0. That is why I've created the intermediate NonGenericParent class.
If anybody has any ideas how to silence these errors I'd be eager to hear them.
Update: We've opened a support ticket with MSFT, I'll update this with whatever their solution is.
We've received word from Microsoft that this is not likely to be fixed in future versions. After they bounced the problem around trying to find the responsible group, it appears that this problem belongs to their WPF developer group, which is where the 'not going to fix it' answer came from.
In the meantime, we've updated our code to yank out the generics from the parent classes until I guess XAML 2009.
Not sure about silverlight, but this compiles and runs as expected in c#:
class GenericObject[T] : UserControl
{
}
class StaticObject : GenericObject[Int32]
{
public Int32 wide { get { return this.Width; } }
}
private void Form1_Load(object sender, EventArgs e)
{
StaticObject so = new StaticObject();
this.Text = so.wide.ToString();
}
So if it compiles against the clr, it should work just fine.
Could be just an intellisense bug as you're suggesting. Normally I'd advise against ignoring comiler warnings, but in this case it seems that the warning is not valid.
edit: substituted angle brackets with square brackets cause SO stripped them.
Despite being at 2.0 silverlight (and especially the VS2008 tweaks for silverlight) are still very young. There are still quirks in the IDE stuff.
Do you still have the problem even after a sucessful build?
This blog post seems to be related to your issue:
http://blogs.msdn.com/b/wpfsldesigner/archive/2010/01/22/known-issue-controls-deriving-from-a-generic-base-class-must-be-in-separate-assembly.aspx
For Silverlight it seems that you must have 3 classes for this to work.

Resources