How to properly use a Subclassed silverlight control? - silverlight

I created this class where I wanted to override this specific event for the content control.
public class MyContentControl : ContentControl
{
protected override void OnKeyUp(KeyEventArgs e)
{
//do something
//..........
e.Handled = true;
}
}
However when I am using this control in my XAML everything compiles and works fine, but I am getting a runtime exception and I am not sure exactly why? Could someone point me in the right directions....
The exception I get is
XamlParseException
UPDATED (Shows where abouts of the exceptions)
In the XAML I have:
xmlns:ctrls="clr-namespace:SilverlightProject.CustomControls"
and I use it like:
<ctrls:MyContentControl Grid.Column="0" x:Name="_contentControl" VerticalAlignment="Center" HorizontalAlignment="Center" />

Content controls require a default template to be created somewhere (e.g. in generic.xaml). They do not have a matching XAML file like user controls.
If you can provide more information, I can show you how to create an appropriate template.

There are many reasons for this.
To start with. Give the fully qualified namespace.
Instead of
xmlns:ctrls="clr-namespace:SilverlightProject.CustomControls"
Use
xmlns:ctrls="clr-namespace:SilverlightProject.CustomControls;assembly=YourAssebmlyName"
If that, doesn't help.
You directly attach your control with the application. Then, enable Debug -> Exceptions. Check Thrown option for the CLR execetion checkbox. You have fair amount of possibility to get to know the cause.

Related

Prism regions not displaying registered views

