UE4
Topic Author
Posts: 62
Joined: 29 Dec 2017, 06:32

A data binding question

08 Feb 2018, 09:46

Hi,
I have 2 UI(View): MyControl.Xaml, MainWindow.Xaml.
<!-- MyUserControl -->
<UserControl>
<Grid>
<Label  Content="{Binding  Title}">
</Grid>
</UserControl>
<!-- MainWindow -->
<UserControl>
<Grid>
<Label  Content="{Binding  MainWindowTitle}">
<local: MyUserControl <!-- How to binding its Title? -->>
</Grid>
</UserControl>
2 ViewModel: MyControlVM(has a string member: Title), MainWindowVM(has a string member: MainWindowTitle),
then how binding child View's DataContext? especially in UE4's blueprint
 
User avatar
hcpizzi
Site Admin
Posts: 185
Joined: 09 Feb 2012, 12:40

Re: A data binding question

08 Feb 2018, 19:28

Hi,

At the moment there's no way to set a DataContext for elements other than the root, via the SetDataContext function. This data context is inherited by all elements.

I was thinking about adding a SetDataContextForElement function to allow having different DataContexts in different elements of the tree, but it's still not implemented. I'll try to get it into the next code release. For now you can add MyControlVM as a property of MainWindowVM, and then change your xaml like this:

<local: MyUserControl DataContext="{Binding MyControlVM}">

I'll let you know once I've implemented SetDataContextForElement.
 
UE4
Topic Author
Posts: 62
Joined: 29 Dec 2017, 06:32

Re: A data binding question

09 Feb 2018, 05:14

Hi,

At the moment there's no way to set a DataContext for elements other than the root, via the SetDataContext function. This data context is inherited by all elements.

I was thinking about adding a SetDataContextForElement function to allow having different DataContexts in different elements of the tree, but it's still not implemented. I'll try to get it into the next code release. For now you can add MyControlVM as a property of MainWindowVM, and then change your xaml like this:

<local: MyUserControl DataContext="{Binding MyControlVM}">

I'll let you know once I've implemented SetDataContextForElement.
Thank you.
And I need to hold a ref of UNoesisInstance in ViewModel, then I can bind events to the UNoesisInstance's element, I don't how to do this for MyUserControl. The blueprint function FindName return a BaseComponent(UObject), but I need a NoesisInstance. Or some other class(BlueprintType) will do the same thing?
Maybe in C++, I could hold the View by MyUserControl* MyControlParam = FindName<MyUserControl>("ControlInstanceName"), and set the return value to MyUserControlVM.
 
User avatar
hcpizzi
Site Admin
Posts: 185
Joined: 09 Feb 2012, 12:40

Re: A data binding question

09 Feb 2018, 18:43

Hi,

I've committed a new version to GitHub. I've added a new function called TrySetDataContext. You can use it in combination with FindName. You use FindName to get the element you want, then TrySetDataContext to set the data context. The Try in the name is because it takes an UObject as both parameters, but only works if the Element parameter is indeed a Noesis FrameworkElement.

Please, let us know if this solves your problem.
 
User avatar
sfernandez
Site Admin
Posts: 1353
Joined: 22 Dec 2011, 19:20

Re: A data binding question

09 Feb 2018, 20:50

Another option is to provide MyControlVM as nested data of the parent MainWindowVM. That is, you store MyControlVM in a public property ("Content" for example) of the MainWindowVM. Then you can bind MyUserControl DataContext to that property:
<!-- MainWindow -->
  <UserControl>
    <Grid>
      <Label Content="{Binding  MainWindowTitle}">
      <local:MyUserControl DataContext="{Binding Content}"/>
    </Grid>
</UserControl>
 
UE4
Topic Author
Posts: 62
Joined: 29 Dec 2017, 06:32

Re: A data binding question

11 Feb 2018, 03:05

Hi
2 methods all works

