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.
Related
I have a custom control in the early stages of development as I endeavour to learn about wpf custom control development. The custom control inherits from ItemsControls which gives me access to an ItemsSource property to which I am binding an enumerable collection.
Currently I have a simple two project solution comprising my custom control in one and a test project in the other to test the former. In my test project I have a simple mainwindow onto which I have put my custom control and bound its ItemsSource.
<WpfControls:VtlDataNavigator x:Name="MyDataNavigator"
ItemsSource="{Binding ElementName=MainWindow, Path=Orders}" />
In the loaded event of the main window (which implements INotifyPropertyChanged) I instantiate the Orders collection. The customcontrols gets initialised before the main window loads but I can see from examining the Live Visual Tree in visual studio that once the main form loads the custom controls Items Source property is indeed set to Orders. Now of course I'd actually like to count the orders and have my custom control display that (it's a simple data navigator so what I'm after is the record count). I know how to get the count but how do I know when the itemsSource has changed so that I can react to it and get the count. There's no itemsSourceChanged event that I can see.
I've seen this blog article, but I'm wondering if there is a more straightforward approach to this as it seems such an obvious thing to want to know about.
You can do that using OverrideMetaData.
Try this:
public class Class1 : ItemsControl
{
static Class1()
{
ItemsSourceProperty.OverrideMetadata(typeof(Class1),
new FrameworkPropertyMetadata(null, OnItemSourceChanged));
}
private static void OnItemSourceChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
Debug.WriteLine("Why you haz Changed me!");
}
}
The ItemsSource is a DependencyProperty, and when creating DPs you can optionally specify a "property changed" event. Unfortunately ItemsSource is locked away in the base class, so I started wondering if there might be a way to add your own event to an existing DP. I came across this article that looks promising. Basically you would do something like this (untested so read the article!):-
var dpd = DependencyPropertyDescriptor.FromProperty(
VtlDataNavigator.ItemsSourceProperty,
typeof(VtlDataNavigator));
if (dpd != null)
{
dpd.AddValueChanged(
vtlDataNavigatorInstance,
delegate
{
var count = VtlDataNavigatorInstance.ItemsSource.Count; // Or whatever...
});
}
I got a Silverlight page opening a dialog. It is an administration page with some advanced logic talking to a database over a webservice. For the Silverlight client side, we use MVVM to its fullest. Opening the dialog the first time, everything works fine according to the implemented logic.
The problem: The second time opening the dialog, our data bound setters start receiving the wrong values.
Code:
How the dialog is created:
MyPopupViewModel myPopup = new MyPopupViewModel();
Caliburn.Micro.Execute.OnUIThread(() => WindowManager.ShowDialog(myPopup));
One of the bindings that eventually get the wrong values:
<ComboBox
ItemsSource="{Binding YesNoItems}"
SelectedValue="{Binding IsSynchronizing, Mode=TwoWay, Converter={StaticResource BooleanToYesNoConverter}}"
/>
What I have tried:
I put breakpoints in the setters. This is how I realized the logic is correct but that the setter is called with other values the second time it is opened.
I found the getters being called {1, 2, 1} times the {1st, 2nd, 3rd} time they are opened.
I made sure the dialog is initialized each time. Maybe Caliburn-micro caches the old one somehow, but it apparently does not cache it for long, as it works fine again the third time it is opened.
Solved it by adding the following decorator in the constructor of the dialog View, in the code-behind. I already had that decorator in the ViewModel, but the View apparently needed it too.
PartCreationPolicy(CreationPolicy.NonShared)]
A colleague helped me to find this out by breakpointing and then setting an ID for each instance. That way we proved there were several instances. Very practical. So the Views needed to be told to recreate each time instead of being reused.
The final code-behind looks like this:
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class MyPopupView
{
public MyPopupView()
{
InitializeComponent();
}
}
I've be struggling for a while trying to make it work. Basically I have a Silverlight application using MVVM/PRISM/Unity combination.
My shell consists by two Regions RootContent and RootMenu. My RegionManager.Regions are able to see those two regions just fine, and the application runs correctly.
The problem starts when one of my Views inside the RootContent opens a ChildWindow, it contains more two Regions, as follows:
<ContentControl Region:RegionManager.RegionName="WOFSCustomerLookup" />
<ContentControl Region:RegionManager.RegionName="WOFSCustomerView" />
The ViewModel of this View that has this XAML above, even inheriting and properly resolved, the IRegionManager.Regions collection do not contains those two new Regions above, just the RootContent and RootMenu.
More Information
This is How my ChildWindow is called (it calls the "View"):
ChildWindow editor = this.container.Resolve<WorkOrderFieldServiceEditor>();
editor.show();
And this is the Constructor of my ViewModel:
public WorkOrderFieldServiceViewModel(IUnityContainer container, IRegionManager regionManager)
{
this.container = container;
this.regionManager = regionManager;
// Still have just the two Root regions:
// this.regionManager.Regions[]
}
Did I miss anything?
Pretty sure the problem is because you are not showing the WorkOrderFieldServiceEditor view through Prism but are just getting an instance of it through the container and then calling Show method directly on it. So, Prism is not really involved. When the main Shell is created through the bootstrapper, the regions defined in the View are then created in the region manager. So, you will need to look at how you Navigate to a popup window using Prism and not call the Show method directly.
Checkout the RegionPopupBehaviors.cs file in the StockTrader reference application.
http://msdn.microsoft.com/en-us/library/ff921074(v=PandP.40).aspx
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.
I'm tryihg to bind a combobox item source to a static resource. I'm oversimplfying my example so that it's easy to understand what i'm doing.
So I have created a class
public class A : ObservableCollection<string>
{
public A()
{
IKBDomainContext Context = new IKBDomainContext();
Context.Load(Context.GetIBOptionsQuery("2C6C1Q"), p =>
{
foreach (var item in SkinContext.IKBOptions)
{
this.Add(item);
}
}, null);
}
}
So the class has a constructor that populates itself using a domaincontext that gets data from a persisted database. I'm only doing reads on this list so dont have to worry about persisting back.
in xaml i add a reference to the namespace of this class then I add it as a usercontrol.resources to the page control.
<UserControl.Resources>
<This:A x:Key="A"/>
</UserControl.Resources>
and then i use it this staticresource to bind it to my combobox items source.in reality i have to use a datatemplate to display this object properly but i wont add that here.
<Combobox ItemsSource="{StaticResource A}"/>
Now when I'm in the designer I get the error:
Cannot Create an Instance of "A".
If i compile and run the code, it runs just fine. This seems to only affect the editing of the xaml page.
What am I doing wrong?
When running in the designer the full application runtime is not available. However the designer doesn't just magically know how to mock the UI of a UserControl. Its Xaml is parsed and the objects described there are instantiated.
Its up to you to code your classes to cope with existence in a designer. You can use the static proeprty DesignerProperties.IsInDesignTool to determine if your code is currently being used in a designer tool or not.
If in a designer you could deliver a set of test data rather than attempt to access a data service.
My problem is same as described above and i alse used DesignerProperties.IsInDesignTool
but i can't open usercontrol in visual studio for designing purpose