Show a xaml from within a ContentControl element?
Hiya! I'm trying to show a xaml from within a ContentControl element so that I can dynamically switch between different xamls from within a root xaml navigation menu. What's the best way to accomplish this?
This is my code so far:
m_pCurrentScreen is set in code like this:
The navigation xaml sets the binding like:
But when I view this navigation menu in-game, all I see is a text of the viewmodel's name, not the actual view itself. What am I missing?
This is my code so far:
Code: Select all
static constexpr LPCSTR REFLECT_SCREEN_CONTENT = "Screen_Content";
NS_IMPLEMENT_REFLECTION(NavigationViewModel, "Global_Navigation_ViewModel")
{
NsProp(REFLECT_SCREEN_CONTENT, &NavigationViewModel::GetCurrentScreen);
}
const Noesis::BaseComponent* NavigationViewModel::GetCurrentScreen() const
{
return m_pCurrentScreen;
}
void NavigationViewModel::SetCurrentScreen(
Noesis::BaseComponent* pNewScreen)
{
if (m_pCurrentScreen != pNewScreen)
{
m_pCurrentScreen = Noesis::WrapPtr(pNewScreen);
OnPropertyChanged(REFLECT_SCREEN_CONTENT);
}
}
Code: Select all
const Noesis::Ptr<Noesis::BaseComponent> pNewScreenViewModel = Noesis::MakePtr<SubMenuViewModel>();
Noesis::Ptr<Noesis::FrameworkElement> uiScreen = Noesis::GUI::LoadXaml<Noesis::FrameworkElement>(screenPath);
uiScreen->SetDataContext(pNewScreenViewModel);
SetCurrentScreen(pNewScreenViewModel);Code: Select all
<ContentControl x:Name="ContentControl_DynamicContent" Content="{Binding Path=Screen_Content}">-
-
sfernandez
Site Admin
- Posts: 3363
- Joined:
Re: Show a xaml from within a ContentControl element?
Hello,
If you expose in your ViewModel a property for the content of the ContentControl and use different default DataTemplates for each of the types of content, it will automatically populate the ContentControl with the corresponding template:
Is this what you are looking for?
If you expose in your ViewModel a property for the content of the ContentControl and use different default DataTemplates for each of the types of content, it will automatically populate the ContentControl with the corresponding template:
Code: Select all
struct SomeData: public BaseComponent
{
String name;
NS_IMPLEMENT_INLINE_REFLECTION(SomeData, BaseComponent, "Tests.SomeData")
{
NsProp("Name", &SomeData::name);
}
};
Code: Select all
struct ViewModel: public BaseComponent, public INotifyPropertyChanged
{
PropertyChangedEventHandler changed;
PropertyChangedEventHandler& PropertyChanged() { return changed; }
Ptr<BaseComponent> screenContent;
BaseComponent* GetScreenContent() const { return screenContent; }
void SetScreenContent(BaseComponent* value)
{
if (screenContent != value)
{
screenContent.Reset(value);
changed(this, PropertyChangedEventArgs(Symbol("ScreenContent"));
}
}
NS_IMPLEMENT_INLINE_REFLECTION(ViewModel, BaseComponent)
{
NsProp("ScreenContent", &ViewModel::GetScreenContent, &ViewModel::SetScreenContent);
}
};
Code: Select all
<Grid>
<Grid.Resources>
<DataTemplate DataType="{x:Type local:SomeData}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</Grid.Resources>
<ContentControl Content="{Binding Path=ScreenContent}">
</Grid>
Re: Show a xaml from within a ContentControl element?
It looks like what you're suggesting is to change data for bespoke elements that are pre-existing on the root xaml, However, what I want to accomplish is for my root xaml to load another xaml dynamically and attach it as a child to a parent element in my root xaml. Could that be done with a ContentControl, or is there another way to accomplish this? It'd look like this:
MENU A
EMPTY ROOT
MENU A
- Root A
- Button 1
- Button 2
- Root B
- Text B
EMPTY ROOT
- Root
- Text Root
- ContentControl
- Root
- Text Root
- ContentControl
- Root A
- Button 1
- Button 2
- Root A
- Root
- Text Root
- ContentControl
- Root B
- Text B
- Root B
Re: Show a xaml from within a ContentControl element?
You can certainly load xaml into a view model property and then show it using a ContentControl, we've done similar menu setup, but I can't quite spot where it might not be working for you, I only know the setup for an Unreal project. Hopefully someone can spot the issue.
Re: Show a xaml from within a ContentControl element?
It looks like your binding is resolving to the actual view model. If you don't define a DataTemplate for that view model type, only its name will be shown.
Presumably, that view model has some property that contains the actual UI you want to display.
You should define a DataTemplate to extract and show that UI:
You can replace the inner ContentControl with a ContentPresenter, but you need to be careful since setting ContentPresenter.Content also sets ContentPresenter.DataContext, so you may need to wrap it inside a Border or similar and use ElementName or RelativeSource.
You could instead just bind to that property directly in the main ContentControl:
If the UIProperty is a DataTemplate instead of a visual element, you should set ContentTemplate instead of Content:
Presumably, that view model has some property that contains the actual UI you want to display.
You should define a DataTemplate to extract and show that UI:
Code: Select all
<DataTemplate TargetType="{x:Type SubMenuViewModel}">
<ContentControl Content="{Binding UiProperty}"/>
</DataTemplate>
You could instead just bind to that property directly in the main ContentControl:
Code: Select all
<ContentControl x:Name="ContentControl_DynamicContent" Content="{Binding Screen_Content.UiProperty}"/>
Code: Select all
<DataTemplate TargetType="{x:Type SubMenuViewModel}">
<ContentControl Content="{Binding}" ContentTemplate="{Binding UiProperty}"/>
</DataTemplate>
Re: Show a xaml from within a ContentControl element?
In Noesis (just like WPF), a ContentControl does not automatically display a loaded XAML view unless one of these is true:
The Content is a visual element (FrameworkElement), or
There is a DataTemplate that maps the ViewModel type → the view to display.
The Content is a visual element (FrameworkElement), or
There is a DataTemplate that maps the ViewModel type → the view to display.
-
-
sfernandez
Site Admin
- Posts: 3363
- Joined:
Re: Show a xaml from within a ContentControl element?
The DataTemplates that describe how to represent each data type could be defined in different ResourceDictionary files, and merged into the Application Resources. No need to define those resources in your root xaml. This is the recommended approach when working in a MVVM scenario.t looks like what you're suggesting is to change data for bespoke elements that are pre-existing on the root xaml, However, what I want to accomplish is for my root xaml to load another xaml dynamically and attach it as a child to a parent element in my root xaml. Could that be done with a ContentControl, or is there another way to accomplish this?
If you want to explicitly load other pages into a ContentControl you can use the LoadContentAction in response to any trigger (for example clicking on a button).
And the last option, as you already mentioned is to manually load other xamls using Noesis::GUI::LoadXaml, and set the loaded tree as the Content of your ContentControl:
Code: Select all
Noesis::Ptr<Noesis::FrameworkElement> uiScreen = Noesis::GUI::LoadXaml<Noesis::FrameworkElement>(screenPath);
uiScreen->SetDataContext(pNewScreenViewModel);
SetScreenContent(uiScreen); // assuming this sets the "Screen_Content" property bound to the ContentControl.ContentWho is online
Users browsing this forum: No registered users and 6 guests