Is there some way could help me hold a View's ref in ViewModel? the C++ code may do it, but not flexible
void UMainWindowViewModel::InitialzieDataBinding()
{
        //MainWindow can hold a ref to UNoesisInstance(NGUI) easily
	if (VirtualJoystickVM && NGUI && NGUI->Xaml)
	{
		VirtualJoystick* VJoystick = NGUI->Xaml->FindName<VirtualJoystick>(TCHAR_TO_UTF8( *JoystickControlName));
		if (VJoystick)
		{
		        //Let child hold View's ref
			VirtualJoystickVM->SetViewRaw(VJoystick);
		}
	}

	if (TouchButtonVM && NGUI && NGUI->Xaml)
	{
		GameGUI::TouchButton* TouchBtn = NGUI->Xaml->FindName < GameGUI::TouchButton > (TCHAR_TO_UTF8(*TouchButtonName));
		if (TouchBtn)
		{
			TouchButtonVM->SetViewRaw(TouchBtn);
		}

		TouchButtonVM->OnDragStarted.AddDynamic(this, &UMainWindowViewModel::ProcessTouchButtonEvent);
	}
}
for ItemsControl, I don't have a right way to set a ref to View automatically
<ItemsControl ItemsSource="{Binding TouchButtonVMList}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" <!-- Orientation doesn't work -->>
                        <local:TouchButton >

                        </local:TouchButton>

                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
 
User avatar
hcpizzi
Site Admin
Posts: 185
Joined: 09 Feb 2012, 12:40

Re: A data binding question

12 Feb 2018, 17:45

Yous still have to use C++ for the VM, but what you can do is use FindName in the Blueprint, and have a native function in your VM class that takes an UObject*. In that function you can retrieve the Noesis component, like this:
void VirtualJoystickVM::SetView(UObject* WrappedView)
{
	Noesis::Ptr<Noesis::BaseComponent> Component = NoesisCreateComponentForUObject(WrappedView);
	if (Component)
	{
		VirtualJoystick* VJoystick = NsDynamicCast<VirtualJoystick*>(Component.GetPtr());
		if (VJoystick)
		{
			SetViewRaw(VJoystick);
		}
	}
}
Is this what you had in mind?
 
User avatar
sfernandez
Site Admin
Posts: 1353
Joined: 22 Dec 2011, 19:20

Re: A data binding question

13 Feb 2018, 16:48

<ItemsControl ItemsSource="{Binding TouchButtonVMList}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <StackPanel Orientation="Horizontal" <!-- Orientation doesn't work -->>
        <local:TouchButton />
      </StackPanel>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>
About this code, ItemTemplate property defines the appearance of a single item only.
If you want to manage the layout of items in an ItemsControl, you should use the ItemsPanel property:
<ItemsControl ItemsSource="{Binding TouchButtonVMList}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <StackPanel Orientation="Horizontal"/>
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <local:TouchButton />
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>
 
Wanderer
Posts: 153
Joined: 08 May 2017, 18:36

Re: A data binding question

14 Feb 2018, 10:18

Maybe late, but try this:
<!-- MainWindow -->
<UserControl>
<Grid>
<Label x:Name="TitleElement"  Content="{Binding MainWindowTitle}">
</Grid>
</UserControl>
<!-- MyUserControl -->
<UserControl>
<Grid>
<Label  Content="{Binding ElementName=TitleElement, Path=Content}">
</Grid>
</UserControl>
if your dataContext is some xaml file, then try this, similar is working on my side (but instead UserControl I use grid).
<!-- MyUserControl -->
<UserControl>
<Grid>
<Label  Content="{Binding ElementName=TitleElement, Path=DataContext.NameOfDataContext[MainWindowTitle]}"> // It depends which element you add DataContext. In this case I think you add DataContext in to label named TitleElement
</Grid>
</UserControl>
Btw. I think your labels missing "/" sign.
<Label x:Name="TitleElement"  Content="{Binding MainWindowTitle}" />
 
UE4
Topic Author
Posts: 62
Joined: 29 Dec 2017, 06:32

Re: A data binding question

14 Feb 2018, 15:34

so, I have to call SetView everytime add/remove a array element in DataContext?
the child elements is defined in a template, and initialized at runtime, I don't its name, the FindName may be helpless?

Who is online

Users browsing this forum: JasonL663 and 13 guests