Linking a collection of buttons to a collection of labels - c#

I am reading in an XML file and using it to populate a WPF Form. Each entry in the XML file is used to create a button and a label.
The problem I am having is associating the button with the label:
Here is my code:
// Loop through Backups
foreach (var back in backups)
{
// Create Wrap Panel
myWrapPanel = new WrapPanel();
//myWrapPanel.Background = System.Windows.Media.Brushes.Red;
myWrapPanel.Orientation = System.Windows.Controls.Orientation.Horizontal;
myWrapPanel.Width = 600;
myWrapPanel.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
myWrapPanel.VerticalAlignment = System.Windows.VerticalAlignment.Top;
// **************************************
// Add Controls to Wrap Panel
// **************************************
// Backup Source
System.Windows.Controls.Button btnBackupSource = new System.Windows.Controls.Button();
btnBackupSource.Content = "Source";
btnBackupSource.Height = 25;
btnBackupSource.Width = 75;
btnBackupSource.Click += btnBackupSource_Click;
btnBackupSource.Name = "btnBackupSource";
myWrapPanel.Children.Add(btnBackupSource);
System.Windows.Controls.Label lblBackupSource = new System.Windows.Controls.Label();
lblBackupSource.Height = 25;
lblBackupSource.Width = 461;
lblBackupSource.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
lblBackupSource.VerticalAlignment = System.Windows.VerticalAlignment.Top;
lblBackupSource.Name = "lblBackupSource";
lblBackupSource.Content = "";
myWrapPanel.Children.Add(lblBackupSource);
The button and labels are created OK but I am struggling to associate them with each other. For example when a button is pressed the result needs to come up in the individual label which is associated with the button.
Any suggestions on how to proceed would be very welcome!
What I have currently got is each button updating a single label:
private void btnBackupSource_Click(object sender, RoutedEventArgs e)
{
SourceFolderBrowser = new System.Windows.Forms.FolderBrowserDialog();
// Allow users to creating new folders and default to the my documents folder.
SourceFolderBrowser.ShowNewFolderButton = true;
SourceFolderBrowser.RootFolder = Environment.SpecialFolder.Personal;
SourceFolderBrowser.ShowDialog();
label2.Content = SourceFolderBrowser.SelectedPath;
}
However what I am trying to do is get each button to update its associated label.

Here is my suggestion for you:
Store the label you want to associate with the button in the button's Tag property like this:
btnBackupSource.Tag = lblBackupSource;
Later when you to do something in the wired up btnBackupSource_Click you can do it like this:
var button = sender as Button;
var label = button.Tag as Label;
label.Text = "Hello";

This would be much easier by creating a DataTemplate and setting the ListBox.ItemTemplate to use the DataTemplate.
That way you do not have to create all the controls in code and need to wire up the button and label only once (preferably by databinding).
<Window.Resources>
<DataTemplate x:Key="backupView">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding BackupName}"/>
<Button Content="Source" Command="{Binding DoSomethingCommand}" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<ListBox ItemsSource="{Binding}" ItemTemplate="{StaticResource backupView}"/>
In code you would need to create a class (Backup?) with the property Name and a DoSomethingCommand. This command would modify the Name of the Backup and that would automatically being passed on to the view.

Related

Hyperlink in TextBlock is is not clickable

