Page 3 of 5

Re: A few questions about some features

Posted: 23 Feb 2015, 17:21
by sfernandez
How do you accessed the property? Do you mean in the XAML or by code?

Re: A few questions about some features

Posted: 23 Feb 2015, 17:44
by ZanAlex
In the Xaml file, something like:
< [CustomControl] Orientation="Vertical" />
when Orientation is not a property of the control.

Re: A few questions about some features

Posted: 24 Feb 2015, 16:59
by jsantos
Right now, if you preprocess that XAML with the BuildTool you will get a warning indicating that the property cannot be found in your type.

Yes, XamlPlayer should have a small console showing this kind of logs. Thanks also for this suggestion.

Re: A few questions about some features

Posted: 25 Feb 2015, 14:46
by ZanAlex
Hi,

I have a question about memory management in general. I'm spawning controls with their data context in my application code and I'm wondering who "owns" these things once passed to Noesis. Will the framework delete these entities or should I take care of these myself? What is the best practice for this kind of use?

I also have a problem with my custom drop down menu.
The first one is related to Xaml itself I think. I would like the Popup state (open/close) synchronized with a ToggleButton. In addition to that, I'd like the Popup to close when clicking outside. To do so, I've made a property IsMenuOpen in my CustomControl (derived from ContentControl) and bound the Popup's IsOpen and ToggleButton's IsChecked to it. It works as expected. Anyway, to get the second behaviour, I've set Popup's StaysOpen to false. The problem is that the ToggleButton stays toggled when the menu is closed that way. I've done some tests and apparently the Popup does not update the property when closed.

My second problem is a bit more mysterious. As I said, I'm trying to spawn controls from my application code. One of my goals is to fill a StackPanel with a custom control containing a custom drop down menu. But as soon as I try to add one in the Panel (using UIElementCollection::Add), the application crashes. Here are some code snippets:

test.xaml, loaded by the application:
<Border
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  HorizontalAlignment="Center" VerticalAlignment="Center"
  x:Name="PART_BorderTest"
  UseLayoutRounding="True">
	
	<FilterBar x:Name="PART_FilterBar" />
	
</Border>
filterBar.xaml
<FilterBar
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="FilterBar" x:Name="FilterBar"
  UseLayoutRounding="True">

	<StackPanel x:Name="PART_CategoryPanel" Orientation="Horizontal" />
	
</FilterBar>
filterCategory.xaml
<FilterCategory
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="FilterCategory" x:Name="FilterCategory"
  UseLayoutRounding="True">
	
	<FilterCategory.Resources>
		<ControlTemplate x:Key="MenuAnchorTemplate" TargetType="{x:Type MenuAnchor}">
			<StackPanel Orientation="Vertical">
				<StackPanel Orientation="Horizontal">
					<ContentPresenter x:Name="PART_HeaderContent"
					  Content="{Binding HeaderContent, RelativeSource={RelativeSource TemplatedParent}}"/>
					<ToggleButton IsChecked="{Binding IsMenuOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"/>
				</StackPanel>
				<Popup x:Name="PART_Popup"
				  IsOpen="{Binding IsMenuOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
				  Focusable="False"
				  PlacementTarget="{Binding ElementName=PART_HeaderContent}"
				  Placement="Bottom"
				  PopupAnimation="Slide"
				  VerticalOffset="1"
				  AllowsTransparency="True"
				  StaysOpen="True">
					<ContentPresenter/>
				</Popup>
			</StackPanel>
		</ControlTemplate>
		<Style TargetType="{x:Type MenuAnchor}">
			<Setter Property="Template" Value="{StaticResource MenuAnchorTemplate}"/>
		</Style>
	</FilterCategory.Resources>
	
	<MenuAnchor>
		<MenuAnchor.HeaderContent>
			<StackPanel Orientation="Horizontal">
				<CheckBox/>
				<TextBlock Text="{Binding CategoryID, Mode=TwoWay, StringFormat=F2}" />
			</StackPanel>
		</MenuAnchor.HeaderContent>
		
		<StackPanel x:Name="PART_FilterPanel" Orientation="Vertical"/>
	</MenuAnchor>
	
</FilterCategory>
Note that I've encountered both problems using that ControlTemplate for MenuAnchor (the custom drop down menu) shown in filterCategory.xaml.

Add function
Noesis::Gui::UIElementCollection* pCol = _filtersCategoriesPanel->GetChildren();
if (pCol != nullptr)
{
    pCol->Add(pNewCategory);
}
This piece of code is run right after the test.xaml is loaded in the application.

Thanks a lot!

Re: A few questions about some features

