Fragensteller
uriMapper macht dynamisches Zuweisen von Uris unmöglich?

Allgemeine Diskussion
-
Hallo Community,
ich habe ein schwerwiegendes Problem. Ich nutze Silverlight 4 mit Visual Studio 2010. Folgender XAML Code befindet sich auf meiner MainPage. Das wichtige ist der uriMapper.
<navigation:Frame x:Name="frmContent" Source="/1Level/Home" Navigated="Content_Navigated" NavigationFailed="Content_NavigationFailed"> <navigation:Frame.UriMapper> <uriMapper:UriMapper> <uriMapper:UriMapping Uri="" MappedUri="/1Level/Home.xaml" /> <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Sites/{pageName}.xaml"/> </uriMapper:UriMapper> </navigation:Frame.UriMapper> </navigation:Frame>
Wie ihr seht kann ich meine URIs relativ einfach darstellen im Format "/{pagename}".
Nun habe ich meine URIs in eine XML ausgelagert und lese diese ein. Dort steht dann zum Beispiel "/1Level/Home". Eine Uri, die, wenn ich sie direkt ins XAML schreibe, einwandfrei funktioniert.
<HyperlinkButton x:Name="hyperHome" Style="{StaticResource main_HyperStyle}" TargetName="frmContent" NavigateUri="/1Level/Home"> <TextBlock /> </HyperlinkButton>
Eigentlich wollte ich sie wie folgt einlesen, aber da kommt eine Exception beim Erstellen der Uri.
IEnumerable<PolFotHyper> values = from elem in doc.Descendants("Hyperlink") select new PolFotHyper { Id = elem.Attribute(XName.Get("Id")).Value, Target = elem.Attribute(XName.Get("Target")).Value, Dict = elem.Elements(XName.Get("Language")).ToDictionary(lang => (string)lang.Attribute(XName.Get("lang")), content => (string)content), <strong>NaviUri = new Uri(elem.Attribute(XName.Get("NaviUri")).Value)</strong> };
Eingelesen habe ich sie nun wie folgt.
IEnumerable<PolFotHyper> values = from elem in doc.Descendants("Hyperlink") select new PolFotHyper { Id = elem.Attribute(XName.Get("Id")).Value, Target = elem.Attribute(XName.Get("Target")).Value, Dict = elem.Elements(XName.Get("Language")).ToDictionary(lang => (string)lang.Attribute(XName.Get("lang")), content => (string)content), <strong>NaviUri = new Uri(new Uri(App.AppDomain), elem.Attribute(XName.Get("NaviUri")).Value)</strong> };
Jetzt müsste ich meinem HyperlinkButton diese Uri auch zuweisen, was ich eigentlich wie folgt machen wollte. dabei stürtzt die Anwendung aber ab...
((HyperlinkButton)this.FindName("Id")).NavigateUri = l.NaviUri;
Folgendes geht ebenfalls nicht, da AbsolutePath nur ein string ist und eine Uri benötigt wird.
((HyperlinkButton)this.FindName("Id")).NavigateUri = l.NaviUri.AbsolutePath
Wenn ich aber nun aus dem AbsolutePath wieder eine Uri machen möchte, geht das wieder nicht...
Ich möchte also folgendes: Dem NavigateUri Property des HyperlinkButtons eine Uri folgenden Formates zuweisen: "/XXX/YYY" oder auch "/XXX" oder auch "/XXX/YYY/ZZZ"
Kann jemand helfen?
- Typ geändert Robert Breitenhofer Montag, 1. August 2011 14:47 Keine Rückmeldung des Fragenstellender
Samstag, 16. Juli 2011 18:38
Alle Antworten
-
Hi,
Kennt keiner eine Lösung?
Entweder das oder die Leute sind im (verdienten) Wochenende. Würd ich jetzt einfach mal so sagen^^
Eigentlich wollte ich sie wie folgt einlesen, aber da kommt eine Exception beim Erstellen der Uri.
was ich eigentlich wie folgt machen wollte. dabei stürtzt die Anwendung aber ab...
Und wo ist die (genaue und vollständige) Fehlermeldung? Ohne die kann man da eh nicht wirklich was sagen.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET CommunitySonntag, 17. Juli 2011 16:25 -
Ich kann Dir einen kostenpflichtigen Support mit entsprechenden Reaktionszeiten empfehlen.
Ansonsten ist Deine Frage unklar. Es ist nicht ersichtlich, was Du genau machst. Ich habe Dein Szenario mal nachgestellt – entsprechend Deinen Angaben, so wie ich sie verstanden haben. Ich kann kein Problem feststellen.
Hier der XAML:
<UserControl x:Class="SilverlightApplication1.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400" xmlns:navigation="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:uriMapper="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation" xmlns:local="clr-namespace:SilverlightApplication1"> <UserControl.Resources> <local:ViewModel x:Key="vm"/> </UserControl.Resources> <StackPanel Background="White" DataContext="{Binding Source={StaticResource vm}}"> <ListBox ItemsSource="{Binding View}"> <ListBox.ItemTemplate> <DataTemplate> <HyperlinkButton Content="{Binding Desc}" NavigateUri="{Binding NaviUri}" /> </DataTemplate> </ListBox.ItemTemplate> </ListBox> <navigation:Frame x:Name="frmContent" Source="/1Level/Home"> <navigation:Frame.UriMapper> <uriMapper:UriMapper> <uriMapper:UriMapping Uri="" MappedUri="/1Level/Home.xaml" /> <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Sites/{pageName}.xaml"/> </uriMapper:UriMapper> </navigation:Frame.UriMapper> </navigation:Frame> </StackPanel> </UserControl>
Der Codehind dazu:
Imports System.Xml Imports System.Xml.Linq Public Class ViewModel Implements INotifyPropertyChanged Public Sub New() Dim inp = <root> <Hyperlinks> <Hyperlink> <Id>1</Id> <Desc>Link 1</Desc> <Target></Target> <Language></Language> <lang></lang> <NaviUri>/Page1</NaviUri> </Hyperlink> <Hyperlink> <Id>2</Id> <Desc>Link 2</Desc> <Target></Target> <Language></Language> <lang></lang> <NaviUri>/Page2</NaviUri> </Hyperlink> </Hyperlinks> </root> cvs.Source = From itm In inp...<Hyperlink> Select New PolFotHyper With {.NaviUri = New Uri(itm...<NaviUri>.Value, UriKind.RelativeOrAbsolute), _ .Desc = itm...<Desc>.Value} End Sub Public Class PolFotHyper Public Property NaviUri As Uri Public Property Desc As String End Class Private cvs As New CollectionViewSource Public ReadOnly Property View As ICollectionView Get Return cvs.View End Get End Property #Region " PropertyChanged" Public Event PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged Private Sub OnPropertyChanged(ByVal prop As String) RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop)) End Sub #End Region End Class
In der ListBox kannst Du einen Eintrag auswählen und diese Seite wird dann angezeigt. Ich hoffe, du kommst mit der BeginnerASIC-Sprache zurecht : -).
--
Viele Gruesse
PeterSonntag, 17. Juli 2011 16:57 -
Ich glaube ich verstehe deinen Code. Du machst es über Bindings. Das habe ich noch nicht ausprobiert.
Nichtsdestotrotz hast du doch ein XML, in dem eine Uri "/Page1" steht. Dann liest du es ein über eine from-Abfrage. Da kommt bei mir schon der Fehler: "UriFormatException". Ich probiere es aber heute abend noch ein Mal.
Andere Frage dazu: Wenn du es über Bindings machst, woher weiß der HyperlinkButton, dass er Link1 ist und nicht Link2? Oder ist ihm das egal? In meinem Szenario muss nämlich ein bestimmter HyperlinkButton eine bestimmte Uri haben. Das müsste ich dann wohl noch über die Id festmachen?!
Montag, 18. Juli 2011 08:16 -
Das Schönste an WPF ist, dass Oberfläche und Logik total getrennt werden können. Da braucht man auch keine ID für irgendwelche Suche in den Elementen der Oberfläche. Es reicht eine Bindung und die Oberfläche holt sich die Daten.Ich habe in meinem Beispiel jeweils für “Link 1” und für “Link 2” ein Item in der ListBox und habe komplex gebunden. Damit erscheinen beide Einträge aus der XML-Datei.Wenn Du nur einen aus der XML-Datei ausgewählten Eintrag wünschst, dann binde einfach, indem Du nur einen Hyperlink in der Oberfläche hast, der an eine Eigenschaft vom Typ Deiner Klasse PolFotHyper ist. Dieser Eigenschaft weist Du das Objekt mit den gewünschten Werten zu.--
Viele Gruesse
PeterMontag, 18. Juli 2011 09:39 -
Das Schönste an WPF ist, dass Oberfläche und Logik total getrennt werden können. Da braucht man auch keine ID für irgendwelche Suche in den Elementen der Oberfläche. Es reicht eine Bindung und die Oberfläche holt sich die Daten.Wenn Du nur einen aus der XML-Datei ausgewählten Eintrag wünschst, dann binde einfach, indem Du nur einen Hyperlink in der Oberfläche hast, der an eine Eigenschaft vom Typ Deiner Klasse PolFotHyper ist. Dieser Eigenschaft weist Du das Objekt mit den gewünschten Werten zu.Dienstag, 19. Juli 2011 08:16
-
Weiß die Oberfläche welchen Inhalt sie verwenden soll?Natürlich, da der Programmierer festlegt, welches Objekt gebunden wird und das Objekt mit entsprechendem Inhalt füllt.Aus deinem Beispiel geht das für mich nicht hervor :(In meinem Beispiel wird komplex gebunden und damit hat jedes ListBoxItem sein entsprechendes Datenobjekt.
Jeder HyperlinkButton ist an ein Objekt gebunden. Entsprechend Programmablauf werden diese Objekte mit Daten gefüllt und über PropertyChange der Oberfläche mitgeteilt, dass sie sich die aktuellen Werte für die Anzeige holen soll.--
Viele Gruesse
PeterDienstag, 19. Juli 2011 09:05 -
Ich habe jetzt folgendes:
<UserControl.Resources> <local:ViewModel x:Key="vm"/> </UserControl.Resources> <Grid x:Name="LayoutRoot" ShowGridLines="False" DataContext="{Binding Source={StaticResource vm}}"> <Grid x:Name="gridHead" VerticalAlignment="Top" Height="75"> <Border x:Name="brdHead" BorderThickness="0,0,0,1"> <Border.BorderBrush> <SolidColorBrush Color="{StaticResource main_2ndColor}"/> </Border.BorderBrush> <StackPanel x:Name="spHead" HorizontalAlignment="Right" VerticalAlignment="Bottom" Orientation="Horizontal" Margin="0,0,10,10"> <HyperlinkButton x:Name="hyperHome" Style="{StaticResource main_HyperStyle}" TargetName="frmContent"> <TextBlock x:Name="hyperHomeTB" /> </HyperlinkButton> <HyperlinkButton x:Name="hyperAbout" Style="{StaticResource main_HyperStyle}" TargetName="frmContent"> <TextBlock x:Name="hyperAboutTB" /> </HyperlinkButton> </StackPanel> </Border> </Grid> </Grid>
Was muss ich dann beim StackPanel eintragen? Gibts da ne Eigenschaft "Source"?public class ViewModel : INotifyPropertyChanged { private CollectionViewSource hypers; public ViewModel() { //Load Hyperlinks this.LoadResources("pathHypers"); } /// <summary> /// Loads the xml files with the specified path /// </summary> /// <param name="resPath">path to xml</param> private void LoadResources(string resPath) { //Create client WebClient client = new WebClient(); //Add eventHandler "DownloadStringCompleted" client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted); //Create url containing xml files Uri url = new Uri(String.Concat(App.AppDomain, ResourceHandler.GetResource(App.ResPath, resPath)), UriKind.Absolute); //Start asynchronous download client.DownloadStringAsync(url); } private void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { if (e.Error == null) { XDocument doc = XDocument.Parse(e.Result); if (doc.DocumentType.Name.Equals("Hyperlinks")) { hypers.Source = ResourceHandler.GetValuesHyperFromXml(doc); } } } public ICollectionView HyperView { get { return hypers.View; } } public event PropertyChangedEventHandler PropertyChanged; public delegate void PropertyChangedEventHandler(object sender, PropertyChangedEventArgs e); private void OnPropertyChanged(string prop) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); } } }
Das mit dem PropertyChanged habe ich allerdings noch nicht verstanden :( Da kommt bei mir folgender Fehler:
"ViewModel" implementiert den Schnittstellenmember "System.ComponentModel.INotifyPropertyChanged.PropertyChanged" nicht. "ViewModel.PropertyChanged" hat nicht den entsprechenden Rückgabetyp "System.ComponentModel.PropertyChangedEventHandler" und kann "System.ComponentModel.INotifyPropertyChanged.PropertyChanged" daher nicht implementieren.
An sich liest er die entsprechende xml ein und erhält auch die Werte, aber wenn ich der Variable hypers.Source die Werte zuweisen will, kommt ein Fehler, dass ich doch mit new erstellen müsste. Folgendes mache ich beim Einlesen:
/// <summary> /// Reads all values for all controls "HyperlinkButton" in the app /// </summary> /// <param name="doc">specified XML document</param> /// <returns>list of values</returns> public static object GetValuesHyperFromXml(XDocument doc) { object values = from elem in doc.Descendants("Hyperlink") select new PolFotHyper { Id = elem.Attribute(XName.Get("Id")).Value, Target = elem.Attribute(XName.Get("Target")).Value, Dict = elem.Elements(XName.Get("Language")).ToDictionary(lang => (string)lang.Attribute(XName.Get("lang")), content => (string)content), NaviUri = new Uri(new Uri(App.AppDomain), elem.Attribute(XName.Get("NaviUri")).Value) }; return values; }
Alternativ:
/// <summary> /// Reads all values for all controls "HyperlinkButton" in the app /// </summary> /// <param name="doc">specified XML document</param> /// <returns>list of values</returns> public static IEnumerable<PolFotHyper> GetValuesHyperFromXml(XDocument doc) { IEnumerable<PolFotHyper> values = from elem in doc.Descendants("Hyperlink") select new PolFotHyper { Id = elem.Attribute(XName.Get("Id")).Value, Target = elem.Attribute(XName.Get("Target")).Value, Dict = elem.Elements(XName.Get("Language")).ToDictionary(lang => (string)lang.Attribute(XName.Get("lang")), content => (string)content), NaviUri = new Uri(new Uri(App.AppDomain), elem.Attribute(XName.Get("NaviUri")).Value) }; return values; }
Mittwoch, 20. Juli 2011 10:47 -
Du solltest erst einmal konzeptionell die Sache durchdenken:1. Was soll genau erreicht werden? Ich habe es nicht verstanden.2. Welche Technologie soll eingesetzt werden? OOP (objektorientierte Programmierung) mit Eigenschaftsbindung oder klassische lineare Programmierung mit Suchen und Wertzuweisung per Code?3. Wie soll das Projekt strukturiert werden? Oberfläche und Code zusammen oder in separaten Klassen/Objekten?4. Da die XML-Datei vermutlich viele Einträge hat und nur 2 Einträge davon benötigt werden, wie sollen diese beiden Einträge ausgewählt werden?--
Viele Gruesse
PeterMittwoch, 20. Juli 2011 16:07