GithubHelp home page GithubHelp logo

Comments (9)

Sally-Xu avatar Sally-Xu commented on September 17, 2024

I think I find out the problem for this bug:
createObject(el, ctx) {
....
xnode.DocNameScope = ctx.NameScope; // assign DocNameScope for the object
...
}

The ctx (so is the DocNameScope) is different depending how the object is created. In my case, the HyperlinkButton is inside of a HierarchicalDataTemplate, the ctx is created at FrameworkTemplate.prototype.GetVisualTree function.

FrameworkTemplate.prototype.GetVisualTree = function (bindingSource) {
var ctx = {
Document: this.TemplateElement.ownerDocument,
ResourceChain: this.ResourceChain,
NameScope: new Fayde.NameScope(true),
ObjectStack: [],
TemplateBindingSource: bindingSource,
};
}

The ctx for the Frame object is created in the Load function:
function Load(doc) {
var ctx = {
Document: doc,
ResourceChain: [],
NameScope: new Fayde.NameScope(true),
ObjectStack: [],
TemplateBindingSource: null,
name: "doc"
};
So the HyperlinkButton has a different DocNameScope from the one that Frame's name is registered. That's why FindName function could not find the Frame. Shouldn't be only one DocNameScope instance for all controls in the page?

from fayde.

BSick7 avatar BSick7 commented on September 17, 2024

Every "Document" created in Fayde will have its own namescope. I will do my best to reduce a complex scenario into a simple system.

Namescopes are a way of isolating xaml so that nodes marked with x:Name can be referenced elsewhere. Each xaml document should have its own ecosystem of names so that if they were included in the same xaml application, they would not collide with each other. Templates also create new namescopes so that collisions do not happen as you could instantiate the template within the same document. This becomes glaringly obvious when you have a data template for a ListBox. That template is created for every item in your ListBox.

There may be a situation worth investigating. If a block of xaml is to be instantiated within a template, yet resides within the flow of a xaml document, the block should belong to the document's namescope. In the following example, InnerPanel will be created within the control template defined for Button. However, since InnerPanel is in the flow of the xaml document, SomeImage.Tag should resolve to MyButton.

<Button x:Name="MyButton">
    <StackPanel x:Name="InnerPanel">
        <Image x:Name="SomeImage" Tag="{Binding ElementName=MyButton}" />
        <TextBlock Text="OK" />
    </StackPanel>
</Button>

If you want to visually explore namescopes, open up your browser console after starting an application. Issue the following command: Fayde._VisualTree(). The visual tree will dump to the console. You will notice something for each node just after the node type and id. The next set of square brackets contains information about the node name and namescope. + indicates the owner of a namescope, while ^ indicates a member of a parent namescope.

from fayde.

Sally-Xu avatar Sally-Xu commented on September 17, 2024

Yes, I understand namescope is for isolation. But seems each control not only has a namescope, but a DocNameScope, which I assume is the namescope for the whole document? FindName function is trying to find the control first within its own namescope, if not found, try the DocNameScope.

Here is the FindName function:

XamlNode.prototype.FindName = function (name, doc) {
    var scope = this.FindNameScope();
    var node;
    if (scope)
        node = scope.FindName(name);
    var docscope;
    ;
    if (!node && doc && (docscope = this.DocNameScope))
        node = docscope.FindName(name);
    return node;
};

It can't find the Frame because the Button's DocNameScope doesn't contain the Frame either.

Here is the HyperlinkButton._Navigate function:

HyperlinkButton.prototype._Navigate = function () {             
    var targetName = this.TargetName;
    var targetUie;
    if (!targetName) {
        targetUie = Fayde.VisualTreeHelper.GetParentOfType(this, Fayde.Controls.Frame);
    } else {
        targetUie = this.FindName(targetName, true);
    }
    if (!targetUie) {
        window.location.href = this.NavigateUri.toString();
    } else if (targetUie instanceof Controls.Frame) {
        window.location.hash = this.NavigateUri.toString();
    } else {
        window.open(this.NavigateUri.toString(), targetName);
    }
};

So we either need to fix the problem in the HyperlinkButton._Navigate function or in the FindName function.

from fayde.

BSick7 avatar BSick7 commented on September 17, 2024

Can you post an example that isn't working?

from fayde.

Sally-Xu avatar Sally-Xu commented on September 17, 2024

Here is the testing code:

default.fap:
<Application
    xmlns="http://schemas.wsick.com/fayde"
    xmlns:x="http://schemas.wsick.com/fayde/x"
    Theme="Metro"
    xmlns:views="Views"
    xmlns:viewmodels="ViewModels">

    <Grid x:Name="LayoutRoot">
      <Grid.DataContext>
        <viewmodels:MenuViewModel/>
      </Grid.DataContext>

      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition/>
      </Grid.ColumnDefinitions>

        <ListBox ItemsSource="{Binding List}">
          <ListBox.ItemTemplate>
            <DataTemplate>
              <HyperlinkButton NavigateUri="{Binding Name}" Content="{Binding Name}" TargetName="ContentFrame" />
            </DataTemplate>
          </ListBox.ItemTemplate>
        </ListBox>

      <Frame x:Name="ContentFrame" Grid.Column="1">
              <Frame.UriMapper>
              <UriMapper>
                <UriMapping Uri="" MappedUri="Views/Page1.fayde" />
                <UriMapping Uri="{pageName}" MappedUri="Views/{pageName}.fayde"/>
              </UriMapper>
              </Frame.UriMapper>
      </Frame>
    </Grid>
</Application>

ViewModels/MenuViewModel:

/// <reference path="../lib/Fayde/Fayde.d.ts" />
class MenuViewModel extends Fayde.MVVM.ViewModelBase {
    List: { Name: string }[] = [];
    constructor() {
        super();
        this.List.push({ Name: "Page1" });
        this.List.push({ Name: "Page2" });
    }
}
export = MenuViewModel;

Views/Page1.Fayde:

<Page xmlns="http://schemas.wsick.com/fayde"
      xmlns:x="http://schemas.wsick.com/fayde/x"
      Title="Page1">
      <Grid>
        <TextBlock Text="Page1"/>
      </Grid>
</Page>

Views/Page2.Fayde:

<Page xmlns="http://schemas.wsick.com/fayde"
      xmlns:x="http://schemas.wsick.com/fayde/x"
      Title="Page1">
      <Grid>
        <TextBlock Text="Page2"/>
      </Grid>
</Page>

from fayde.

BSick7 avatar BSick7 commented on September 17, 2024

Thanks for posting. I can immediately see why this works in Silverlight and not Fayde. Even in Silverlight, the HyperlinkButton exists within a namescope separate from the Frame. The distinction emerges when the engine attempts to find the target. Silverlight has a way of "escaping" from the ListBox.

When I rebuilt the node management, I refined to be more peformant. The benefits of performance gain outweighed the edge cases that we could no longer support. This is one of those cases that I believe has 2 possible workarounds.

  1. Prepend # in front of the uri and remove the target name. This will force the Frame to follow the link through deep linking.
  2. We can register Frames independent of namescopes. If there are nested Frames, the algorithm would crawl the tree upwards until it found a Frame or an Application. You would look from there for Frames that matched your TargetName.

from fayde.

Sally-Xu avatar Sally-Xu commented on September 17, 2024

If there is only one Frame on the page, the 1st workaround would be enough. If more than one Frame are allowed on the page, we should go with the 2nd approach.

from fayde.

BSick7 avatar BSick7 commented on September 17, 2024

I found the deeper issue with finding the target for navigation. Fix will be included with implementation of TargetName for issue #143.

from fayde.

BSick7 avatar BSick7 commented on September 17, 2024

Fixed in Fayde v0.16.41.

from fayde.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.