Posted: 02 Mar 2015, 18:01
by sfernandez
Hi,
I have a question about memory management in general. I'm spawning controls with their data context in my application code and I'm wondering who "owns" these things once passed to Noesis. Will the framework delete these entities or should I take care of these myself? What is the best practice for this kind of use?
NoesisGUI UI elements take ownership of the objects you set in them. For example, when setting the ContentControl.Content property, the control keeps a reference to its content, so it isn't destroyed while it is being used. The same occurs for a brush set as Control.Background, etc.
void SetText(ContentControl* control, const NsChar* text)
{
  Ptr<TextBlock> tb = *new TextBlock(text); // Ptr keeps a reference to the new TextBlock (1 ref)
  Ptr<Brush> fg = *new SolidColorBrush(Colors::Red()); // Ptr keeps a reference to the new Brush (1 ref)
  tb->SetForeground(fg.GetPtr()); // TextBlock grabs a reference to the Brush (2 refs now)
  control->SetContent(tb.GetPtr()); // ContentControl grabs a reference to the TextBlock (2 refs now)
}
// Ptrs are out of scope and destroyed, releasing their references. TextBlock and Brush with 1 ref now       
I also have a problem with my custom drop down menu...
I'll take a look at these two problems and let you know when find something.

Re: A few questions about some features

Posted: 03 Mar 2015, 11:56
by ZanAlex
Alright, thank you very much! :)

While you're having a look at my previous problems, I'm trying to use a member of my data context to interrogate a ResourceDictionary.

After some research, I've found that a way to achieve this is to use a converter to turn the argument (in my case an int) into an ImageSource, contained by the ResourceDictionary passed as parameter.

But apparently, the problem comes from line 25: ResDiscs is not found. However, I manage to get the converter and the data model elsewhere in the code.

My Xaml code:
 <UserControl
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="InventoryTile" x:Name="ROOT_InventoryTile">
  
	<UserControl.Resources>
		<ResourceDictionary x:Key="ResDics">
			<ResourceDictionary.MergedDictionaries>
				<ResourceDictionary x:Key="ResDics" Source="itemIcons.xaml"/>
			</ResourceDictionary.MergedDictionaries>
		</ResourceDictionary>
	
		<ResourceArgConverter x:Key="ResArgConverter"/>
		<InventoryTileModel x:Key="dataModel" ItemID="1" Quantity="42"/>
    </UserControl.Resources>
	
    <Border DataContext="{StaticResource dataModel}"
      BorderBrush="Gray" BorderThickness="1">
        <StackPanel
          HorizontalAlignment="Center" VerticalAlignment="Center"
          Orientation="Vertical">
          
            <Image Source="{Binding ItemID, 
							Converter={StaticResource ResArgConverter}, 
							ConverterParameter={StaticResource ResDics}}"
			  Height="60" Width="60"/>
			<TextBlock
              HorizontalAlignment="Center"
              Text="{Binding Quantity}" />
            
        </StackPanel>
    </Border>
 
 </UserControl>
My converter code:
NsBool TryConvert(Noesis::Core::BaseComponent* value, 
                 const Noesis::Core::Type* targetType,
                 Noesis::Core::BaseComponent* parameter, 
                 Noesis::Core::Ptr<Noesis::Core::BaseComponent>& result)
{
    Noesis::Core::BaseComponent* pResult = nullptr;
    if (nullptr != value)
    {
        Noesis::Gui::ResourceDictionary* pParam = Noesis::Core::Boxing::Unbox<Noesis::Gui::ResourceDictionary*>(parameter);

        NsInt32 intKey = Noesis::Core::Boxing::Unbox<NsInt32>(value);

        std::string strKey = std::to_string(intKey);
        const NsChar* charKey = strKey.c_str();

        Noesis::Core::Ptr<Noesis::Gui::ResourceKeyString> pResKeyStr = Noesis::Gui::ResourceKeyString::TryCreate(charKey);
        if (nullptr != pParam && 0 != pResKeyStr)
        {
            pResult = pParam->TryGet(pResKeyStr);
            if (nullptr != pResult)
            {
                result.Reset(pResult);
            }
        }
    }

    return nullptr != pResult;
}
Can you think of a better way to achieve it?
Do you have an idea of what I might be missing?
Thank you again.

Re: A few questions about some features

