views:

279

answers:

3

I got a problem. I added a frame in the window xaml to load pages in. I can directly load a page into frame with Source tag of the frame. It works. I need to use the code in C# to refer to the link from listbox menu a poplulate an apropriate link when an listbox item is selected. My problem is that I cannot refer the frame in C# code, it just cannot be seen. I defined the frame with x:Name="ContentFrame". When I refer to in in C#, Intellisense tells that "The name "ContentFrame" does not exist in the current context". What I am doing wrong? I am lost here. Any ideas are highly appreciated. Here is the code:

XAML:

<Frame x:Name="ContentFrame" JournalOwnership="OwnsJournal" NavigationUIVisibility="Hidden" Grid.Column="2" </Frame>

C#

` private void SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)

    {
        ListBoxItem lbi = ((sender as ListBox).SelectedItem as ListBoxItem);
        string itemName = lbi.Content.ToString();
        if ( Nav_ListBox.SelectedItem.Equals("Page1" ) )
        {
            ContentFrame.Source = new Uri("Pages/Page1.xaml", UriKind.Relative);
            Canvas_Frame.NavigationUIVisibility = NavigationUIVisibility.Hidden;
        }
    }

`

+1  A: 

I cant exactly understand why your frame cant be referenced. Did you try another name? I would like you to suggest another smarter way to do this. You can use a Binding for the source. Here is a little example:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="24"/>
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <ComboBox x:Name="SourceBox" Grid.Row="0"
              VerticalAlignment="Top"
              DisplayMemberPath="Label"
              TextBlock.Foreground="Black"></ComboBox>

    <Frame NavigationUIVisibility="Hidden" 
           JournalOwnership="OwnsJournal" Grid.Row="1"
           Source="{Binding ElementName=SourceBox, Path=SelectedItem.Source}"/>
</Grid>

Notice the Source binding on the frame. There is also no more x:Name on the Frame.

In the code behind you have to build a propper ItemSource for the combobox. Therefore i built a simple object, which holds a lable and a source.

public class SourceHolder
{
    public string Label { get; set; }
    public Uri Source { get; set; }
}

In the constructor of your window you can assign the itemssource to your combobox:

public Window1()
{
    List<SourceHolder> sources = new List<SourceHolder>();
    sources.Add(new SourceHolder()
                {
                    Label = "Page1",
                    Source = new Uri("Page1.xaml", UriKind.Relative)
                }
        );

    sources.Add(new SourceHolder()
                {
                    Label = "Page2",
                    Source = new Uri("Page2.xaml", UriKind.Relative)
                }
        );

    InitializeComponent();

    this.SourceBox.ItemsSource = sources;

}

The result is, that the combobox has two items (Page1, Page2). If you change the item, the frame updates it's content with the given Source of the selected combobox item.

Jan

JanW
PS: of course the same works for a listbox. I had a combobox in mind when i wrote this :)
JanW
Thank you! It looks like Expression Blend has some kind of bug. I restarted it and then I was able to reference the frame. It is weird. I am wondering if you can tell me how I could populate label and Uri Source using xml. The idea is to have a listbox which will be generated from xml. Each item will have "name" and "UriLink". I need to navigate to the page on click on the listboxitem. I was experimented with it but it seems like I am missing something. Thank you in advance.
vladc77
There are lots of ways filling the listbox with content. If you like to use XML, i suggest you to use XPath Binding. A very nice explained example you can find here:http://msdn.microsoft.com/en-us/library/system.windows.data.binding.xpath.aspxThan you no longer need my "SourceHolder" object and actually zero code behind :)
JanW
Thank you for the lead. I utilized XPath Binding with XmlDataProvider and it works great.I am still having problems assigning Uri on ListboxItem Selected or Clicked. I am wondering if you can advise the way to make it work. I include the code below:
vladc77
see my new answer below
JanW
A: 

Thank you for the lead. I utilized XPath Binding with XmlDataProvider and it works great. I am still having problems assigning Uri to ListboxItem Selected or Clicked. I am wondering if you can advise the way to make it work. Here is what I did so far:

XAML:

    <DataTemplate x:Key="pageTemplate">
        <StackPanel Orientation="Horizontal" >
            <Image Source="Resources/Images/icon_placeholder_dark20x20.png" Margin="4" VerticalAlignment="Center" />
            <TextBlock Text="{Binding XPath=name}" FontFamily="Segoe UI" LineHeight="22" Foreground="#FF000000" FontSize="14" VerticalAlignment="Center" Margin="4" />
        </StackPanel>
    </DataTemplate>

Assigning it to the ListBox:

