- ExtZGholson
- Posts: 22
- Joined:
Passing Rectangle via converter
Hello,
I am currently trying to pass a Rectangle in to a convert so that I can return a Rect for a Viewbox. Unfortuantely, I am missing something simple when trying to either cast or Unbox the BaseComponent*.
When attempting to unbox the Rectangle I get the follow error:
Here is the code in the converter:
I am currently trying to pass a Rectangle in to a convert so that I can return a Rect for a Viewbox. Unfortuantely, I am missing something simple when trying to either cast or Unbox the BaseComponent*.
When attempting to unbox the Rectangle I get the follow error:
What may I be doing wrong here?'Project.UI.Converters.ElementPositionSizeConverter' binding converter failed to convert value 'Rectangle' (type 'Rectangle')'Project.UI.Converters.ElementPositionSizeConverter' binding converter failed to convert value 'Rectangle' (type 'Rectangle')
Here is the code in the converter:
Code: Select all
bool ElementPositionSizeConverter::TryConvert(Noesis::BaseComponent* value, const Noesis::Type* /*targetType*/, Noesis::BaseComponent* /*parameter*/, Noesis::Ptr<Noesis::BaseComponent>& result)
{
if (Noesis::Boxing::CanUnbox<Noesis::Rectangle*>(value))
{
const Noesis::Rectangle* myRectangle = Noesis::Boxing::Unbox<Noesis::Rectangle*>(value);
if (myRectangle)
{
Noesis::Size contentSize = Noesis::Size(myRectangle->GetActualWidth(), myRectangle->GetActualHeight());
const Noesis::Point contentPosition = (myRectangle->PointToScreen(Noesis::Point(0, 0)));
result.Reset(Noesis::Boxing::Box(Noesis::Rect(contentPosition, contentSize)));
return true;
}
}
return false;
}
-
sfernandez
Site Admin
- Posts: 2984
- Joined:
Re: Passing Rectangle via converter
Hi, if I understand correctly you are binding to a Rectangle element, something like this:
In that case the value received in the converter will be the reference to the Rectangle element, so you can cast like this:
Only basic types (bool, int, float, ...) and non-ref counted classes (String, Size, Point, Rect, Thickness....) are boxed and should use Unbox to obtain the value. For reference count objects you should use casting, static or dynamic, depending if you know the type or no.
Have you already tried that?
Code: Select all
<Rectangle x:Name="rect" Width="200" Heigth="100">
<Rectangle.Fill>
<ImageBrush Viewbox="{Binding ElementName=rect, Converter={StaticResource ElementPositionSizeConverter}}"/>
</Rectangle.Fill>
</Rectangle>
Code: Select all
bool ElementPositionSizeConverter::TryConvert(Noesis::BaseComponent* value, const Noesis::Type* /*targetType*/, Noesis::BaseComponent* /*parameter*/, Noesis::Ptr<Noesis::BaseComponent>& result)
{
Rectangle* rect = DynamicCast<Rectangle*>(value);
if (rect != nullptr)
{
//...
}
}
Have you already tried that?
- ExtZGholson
- Posts: 22
- Joined:
Re: Passing Rectangle via converter
I haven't. I tried something close but we thinking it would be a Noesis Rectangle. I will give this a try!
Thank you very much!
Thank you very much!
- ExtZGholson
- Posts: 22
- Joined:
Re: Passing Rectangle via converter
When using a Noesis::Rectangle* with the dynamic cast, we get the following Errors:
The properties of the rectangle don't seem to be initialized or assigned.
Code: Select all
ERROR| [Noesis] Visual is not connected to a ViewVisual is not connected to a View
000000.621| ERROR| [Noesis] Visual is not connected to a ViewVisual is not connected to a View
000000.622| ERROR| [Noesis] Visual is not connected to a ViewVisual is not connected to a View
000000.625| ERROR| [Noesis] Visual is not connected to a ViewVisual is not connected to a View
000015.485| ERROR| Run failed: Error emitted [Noesis] Visual is not connected to a View
-
sfernandez
Site Admin
- Posts: 2984
- Joined:
Re: Passing Rectangle via converter
Those error messages are raised when calling PointToScreen() on the Rectangle if it is not part of the UI tree (not connected to the View).
You can use rectangle->IsConnectedToView() before calling PointToScreen() to avoid them:
You can use rectangle->IsConnectedToView() before calling PointToScreen() to avoid them:
Code: Select all
bool ElementPositionSizeConverter::TryConvert(Noesis::BaseComponent* value, const Noesis::Type* /*targetType*/, Noesis::BaseComponent* /*parameter*/, Noesis::Ptr<Noesis::BaseComponent>& result)
{
Noesis::Rectangle* myRectangle = Noesis::DynamicCast<Noesis::Rectangle*>(value);
if (myRectangle && myRectangle->IsConnectedToView())
{
Noesis::Size contentSize = Noesis::Size(myRectangle->GetActualWidth(), myRectangle->GetActualHeight());
const Noesis::Point contentPosition = (myRectangle->PointToScreen(Noesis::Point(0, 0)));
result.Reset(Noesis::Boxing::Box(Noesis::Rect(contentPosition, contentSize)));
return true;
}
return false;
}
- ExtZGholson
- Posts: 22
- Joined:
Re: Passing Rectangle via converter
Thank you this is certainly helpful.
I know this sounds like a silly question, but how would I go about connecting this Rectangle to the view?
The structure exists as the following.
Main Window -> Viewbox -> Noesis::ContentControl (loads User Control XAML via set source NsPRop) -> Grid -> Rectangle -> Button -> Grid -> Rectangle(Target Rectangle) -> Visual Brush (Contains Converter)
I know this sounds like a silly question, but how would I go about connecting this Rectangle to the view?
The structure exists as the following.
Main Window -> Viewbox -> Noesis::ContentControl (loads User Control XAML via set source NsPRop) -> Grid -> Rectangle -> Button -> Grid -> Rectangle(Target Rectangle) -> Visual Brush (Contains Converter)
-
sfernandez
Site Admin
- Posts: 2984
- Joined:
Re: Passing Rectangle via converter
Elements are connected to the View when they raise the Loaded event. Instead of binding directly to the rectangle, you can bind to a property that gets updated with the Rectangle when it gets loaded:
Code: Select all
<Grid x:Name="target">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<ei:ChangePropertyAction PropertyName="Tag" Value="{Binding ElementName=rect}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Rectangle x:Name="rect" Width="200" Height="100">
<Rectangle.Fill>
<ImageBrush Viewbox="{Binding Tag, ElementName=target, Converter={StaticResource ElementPositionSizeConverter}}"/>
</Rectangle.Fill>
</Rectangle>
</Grid>
- ExtZGholson
- Posts: 22
- Joined:
Re: Passing Rectangle via converter
Thank you, I am now able to read the properties on the Rectangle for my converter! I just need to tweak some values on my end and I am all clear. I appreciate your time and assistance.
- ExtZGholson
- Posts: 22
- Joined:
Re: Passing Rectangle via converter
As we are reading the values for the rectangles that we passed in, we noticed that we are getting inconsistent values when calling `contentPosition = myRectangle->PointToScreen(Noesis::Point(0, 0));`. The values we are expecting in one case are (93,216). However, one one machine we are getting (85.308, 136.199), while the other machine is closer but not accurate.
Is there some other way of determining the position for an element on screen?
Thank you,
Zane
Is there some other way of determining the position for an element on screen?
Thank you,
Zane
- ExtZGholson
- Posts: 22
- Joined:
Re: Passing Rectangle via converter
We ended up walking up the visual tree and examining the values of the offsets of the elements as went. Based on this, we discovered that we could pick a target parent by name (Noesis::String), get the TransformToAncestor and then calculate a position from the transformation matrix.
Code: Select all
bool ElementPositionSizeConverter::TryConvert(Noesis::BaseComponent* value, const Noesis::Type* /*targetType*/, Noesis::BaseComponent* parameter, Noesis::Ptr<Noesis::BaseComponent>& result)
{
const Noesis::String targetName = Noesis::Boxing::CanUnbox<Noesis::String>(parameter) ? Noesis::Boxing::Unbox<Noesis::String>(parameter) : Noesis::String("NameNotFound");
const Noesis::Rectangle* myRectangle = DynamicCast<Noesis::Rectangle*>(value);
if (myRectangle && myRectangle->IsConnectedToView())
{
Noesis::FrameworkElement* rootElement = myRectangle->GetParent();
while (rootElement->GetParent() != nullptr)
{
if (strcmp(rootElement->GetName(), targetName.Str()) == 0)
{
break;
}
rootElement = rootElement->GetParent();
}
const Noesis::Size contentSize = Noesis::Size(myRectangle->GetActualWidth(), myRectangle->GetActualHeight());
const Noesis::Matrix4 theMatrix = myRectangle->TransformToAncestor(rootElement);
const Noesis::Vector4 myTransform = Noesis::Vector4(0, 0, 0, 1.0f) * theMatrix;
const Noesis::Point contentPosition = Noesis::Point(myTransform.x / myTransform.w, myTransform.y / myTransform.w);
result.Reset(Noesis::Boxing::Box(Noesis::Rect(contentPosition, contentSize)));
return true;
}
//Return true always to prevent log spam. Is there a better way of doing this?
result.Reset(Noesis::Boxing::Box(Noesis::Rect(Noesis::Point(), Noesis::Size())));
return true;
}
Who is online
Users browsing this forum: Ahrefs [Bot] and 65 guests