Posted: 03 Mar 2015, 17:52
by sfernandez
I see one thing wrong in your converter code. Objects deriving from BaseComponent are not boxed, so you don't need to call Unbox over them, just perform the desired cast:
NsBool TryConvert(Noesis::Core::BaseComponent* value, 
  const Noesis::Core::Type* targetType,
  Noesis::Core::BaseComponent* parameter, 
  Noesis::Core::Ptr<Noesis::Core::BaseComponent>& result)
{
  Noesis::Core::BaseComponent* pResult = nullptr;
  if (nullptr != value)
  {
    // if you are sure of the parameter type use NsStaticCast, if you don't know call NsDynamicCast
    // and check for null
    Noesis::Gui::ResourceDictionary* pParam = NsStaticCast<Noesis::Gui::ResourceDictionary*>(parameter);

    // you can use ToString to get a string representation of a boxed value
    Noesis::Core::Ptr<Noesis::Gui::ResourceKeyString> pResKeyStr =
      Noesis::Gui::ResourceKeyString::TryCreate(value->ToString().c_str());

    if (nullptr != pParam && 0 != pResKeyStr && pParam->Find(pResKeyStr.GetPtr(), pResult))
    {
      result.Reset(pResult);
      return true;
    }
  }

  result.Reset();
  return false;
}
Let me know if it works this way.

Re: A few questions about some features

Posted: 03 Mar 2015, 18:06
by ZanAlex
Oh, that's a good thing to know, thank you. But I cannot even specify the ResourceDictionary as the parameter of the converter. I have an error at that line, telling me that the resource cannot be found.

I've tried to turn the integer into a ResourceKeyString but I did not have much more success that way.

Am I tackling the problem correctly?

Re: A few questions about some features

Posted: 03 Mar 2015, 18:24
by sfernandez
Maybe it is setting the 'ResDics' in the Resources property, but it should show an error of setting the property multiple times. We will improve error checking if no message is shown.

Please try the following in your xaml:
<UserControl
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="InventoryTile" x:Name="ROOT_InventoryTile">
  
   <UserControl.Resources>
      <ResourceDictionary>
         <ResourceDictionary x:Key="ResDics" Source="itemIcons.xaml"/>
         <ResourceArgConverter x:Key="ResArgConverter"/>
         <InventoryTileModel x:Key="dataModel" ItemID="1" Quantity="42"/>
       </ResourceDictionary>
    </UserControl.Resources>
   
    <!-- ... -->

</UserControl> 

Re: A few questions about some features

Posted: 03 Mar 2015, 18:52
by ZanAlex
It's working great, thank you so much! :)

Actually, it works in the XamlPlayer, but as soon as I try to integrate it in my application, bad things happens.

Here's my minimal file:
<Border
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Name="Root"
  BorderBrush="White" BorderThickness="1"
  HorizontalAlignment="Center" VerticalAlignment="Center">
    
    <!--<Border.Resources>
        <ResourceDictionary>
            <InventoryTileModel x:Key="model" ItemID="0" Quantity="10" />
        </ResourceDictionary>
    </Border.Resources>-->

    <Image
      Source="./assets/woodicon.png"
      Height="60" Width="60" />
	  
</Border>
As soon as I uncomment the Border resources, I get that error:
File Core\Kernel\Src\Memory.cpp (l. 130): Not enough memory! (malloc(15627680408))
Here is the code of my data model but that's a really standard thing and I don't think the problem originate from there:
class InventoryTileModel : public Noesis::Core::BaseComponent
{
public:
    InventoryTileModel()
        : _itemID(-1)
        , _quantity(-1)
    {}
    InventoryTileModel(int inID, int inQuantity) 
        : _itemID(inID)
        , _quantity(inQuantity)
    {}
    ~InventoryTileModel() {}

    int GetItemID() const { return _itemID; }
    void SetItemID(int inID) { _itemID = inID; }

    int GetQuantity() const { return _quantity; }
    void SetQuantity(int inQuantity) { _quantity = inQuantity; }

    /** BaseComponent interface **/
    void Serialize(Noesis::Core::SerializationData* data) const;
    void Unserialize(Noesis::Core::UnserializationData* data, NsUInt32 version);
    /**/

private:
    int _itemID;
    int _quantity;

    NS_IMPLEMENT_INLINE_REFLECTION(InventoryTileModel, Noesis::Core::BaseComponent)
    {
        NsMeta<Noesis::Core::TypeId>("InventoryTileModel");
        NsProp("ItemID", &InventoryTileModel::GetItemID, &InventoryTileModel::SetItemID);
        NsProp("Quantity", &InventoryTileModel::GetQuantity, &InventoryTileModel::SetQuantity);
    }
};
The weird thing is that everything is working in the XamlPlayer. Do you have a lead on what might be wrong with that? Thank you.

EDIT: I manage to skip the problem by setting the DataContext in the application rather than in the Xaml, but I'd like to make sure I can trust the XamlPlayer at 100% in the future. Knowing what I've done wrong is still very valuable to me.