<ListBox x:Name="Nav_ListBox" Margin="0" ScrollViewer.HorizontalScrollBarVisibility="Hidden" Background="#FFF2F2F2" ItemTemplate="{DynamicResource pageTemplate}" ItemsSource="{Binding Source={StaticResource PagesData}, XPath=page}" Padding="6" IsTabStop="True" BorderBrush="Black" FontFamily="Segoe UI Light" Foreground="Black" BorderThickness="0" Width="200" SelectedIndex="1" Style="{DynamicResource ListBoxStyle1}" Grid.Column="0" HorizontalAlignment="Left" SelectionChanged="SelectionChanged" />

XML:

<Pages xmlns="">
<page id="page01">
    <name>Page 1</name>
    <source>Pages/Page1.xaml</source>
</page>
<page id="page02">
    <name>Page 2</name>
    <source>Pages/Page2.xaml</source>
</page>

It populates the listbox with all items. Then I need to load the pages in the Frame on ListboxItem Selecxted or clicked:

Xaml for Frame:

<Frame x:Name="ContentFrame" Source="{Binding ElementName=Nav_ListBox, Path=SelectedItem.Source}" JournalOwnership="OwnsJournal" NavigationUIVisibility="Hidden" Grid.Column="2" HorizontalAlignment="Left" Width="Auto">
            </Frame>

I need to pass the Uri value on item selected or click. I am still looking for the way to make it right. Any ideas?

vladc77
I finally completed it. Here is what I had to add for the Frame: <Frame x:Name="ContentFrame" JournalOwnership="OwnsJournal" NavigationUIVisibility="Hidden" Grid.Column="2" HorizontalAlignment="Left" Width="Auto" DataContext="{Binding ElementName=Nav_ListBox, Path=SelectedItem, Mode=OneWay}" Source="{Binding XPath=UriSource}" /> It works perfectly now. No C# code is needed. I am only wondering if it is not the best practice for what I am doing here. Thank you.
vladc77
Ah okay. Did not guess that the DataContext Binding would make the difference. Maybe Source Binding With ElementName, Path and XPath is not working together at all. Nice Idea. I think the way you solved it now is at least a good practice. No code behind, clear code, reliable, flexible, extendable. Would be nice if you honor my work if you check the solved button or push some of my answers :-) Jan
JanW
Where is that solved button. I'd love to honor your help but had hard time finding the way.
vladc77
+1  A: 

You did it almost right. The only problem is the binding to the selected item. Since the Source property of the frame is of type Uri, and has no dynamic converter, you need an own converter, which does the job:

public class UriConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        XmlElement element = value as XmlElement;

        if (element != null)
        {
            string uriSource = element.SelectSingleNode("source").InnerText;
            return new Uri(uriSource, UriKind.Relative);
        }
        else
            return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

You now bind the selected item directly with no xpath and the converter extracts the uri string and builds an Uri object. Here is the fully working xaml (no code behind, except the converter):

<Window x:Class="FrameTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:FrameTest"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate x:Key="pageTemplate" >
            <StackPanel Orientation="Horizontal" >
                <TextBlock Text="{Binding XPath=name}" FontSize="14"
                           VerticalAlignment="Center" Margin="4" />
            </StackPanel>
        </DataTemplate>

        <XmlDataProvider x:Key="PagesData" XPath="Pages">
            <x:XData>
                <Pages xmlns="">
                    <page id="page01">
                        <name>Page 1</name>
                        <source>Pages/Page1.xaml</source>
                    </page>
                    <page id="page02">
                        <name>Page 2</name>
                        <source>Pages/Page2.xaml</source>
                    </page>
                </Pages>

            </x:XData>
        </XmlDataProvider>

        <local:UriConverter x:Key="UriConverter" />
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200" />
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <ListBox x:Name="Nav_ListBox" Grid.Column="0" 
                 VerticalAlignment="Top" 
                 TextBlock.Foreground="Black"
                 ItemTemplate="{DynamicResource pageTemplate}"
                 ItemsSource="{Binding  Source={StaticResource PagesData},
                               XPath=page}"/>

        <Frame NavigationUIVisibility="Hidden"  
               JournalOwnership="OwnsJournal" Grid.Column="1" 
               Source="{Binding ElementName=Nav_ListBox, Path=SelectedItem,
                                Converter={StaticResource UriConverter}}"/>

    </Grid>
</Window>

The pages have to be in the pages folder of the same directory of the window of course. In my example, I had two pages with a TextBlock "I am Page1/Page2".

Hope i could help you :)

JanW
It is great. Thank you for your help. I highly appreciate it.
vladc77
I have a question related to the solution you described. I need to change a selection state of the listbox item related to the UriSource while clicking 'back'/'forward' buttons of journal navigation. I also can have two buttons which may perform the navigating back and forward command. I need to make the selected item in the ListBox be the current with the page in the ContentFrame. Please let me know if you can help. Thank you in advance.
vladc77