WPF Resources.resx string with hyperlink?
I want to have a string resource, which contains a hyperlink in it. I guess this isn't possible, unless I had 4 resource strings:
Pre-hyperlink text hyperlink href hyperlink text Post-hyperlink text.
Then construct it in the xaml via:
<StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Right">
<TextBlock Grid.Column="1" Text="{x:Static p.Resources.PreHText}" />
<Hyperlink Grid.Column="1" NavigateUri="{x:Static p.Resources.HHref}">
<TextBlock Text="{x:Static p.Resources.HText}" /></Hyperlink></TextBlock>
<TextBlo开发者_运维知识库ck Grid.Column="1" Text="{x:Static p.Resource.PostHText}" />
</StackPanel>
Which is just awful, for many many reasons (Styling, not very dynamic etc etc). Bar creating my own render and string format, such as "Please email {me@there.com|the helpdesk} for further assistance". Is there any other way to achieve this? (Doesn't have to use the resources.resx file)
In the end I just made my own textblock control for it (Imaginitively named AdvancedTextBlock):
public class AdvancedTextBlock : TextBlock {
new private String Text { get; set; } //prevent text from being set as overrides all I do here.
private String _FormattedText = String.Empty;
public String FormattedText {
get { return _FormattedText; }
set { _FormattedText = value; AssignInlines(); }
}
private static Regex TagRegex = new Regex(@"\{(?<href>[^\|]+)\|?(?<text>[^}]+)?}", RegexOptions.Compiled);
public AdvancedTextBlock() : base() { }
public AdvancedTextBlock(System.Windows.Documents.Inline inline) : base(inline) { }
public void AssignInlines(){
this.Inlines.Clear();
Collection<Hyperlink> hyperlinks = new Collection<Hyperlink>();
Collection<String> replacements = new Collection<String>();
MatchCollection mcHrefs = TagRegex.Matches(FormattedText);
foreach (Match m in mcHrefs) {
replacements.Add(m.Value);
Hyperlink hp = new Hyperlink();
hp.NavigateUri = new Uri(m.Groups["href"].Value);
hp.Inlines.Add(m.Groups["text"].Success ? m.Groups["text"].Value : m.Groups["href"].Value);
hp.RequestNavigate += new RequestNavigateEventHandler(hp_RequestNavigate);
hyperlinks.Add(hp);
}
String[] sections = FormattedText.Split(replacements.ToArray(), StringSplitOptions.None);
hyperlinks.DefaultIfEmpty(null);
for (int i = 0, l = sections.Length; i < l; i++) {
this.Inlines.Add(sections.ElementAt(i));
if (hyperlinks.ElementAtOrDefault(i) != null) {
this.Inlines.Add(hyperlinks[i]);
}
}
}
void hp_RequestNavigate(object sender, RequestNavigateEventArgs e) {
RequestNavigate(sender, e);
}
//
// Summary:
// Occurs when navigation events are requested.
public event RequestNavigateEventHandler RequestNavigate;
}
The only two things I'm not too happy about with my implementation is that:
A) I had to hack-hide the existing Text property, because I didn't know how to prevent that property from overriding the stuff I do
B) (Related to A) I have to call AssignInlines
everytime the FormattedText
field is set (which should only be once admittidly), but this is again, down to not knowing how to hook into the method which actually does the displaying stuff (Expecting to find a PreRender, Render event or similar, however I could not), so if anyone knows how to, that'd be awesome :).
My workaround is to declare "x" and "resx" at top of the WPF XAML so it can see the resource. (Replace ProductName with your namespace for the product):
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:resx="clr-namespace:ProductName.Properties;assembly=ProductNameResources"
and then I adjust the hyperlink by having it contain a Run sub control. (Change DeactivateCommand to your command in your data context and the Strings.Deactivate with your resource name.resource property:
<Hyperlink Command="{Binding DeactivateCommand}" FontSize="18">
<Run Text="{x:Static resx:Strings.Deactivate}"/>
</Hyperlink>
I prefer this way because it is shorter and no custom control.
If you need the word "Contact:" followed by the emailTo link, you can:
<TextBlock HorizontalAlignment="Center" FontSize="14">
<Run Text="{x:Static resx:Strings.Contact}"/>
<Hyperlink Command="{Binding SupportCommand}" FontStyle="Italic">
<Run Text="{x:Static resx:Strings.EmailTo}"/>
</Hyperlink>
</TextBlock>
Here is my solution:
<TextBlock x:Name="MyTextBlock" Grid.Column="1" Text="{x:Static resource:ResourceFile.Message}" Style="{StaticResource MyTextStyle}" >
<Hyperlink>
click here
</Hyperlink>
</TextBlock>
精彩评论