I'm using PRISM in a SilverLight 4 application. I have a problem where views registered to some regions doesn't get displayed.
When loading a module at startup I register some views to regions as follows:
RegionManager.RegisterViewWithRegion("MyRegion1", typeof(IMySubView1));
RegionManager.RegisterViewWithRegion("MyRegion2", typeof(IMySubView2));
I have a view implementing an interface called IMyView, where the xaml have two contentcontrols with regions defined in a grid like this:
<ContentControl Regions:RegionManager.RegionName="MyRegion1" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Grid.Row="0" Grid.RowSpan="1"/>
<ContentControl Regions:RegionManager.RegionName="MyRegion2" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Grid.Row="1" Grid.RowSpan="1"/>
I have tried two different methods for adding the view to the main region. Both adds the view and basic elements such as buttons get displayed, but the regions defined in the view does not get filled with associated views.
Method 1:
object obj = _container.Resolve<IMyView>();
IRegion mainRegion = _regionManager.Regions["MainViewRegion"];
IRegionManager scoped = mainRegion.Add(obj, "test", true);
mainRegion.Activate(obj);
// Enabling the following call, it will fail saying the region MyRegion1 does not exist. Feels like it should?
// IRegion myRegion = scoped.Regions["MyRegion1"];
Method 2:
object obj = _container.Resolve<IMyView>();
_regionManager.AddToRegion("MainViewRegion", obj);
_regionManager.Regions["MainViewRegion"].Activate(obj);
It feels like the regions defined in the xaml file doesn't get registered, and because of that the registered views do not get displayed.
The MainViewRegion is defined in the shell in a TabControl as this:
<TabControl Margin="8,0,8,8" Regions:RegionManager.RegionName="MainViewRegion">
Any suggestions on solving my problem will be greatly appreciated!
I'm facing the same problem. The idea is that for whatever reason view injection {mainRegion.Add(obj, "test", true)} for already created regions doesn't show the view. A workaround that worked for me, is to create the region from code, and then inject the view. Something like this:
Microsoft.Practices.Composite.Presentation.Regions.RegionManager.SetRegionManager(headerRegionContainer, _RegionManager);
Microsoft.Practices.Composite.Presentation.Regions.RegionManager.SetRegionName(headerRegionContainer, regionName);
var view = _UnityContainer.Resolve(bag.HeaderViewType);
_RegionManager.Regions[regionName].Add(view);
_RegionManager.Regions[regionName].Activate(view);
Unfortunately for me I can't reach my goal this way, but maybe you can.
Regards,
Levente
After many hours of troubleshooting I found something.
In Composite.Presentation\Regions\RegionManager.cs there is a method called IsInDesignMode. When a region is about to be created this method is called, and if this method returns true the region is not created. See below:
private static void OnSetRegionNameCallback(DependencyObject element, DependencyPropertyChangedEventArgs args)
{
if (!IsInDesignMode(element))
{
CreateRegion(element);
}
}
private static bool IsInDesignMode(DependencyObject element)
{
// Due to a known issue in Cider, GetIsInDesignMode attached property value is not enough to know if it's in design mode.
return DesignerProperties.GetIsInDesignMode(element) || Application.Current == null
|| Application.Current.GetType() == typeof(Application);
}
When our silverlight application starts up and the regions in the shell gets created everything is fine, the Application.Current property is of type "MyName.Shell.App". But when a view gets added after startup, as a response to user input, the Application.Current type is suddenly of type "Application", and thus the IsInDesignMode method returns true and the regions are not created.
If I remove the Application.Current conditions everything works as expected. So the question is, is there something wrong in my application or is there something wrong in the prism source code?
where is your _regionManager coming from ?
Did you write a proper BootStrapper
?
You need to write a class inheriting from MefBootstrapper or UnityBootstrapper (or a custom one if you're not using neither of those IoC/Extension framework) in order to register all your needed types within the IoC container.
could you post the BootStrapper code ?
The problem is gone in Prism version 4.0, I was running Prism version 2.2 when the problem occured.

Element is already the child of another element

I get the folowing error in my Silverlight application. But i cant figure out what control it is that is the problem. If i debug it don't break on anything in the code, it just fails in this framework callstack with only framework code. Is there any way to get more information on what part of a Silverlight app that is the problem in this case.
Message: Sys.InvalidOperationException: ManagedRuntimeError error #4004 in control 'Xaml1': System.InvalidOperationException: Element is already the child of another element.
at MS.Internal.XcpImports.CheckHResult(UInt32 hr)
at MS.Internal.XcpImports.Collection_AddValue[T](PresentationFrameworkCollection`1 collection, CValue value)
at MS.Internal.XcpImports.Collection_AddDependencyObject[T](PresentationFrameworkCollection`1 collection, DependencyObject value)
at System.Windows.PresentationFrameworkCollection`1.AddDependencyObject(DependencyObject value)
at System.Windows.Controls.UIElementCollection.AddInternal(UIElement value)
at System.Windows.PresentationFrameworkCollection`1.Add(T value)
at System.Windows.Controls.AutoCompleteBox.OnApplyTemplate()
at System.Windows.FrameworkElement.OnApplyTemplate(IntPtr nativeTarget)
The XAML for the AutoCompeletBox that is in the context is:
<tk:AutoCompleteBox
x:Name="acName"
Grid.Row="0"
Grid.Column="1"
LostFocus="acName_LostFocus"
Height="20"
Width="80"
HorizontalAlignment="Left"/>
The error is a generic catch-all exception that has many many causes. I've written a debugger utility that can help to identify which part of the XAML is actually causing the error. You can download it from my blog: http://whydoidoit.com/2010/08/30/debug-xaml-element-is-already-the-child-of-another-element/
Your items may be visual elements, instead of data objects.
If you provide the XAML, I can help make sure that is the case.
Usually this error occurs when the said Element is already attached to an existing Parent and somewhere in your code you're attempting to re-parent it (ie via just straight "add" when you in turn must remove the child from the parent first, then Add it to the children etc).
Where specifically the control is failing the above isn't enough info to digest.
Simple and stupid solution:
public class AutoCompleteTextBox : AutoCompleteBox
{
public override void OnApplyTemplate()
{
try
{
base.OnApplyTemplate();
}
catch { }
}
}

Accessing the WebContext class in XAML

The generated App.xaml.cs file contains this
private void Application_Startup(object sender, StartupEventArgs e)
{
// This will enable you to bind controls in XAML files to WebContext.Current
// properties
this.Resources.Add("WebContext", WebContext.Current);
but I cannot figure out how to refer to this object. It seems like I ought to set the page DataContext = "WebContext" and then use it like this
... property="{Binding Path=User.IsAuthenticated}
I'm sure it's straightforward. Can someone clue me in?
Well done, and of course I can't believe I didn't see that. With the addition of a value converter suddenly a tangled mess of state management code becomes declarative, showing and hiding various UI elements according to whether the user is logged in or in various roles without me having to litter my code with trivial conditionals at myriad logical inflection points.
Try:-
property="{Binding Path=User.IsAuthenticated, Source={StaticResource WebContext}}"
that ought to find it. Its not an object you'd want directly assigned to the DataContext normally, the similarity of the names is co-incidental.

Dynamic Application-level resources are not dynamic when hosted in ElementHost

I'm hosting a WPF UserControl in a WinForms container. Now, I want to be able to theme/skin the UserControl. To do this, I've got several resource dictionaries that define the "skins." When my app starts up I create a "new System.Windows.Application()" so that Application.Current exists. To change the theme the old skin is removed and a new skin is merged into the Application level resource dictionary at runtime. However, this does not change any of the dyanamically referenced resources in the UserControl. I tried this in a straight WPF application and it worked just fine. Am I missing something, or is it not possible to do this at all? By the way, if I add a skin into the application resources before the UserControl is initialized it will work but I cannot change the skin after that.
To repo this in the most basic way:
Create a new WinForms application. Add a WPF UserControl to the app. This is simple enough:
<UserControl ...>
<Grid>
<Button
Background="{DynamicResource ButtonBG}"/>
</Grid>
</UserControl>
Create two ResourceDictionaries, White.xaml and Black.xaml (or whatever) that have a SolidColorBrush with the key ButtonBG with respective color. In Form1.cs, add two Buttons and an ElementHost. Set the child of the ElementHost to an instance of the UserControl we just created. Wire up the buttons to events that swap the skin:
private void White_Click(object sender, EventArgs e)
{
Application.Current.Resources.MergedDictionaries[0] =
(ResourceDictionary)Application.LoadComponent(
new Uri(#"\WpfThemes;component\White.xaml", UriKind.Relative)));
}
private void Black_Click(object sender, EventArgs e)
{
Application.Current.Resources.MergedDictionaries[0] =
(ResourceDictionary)Application.LoadComponent(
new Uri(#"\WpfThemes;component\Black.xaml", UriKind.Relative)));
}
In Program.cs, ensure that Application.Current exists and set the initial skin:
[STAThread]
static void Main()
{
new System.Windows.Application();
Application.Current.Resources.MergedDictionaries[0] =
(ResourceDictionary)Application.LoadComponent(
new Uri(#"\WpfThemes;component\White.xaml", UriKind.Relative)));
...
}
Now, when the White button is clicked I would expect the button in the UserControl to turn white and when the Black button is clicked I would expect the button to turn black. This does not happen, however.
Does anyone know why? Is there a solution?
Edit: Idea: Perhaps, if there's a way to force re-evaluation of DynamicResources when the theme changes, that would work.
Thanks,
Dusty
I think this may be an overlooked issue in the WPF framework.
From what I can tell via Reflector, it appears that when the Application resource dictionary is catastrophically changed (a change that will likely have wide ranging effects like adding, removing, or replacing a skin), there is code that loops over all of the Windows in the application and forces them to re-evaluate their DynamicResources. However, other elements that I would consider top-level in WPF like ElementHosts do not get the same treatment. This leads to the behavior that I'm experiencing.
My workaround to this issue is to manually go through all of my ElementHosts individually and add, remove, or replace the skin ResourceDictionary file. It's not perfect, but it gets the job done.
Dr. WPF came to my rescue when I was trying to do something similar. He shows how to create the Application object in WinForms. Now you can reference everything as StaticResource just like in a WPF application.
http://drwpf.com/blog/2007/10/05/managing-application-resources-when-wpf-is-hosted/
Another workaround would be to create a dummy window and specify the content of the elementhost as content.
If you look into the Application and check how it handles changes of resourcedictionaries, you see that it only notifies windows..
The only thing you should remind is to never show the window (-> exception), and to close it when disposing the elementhost, so the application can shutdown properly.

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