I have made this in code-behind :
var finishedText = new Run("Some text");
var finishedUrl = new Run("http://somewhere");
var hyperlink = new Hyperlink(finishedUrl) { NavigateUri = new Uri("http://somewhere") };
hyperlink.RequestNavigate += Hyperlink_RequestNavigate;
FinishedTextBlock.Inlines.Clear();
FinishedTextBlock.Inlines.Add(finishedText);
FinishedTextBlock.Inlines.Add(hyperlink);
FinishedTextBlock.Inlines.Add(Environment.NewLine);
FinishedTextBlock.Inlines.Add(finishedUrl);
In XAML :
<TextBlock Grid.Row="0"
x:Name="FinishedTextBlock"
Width="Auto"
Margin="10 10 0 0">
</TextBlock>
The text is not clickable.
What am I doing wrong?
The text is not clickable.
That is because your Hyperlink text is not even shown. You see the last Run that you have added to the Inlines collection, not the hyperlink itself.
You add the same Run named finishedUrl to your Hyperlink and its containing TextBlock, but you have to create a separate Run instance for the Hyperlink.
var finishedText = new Run("Some text");
var finishedUrl = "http://somewhere";
var finishedUrlRun = new Run(finishedUrl);
var hyperlink = new Hyperlink(finishedUrlRun) { NavigateUri = new Uri("http://somewhere") };
hyperlink.RequestNavigate += Hyperlink_RequestNavigate;
FinishedTextBlock.Inlines.Clear();
FinishedTextBlock.Inlines.Add(finishedText);
FinishedTextBlock.Inlines.Add(hyperlink);
FinishedTextBlock.Inlines.Add(Environment.NewLine);
var finishedUrlRun1 = new Run(finishedUrl);
FinishedTextBlock.Inlines.Add(finishedUrlRun1);
Even better, just do not add the last Run, as it is redundant, and replace the NewLine with a LineBreak to get the same layout as in your image but with a link.
FinishedTextBlock.Inlines.Clear();
FinishedTextBlock.Inlines.Add(finishedText);
FinishedTextBlock.Inlines.Add(new LineBreak());
FinishedTextBlock.Inlines.Add(hyperlink);
Unless your hyperlink is inside a webview then nothing will happen when you click on a hyperlink.
You need to handle the RequestNavigate event and do something before you'll see a web browser appear with a page in it.
If this was a wpf page inside a frame, or navigationwindow then it would also navigate without code.
https://learn.microsoft.com/en-us/dotnet/api/system.windows.documents.hyperlink?view=netcore-3.1
Remarks
Hyperlink implements the NavigateUri property that you set
with the Uri of the content that should be navigated to when the
Hyperlink is clicked. Hyperlink navigation can only occur, however, if
either the direct or indirect parent of a Hyperlink is a navigation
host, including NavigationWindow, Frame, or any browser that can host
XBAPs (which includes Internet Explorer 6 and later versions, and
Firefox 2.0+). For more information, see the Navigation Hosts topic in
Navigation Overview.
As it is, you need an event handler.
I'm not clear whether you intend the url to appear or a string. If you want a different string then this should work:
TextBlock tb = new TextBlock();
tb.Inlines.Add(new Run {Text="Some text" } );
tb.Inlines.Add(new LineBreak());
Run linkRun = new Run("Link To Google");
Hyperlink hyper = new Hyperlink(linkRun) { NavigateUri = new Uri(#"http://www.google.com") };
hyper.RequestNavigate += (o, e) => Process.Start(new ProcessStartInfo(e.Uri.ToString()){ UseShellExecute = true });
tb.Inlines.Add(hyper);
If you want the url to appear rather than some other string then:
TextBlock tb = new TextBlock();
tb.Inlines.Add(new Run { Text = "Some text" });
tb.Inlines.Add(new LineBreak());
string url = #"http://www.google.com";
Run linkRun = new Run(url);
Hyperlink hyper = new Hyperlink(linkRun){ NavigateUri = new Uri(url) };
hyper.RequestNavigate += (o, e) => Process.Start(new ProcessStartInfo(e.Uri.ToString()) { UseShellExecute = true });
tb.Inlines.Add(hyper);
sp.Children.Add(tb);
Note
One the process start, you will often get an error on win 10 machines without that useshellexecute in the process startinfo.
In older OS ( and you would see in old SO answers ) you used to be able to just process start with a URL and it would work with the default browser.
There is a linebreak inline which is intended to add a linebreak between a series of runs in a textblock.
In XAML, it needs to be like this:
<TextBlock Grid.Row="0"
x:Name="FinishedTextBlock"
Width="Auto"
Margin="10 10 0 0">
<Run Text="Some text" />
<LineBreak/>
<Hyperlink>http://somewhere</Hyperlink>
</TextBlock>
The hyperlink in your code does not content anything. The hyperlink constructor parameter
[finishedUrl] did not initialized the hyperlink to contain the string "http://somewhere".
You can change your code something like below:
var finishedText = new Run("Some text");
var finishedUrl = new Run("http://somewhere");
var hyperlink = new Hyperlink() { NavigateUri = new Uri("http://somewhere") };
hyperlink.Inlines.Add(finishedUrl.Text);
hyperlink.RequestNavigate += Hyperlink_RequestNavigate;
FinishedTextBlock.Inlines.Clear();
FinishedTextBlock.Inlines.Add(finishedText);
FinishedTextBlock.Inlines.Add(Environment.NewLine);
FinishedTextBlock.Inlines.Add(hyperlink);

Inline Hyperlink navigate to Page

I'm constructing text, and some pieces of the text should contain a hyperlink. However, these hyperlinks do not redirect to a webpage but should open a page in the UWP app (the currently running UWP app, not a new instance of it or a different app).
A HyperlinkButton can only open URL's that lead to an external browser, it can't open a page inside the app.
Using an InlineUIContainer doesn't work, I get
Exception thrown: 'System.ArgumentException' in mscorlib.ni.dll
Additional information: Value does not fall within the expected range.
With this code
List<Inline> ic = new List<Inline>();
InlineUIContainer container = new InlineUIContainer();
TextBlock tbClickable = new TextBlock();
tbClickable.Foreground = new SolidColorBrush(Colors.Red);
tbClickable.Text = label?.name;
tbClickable.Tag = label?.id;
tbClickable.Tapped += TbArtist_Tapped;
container.Child = tbClickable;
ic.Add(container);
When I use
foreach (var item in ic)
{
dTb.Inlines.Add(item);
}
Where tbCurrent is the TextBlock.
Any other ways to get a clickable link as an Inline element?
Best case scenario I can attach a Tapped/Click event handler.
But opening the page via a URI method or so is also good.
I changed to a RichTextBlock and using Blocks I could add a clickable TextBlock.
This works in UWP.
List<Block> ic = new List<Block>();
Paragraph para = new Paragraph();
InlineUIContainer iuic = new InlineUIContainer();
TextBlock hpb = new TextBlock();
hpb.Text = "link text";
hpb.Tag = "some tag to pass on to the click handler";
hpb.Tapped += ClickHandler;
hpb.TextDecorations = TextDecorations.Underline;
hpb.Foreground = new SolidColorBrush((Windows.UI.Color)page.Resources["SystemAccentColor"]);
iuic.Child = hpb;
para.Inlines.Add(iuic);
ic.Add(para);
There is no reason you could not use a HyperlinkButton for this. Quick example:
<HyperlinkButton Click="HyperlinkButton_Click" Content="Click me" />
And the Click handler:
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
Frame.Navigate(typeof(MainPage));
}

Dinamically generate a button to open file dialog and select a file using WPF controls and C#

Basically I'm making a program that allows you to add to a stackpanel another stackpanel with several horizontally aligned textboxes with the press of a button. So far, everything is working as intented. Here's my code so far ,Stacker is the name of the parent stackpanel and it starts off empty:
private void Add_Click(object sender, RoutedEventArgs e)
{
Stacker.Children.Add(NewXD(Stacker.Children.Count + 1));
}
public System.Windows.Controls.StackPanel NewXD(int XD)
{
System.Windows.Controls.StackPanel NewP = new StackPanel();
NewP.Orientation = Orientation.Horizontal;
System.Windows.Controls.TextBox HAHA = new TextBox();
HAHA.Name = "question" + XD.ToString();
//HAHA.Text = HAHA.Height.ToString()+" "+HAHA.Width.ToString();
HAHA.Height = Double.NaN;
HAHA.Width = 120;
HAHA.FontSize=20;
NewP.Children.Add(HAHA);
for (int i = 1; i < 6; i++)
{
System.Windows.Controls.TextBox newBox = new TextBox();
newBox.Name = "answer"+XD.ToString()+"_"+i.ToString();
newBox.Height = Double.NaN;
newBox.Width = 120;
NewP.Children.Add(newBox);
}
System.Windows.Controls.ComboBox correct = new ComboBox();
correct.Name = "correct" + XD.ToString();
for (int i = 1; i < 6; i++)
{
System.Windows.Controls.ComboBoxItem newItem = new ComboBoxItem();
newItem.Name = "ans" + XD.ToString() + "_" + i.ToString();
newItem.Content = i.ToString();
correct.Items.Add(newItem);
}
NewP.Children.Add(correct);
return NewP;
}
I apologize for the lack of seriousness in some of my code.
Now, what I need to do is for the child stackpanels to also contain independent file pickers that work like the one sampled in this thread: Open file dialog and select a file using WPF controls and C#
What I don't know how to perform is that each of these generated buttons have the same basic funcion but are linked with each of their corresponding textbox.
Thanks in advance :)
Edit: As I was writing this it occured to me that perhaps I could use the help of the child stackpanel's array-like properties to choose the corresponding textbox, because the file selector's textbox and button will always be the last two items in the stackpanel, but I'm not very sure how to perform this.
For functionality you can create an EventHandler that will be assigned to each button. Your event handler will then open File Dialog...
Buttons have Tag property which you could use to identify your TextBoxes, or you could derive from Button class and add AssociatedTextBox property for example.

Adding dynamic text boxes in windows store app 8.1 using xaml c#

TextBox x = new TextBox();
x.Height = 30;
x.Width = 200;
x.Name = "Title";
x.Text = item.Title;
x.TextWrapping = TextWrapping.Wrap;
x.FontSize = 60;
StackPanel s = new StackPanel();
s.Children.Add(x);
I have placed this code inside a function called private async void Getnotes();
and im calling this function from the constructor after this.InitializeComponent();
But when i run the app,text boxes are not getting added. what could be the problem?
You need to add the stackpanel to the window
window.AddChild(s);
You need to pass the window to your function.
by default wpf app has a non named grid.
name it "MyMainGrid".
and then you can add ether your stack panel.
MyMainGrid.Children.Add(s);
or directly add textbox to grid.
MyMainGrid.Children.Add(X);

How To Create A Bottom Or Top AppBar in Windows Store App Using C#?

I'm aware of the way to create the AppBar via XAML code. I want to know how to create the AppBar via C#.
On the Windows Phone App, i can just do this.
ApplicationBar = new ApplicationBar(){
Mode = ApplicationBarMode.Minimized
};
ApplicationBarMenuItem copyLinkButton = new ApplicationBarMenuItem();
copyLinkButton.Click += (sender, e) => { //action };
copyLinkButton.Text = "copy to clipboard";
ApplicationBar.MenuItems.Add(copyLinkButton);
ApplicationBarMenuItem openInIEButton = new ApplicationBarMenuItem();
openInIEButton.Click += (sender, e) => { //action };
openInIEButton.Text = "open in internet explorer";
ApplicationBar.MenuItems.Add(openInIEButton);
How do i do it in Windows Store App?
Update
Thank you #kimsk for giving me an answer to my previous question. I've solved it with your answer. But after solving that problem, another similar problem surfaced.
Because i didn't simply use a button like this,
<Button>Button 3</Button>
I have problem tapping into the Microsoft's default style. Is there anyway to reference to that particular style or do i have to create one from scratch by myself?
<Button Style="{StaticResource EditAppBarButtonStyle}"/>
Thanks again!
It's pretty straightforward if you think about XAML is just a declarative way to create objects of UIElement elements such as AppBar, Button, StackPanel, and so on.
Here is the code to create a BottomAppBar in XAML that you already know:
<Page.BottomAppBar>
<AppBar>
<StackPanel Orientation="Horizontal">
<Button>Button 3</Button>
<Button>Button 4</Button>
</StackPanel>
</AppBar>
</Page.BottomAppBar>
Here is the C# code that creates a TopAppBar:
var appBar = new AppBar();
var stackPanel = new StackPanel{Orientation = Orientation.Horizontal};
stackPanel.Children.Add(new Button { Content = "Button1" });
stackPanel.Children.Add(new Button { Content = "Button2" });
var buttonWithStyle = new Button();
buttonWithStyle.Style = Application.Current.Resources["EditAppBarButtonStyle"] as Style;
stackPanel.Children.Add(buttonWithStyle);
appBar.Content = stackPanel;
this.TopAppBar = appBar;
Notice the pattern? :-)
And this is the screenshot:
Hope this helps!

Categories