I'm developing a Windows 10 UWP app and I'd like to add textboxes with buttons like shown in the screenshot. The screenshot is taken from the universal Maps app on Windows 10. If someone could point me to any documentation or samples, I'd be very grateful.
Here's a hint: look at the TextBox control template.
It's very long so I won't copy the whole thing, but if you look at the bottom, you'll notice that there is a ContentControl for placeholder text (PlaceholderTextContentPresenter), and there's also a button called DeleteButton which is visible when you focus on a TextBox with some text inside.
This shows you that one way to do what you want is to modify the template to have another button next to the DeleteButton or something similar (depending on what you're trying to achieve in the end) and then you can hide it or show it depending on the current VisualState, which is also something you would define in your template.
Making a template also means that you can make it quite reusable, so you should be able to use it in future projects, too.
This answers the follow-up question: How do you handle the events on the extra button?
If your new button template resides in some local resource dictionary (e.g., Page.Resources, you can just add a click handler directly. If, however, the button template lives in a separate resource dictionary (Styles.xaml or whatever), doing so would require creating code-behind for the dictionary. It is probably better to subclass and do something like this:
public class MyTextBox : TextBox
{
public event EventHandler<RoutedEventArgs> ExtraClick;
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
Button extraButton = GetTemplateChild("ExtraButton") as Button;
if (extraButton != null)
{
extraButton.Click += (sender, e) => ExtraClick?.Invoke(sender, e);
}
}
}
You could then handle this (or any other you care to tackle) events where you actually use the button, e.g.,
<local:MyTextBox ExtraClick="OnExtraClicked" />
Code-behind:
private void OnExtraClicked(object sender, RoutedEventArgs e)
{
// ...
}
For completeness: The external dictionary must be merged into the available resources at some point, for example in the application's resources:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Related
I'm just learning how to make universal apps for windows 10. Most of the tutorials show you how to work with XAML and how to assign functions to elements when you click on them but I couldn't find a way to make a new control appear when I click a button.
I'm making a note taking application. I've designed most of the stuff that I need. Now I want whenever I click a button to create a new textblock where the user can write their note.
//Create a new note when clicking the add button
private void newNoteBtn_Click(object sender, RoutedEventArgs e)
{
TextBox newNote = new TextBox();
newNote.Text = "Enter your text";
}
This is the code that runs when the button is clicked. When I run the application nothing happens. I think I have to put the new textbox in some kind of Grid or something.
Most of the tutorials are really old or mention windows forms and use some sort of this.Controls.Add(newNote); but Visual studio doesn't give me the Controls.Add option. I've also created a <Grid x:Name="notes"></Grid> which I thought I could use as a placeholder for the notes that are being created but I can't access the Grid element through the code.
Container Controls like Grid have Children property so you should use Childern like this:
TextBox newNote = new TextBox();
newNote.Text = "Enter your text";
notes.Childern.Add(newNote);
When defining
<Grid x:Name="notes"></Grid>
in XAML on the page, you be able to use notes as the identifier to access this Grid from the page's code behind:
notes.Children.Add(newNote);
I am attempting to form some xaml for a dataform programmatically using a string. I can get the combo box to appear. but when I attempt to use the code specifying the "MouseLeftButtonUp" or the "Loaded" event handler in the string; the page will turn white (no noticeable error) out after going into it. Please see relevant code below.
StringBuilder editTemplate = new StringBuilder("");
editTemplate.Append("<DataTemplate ");
editTemplate.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ");
editTemplate.Append("xmlns:toolkit='http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit' ");
editTemplate.Append("xmlns:navigation='clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation' ");
editTemplate.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' >");
editTemplate.Append("<StackPanel>");
editTemplate.Append(#" <toolkit:DataField Label='" + GetFieldWithoutNumber(theInfo, theDataContext) + "'>");
/* Won't Work */ editTemplate.Append(#" <ComboBox MouseLeftButtonUp='ComboBox_MouseLeftButtonUp' />");
/* Will Work */ editTemplate.Append(#" <ComboBox />");
editTemplate.Append(#" </toolkit:DataField>");
editTemplate.Append("</StackPanel></DataTemplate>");
dynamicDataForm.EditTemplate = XamlReader.Load(editTemplate.ToString()) as DataTemplate;
Event handlers hooked up in XAML are required to be declared in the code-behind connected to the XAML file. In the case of a ResourceDictionary or anything loaded from XamlReader.Load there can't be any code-behind, so event handlers can't be set in the XAML. The easiest way to get around this restriction would be to not build your template from strings and just declare it in the Resources section of your XAML file which you can then do like:
Resources["MyTemplate"] as DataTemplate
to get the template and assign it in code like you're doing here, or just use StaticResource in XAML. As long as it stays in the same XAML file connected to this code the event handlers you have in it currently should work fine. The dynamic part of the strings would also need to be changed to use Bindings.
If you want to stick with the XamlReader method you have 2 problems to solve.
Locate the ComboBox instance inside the rendered template
Wait until the template is rendered to look for the ComboBox
To find the ComboBox you need to first give it an x:Name attribute in the template text (you can just replace the event code currently there). Next you need to be able to locate an item in the visual tree by name. This is fairly straightforward and you can find an example here to do that.
To call this code at the right time you either need to override OnApplyTemplate, which unfortunately won't work if you're in something like a UserControl, or use another trick to keep it from running until all the controls are rendered. Here's a full example that could go in a constructor and uses the find method linked from above:
DataTemplate template = Resources["MyTemplate"] as DataTemplate;
dynamicDataForm.ContentTemplate = template;
Dispatcher.BeginInvoke(() =>
{
ComboBox button = FindVisualChildByName<ComboBox>(this, "MyControl");
if (button != null)
button.MouseLeftButtonUp += (s, _) => MessageBox.Show("Click");
});
In your case it looks like your template might need to wait to switch to an edit state before it renders in which case you'd need to hold off on connecting the event and find some other event on your dataform that happens when that state is changed.
One solution is to handle the BeginningEdit event of the DataForm and use that to subscribe your event handler to the ComboBox's MouseLeftButtonUp event.
To do this, add to your code-behind a private field named isEventWiredUp. We'll use this field to keep track of whether we've subscribed to the event and prevent the event from being subscribed to more than once.
Next, add an x:Name="..." attribute to your ComboBox. We use this name to get at the combobox.
Once that is done, add the following two methods, which should do what you want. Replace yourComboBoxName with the x:Name you gave to your combobox:
private void dynamicDataForm_BeginningEdit(object sender, CancelEventArgs e)
{
Dispatcher.BeginInvoke(OnBeginEdit);
}
private void OnBeginEdit()
{
if (!isEventWiredUp)
{
var combobox = dynamicDataForm.FindNameInContent("yourComboBoxName") as ComboBox;
if (combobox != null)
{
combobox.MouseLeftButtonUp += combobox_MouseLeftButtonUp;
isEventWiredUp = true;
}
}
}
Subscribe the first of these two methods to the DataForm's BeginningEdit event.
I have to admit that I was unable to get the MouseLeftButtonUp event to fire on the ComboBox. I'm not sure why this happens, but it seems to be a general problem with the ComboBox as opposed to something that happens because of the way you're constructing XAML. I was able to get an event handler for the ComboBox's SelectionChanged event to work, however.
I also tried replacing the Dispatcher.BeginInvoke line with a direct call to the OnBeginEdit method, but I found that this approach didn't work. The events weren't quite wired up correctly; again, I'm not sure why.
Rather than trying to hookup the event directly, you can use interactivity to bind up your events
e.g.
...
editTemplate.Append("xmlns:i='clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity' ");
...
editTemplate.Append(#"
<ComboBox>
<i:Interaction.Triggers>
<i:EventTrigger EventName='MouseLeftButtonUp'>
<i:InvokeCommandAction Command='{Binding DataContext.YourCommand,
RelativeSource={RelativeSource AncestorType=XXX}}'
CommandParameter='{Binding}'/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>");
you might have to use some ancestor binding to get to the context on which your handler is defined. I use a custom implementation of InvokeCommandAction; basically a copy of System.Windows.Interactivity.InvokeCommandAction but extended so that it will pass the event args to the command, you might want to do the same.
XamlReader.Load not allowed to attach eventHandlers in it.
so use this technique to dynamically attach the eventHandlers to it.
1- Write your Xaml string without eventHandlers -But write the Name property of those Controls.
2- Load the string with XamlReader.Load(str);
3- Then load the content of DataTemplate from it. using Grid template = ((Grid)(dt.LoadContent()));
Note: here Grid is the parent Control in DataTemplate.
4- Find the Control by Name you want to attach the Event Handler.
Button img = (Button)template.FindName("MyButtonInDataTemplate");
I hope it helps.
if I add control in Microsoft Blend 4 without set Name to this control and I want to set name to it and use it in c# how ?
example I added button using Blend in my layout but without give it a name
I want to give it a name using c# without x:Name="" in xaml
In your place I would give LogicalTreeHelper.GetChildren (this) a chance. It returns a collection of children to Window (this is a handle to Window) Reference MSDN
From there you can try to find your control.
But I think it is easier to try to rewrite the control (or look for another component) so you can have names on the children. That was your problem from the start.
Hope it helps
Gorgen
First, why in the world would you want to do that?
If you do not set a name you have no easy way of accessing the control. However you can get access to the control via relationships to other controls or events that pass a reference, for example the loaded event.
e.g.
private void Menu_Loaded(object sender, RoutedEventArgs e)
{
(sender as Menu).Name = "MainMenu";
}
Or if the control is the child of another control:
(ControlStack.Children[0] as Menu).Name = "MainMenu";
But i cannot think of anything useful that could be achieved by that...
You probably just want to get a reference to the object which you can easily store in a class member. In some cases you can also slice up your XAML using resources.
e.g.
<local:SomethingIWouldLikeToReference x:Key="SomethingIWouldLikeToReference"/>
<local:UserControl x:Name="userControl">
<Stuff>
<MoreStuff Content="{StaticResource SomethingIWouldLikeToReference}"/>
</Stuff>
</local:UserControl>
public MainWindow()
{
InitializeComponent();
MyReference = FindResource("SomethingIWouldLikeToReference") as SomethingIWouldLikeToReference;
}
Example if I have ListView Control and I want to use it to add items and remove items
Make private ListView and initialize it
ListView temp_control_List = new ListView()
then make loaded Eventhandler from Blend so it will be in VS then
private void ListView_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
temp_control_List = sender as ListView;
}
Now you can add and remove to and from the list view control from temp_control_List
I'm trying to write a silverlight application that takes in InitParams and then uses those InitParams to make a change to the Source of the MediaElement on the page. I'm trying to figure out the proper place to put my code.
I watched Tim Heuer's excellent video on InitParams, but in the video (which was for Silverlight 2), it shows the following on the Page.xaml.cs:
void Page_Loaded(object sender, RoutedEventArgs e)
{
}
I don't see Page_Loaded when I open MainPage.xaml.cs, and I'm wondering if that was automatically created in the Silverlight 2 SDK and left out of the Silverlight 3 SDK. Or perhaps Tim added that in his video manually.
I find that I can go into the opening UserControl tag of MainPage.xaml and add Loaded="<New_Event_Handler>" which creates the following in MainPage.xaml.cs:
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
}
By default, there's also the following in MainPage.xaml.cs, which is run during the Application_Startup event in App.xaml.cs:
public MainPage()
{
InitializeComponent();
}
I need to figure out where is the best place to insert my code to change the Source on my MediaElement in my xaml. Should I put it in MainPage? Should I add the Loaded event handler and put it into UserControl_Loaded? If it's supposed to be Page_Loaded, where do I find that in Silverlight 3?
Any help would be much appreciated.
"UserControl_Loaded" and "Page_Loaded" are just method names and the names don't matter (you could name the method "Foo" if you wanted). What makes these methods do anything is the fact that they are attached to the Loaded event on the UserControl (which is what you did when you edited the MainPage.xaml file).
First off, I'm new to WPF and C# so maybe the issue I have is really easy to fix. But I'm kinda stuck at the moment.
Let me explain my problem.
I have a WPF Window and two usercontrols (Controls and ContentDisplayer).
The usercontrol Controls, wich contains some buttons, is added in the XAML of the Window.
Nothing special here.
Window.XAML
<nv:Controls/>
Now, what I want to do is when a user is pressing a button in Controls, ContentDisplayer needs to be added to the Scatterview I have in my Window.
I solved the problem by adding the buttons to the Window, and not using the usercontrol Controls. But this is not what I want.
Window.XAML.CS
private static void Button_ContactChanged(object sender, ContactEventArgs e)
{
object ob = Application.LoadComponent(new Uri(
"NVApril;component\\XAML\\ContentDisplayer.xaml",
System.UriKind.RelativeOrAbsolute));
//Set a unique name to the UserControl
string name = String.Format("userControl{0}",
SurfaceWindow1_Scatterview.Items.Count);
UserControl userControl = ob as UserControl;
userControl.Name = name;
//Add the new control to the Scatterview
SurfaceWindow1_Scatterview.Items.Add(userControl);
SurfaceWindow1_Scatterview.RegisterName(name, userControl);
}
So the real question is: How do I add a usercontrol to the Window by pressing a button in an other usercontrol?
Thanks,
Toner
At the top of the window xaml add
xmlns:d="clr-namespace:SomeNamespace.Usercontrols"
where you these exist already, you can choose the namespace of your control from the intellesence list.
Then where you want to place the control type:
<d:yourusercontrolhere params />
and your usercontrols can be added there.
Within Controls expose an event that is fired when you want to add a new control.
public event EventHandler AddControl;
private void RaiseAddControl()
{
if (AddControl!= null)
{
AddControl(this, EventArgs.Empty);
}
}
Now sink that event in your Window
yourControl.AddControl += ContactChanged
In your window, it sounds like you need to add the event to the instances of Controls.
<local:ContentDisplayer>
...
<nv:Controls AddControl="ContactChanged"/>
...
Then in your ContactChanged event handler you can instantiate a new Controls control and add it to whatever collection you're using like in your Button_ContactChanged event handler above.
Let me know if you need further clarification.
I have no idea what you are trying to do your example,
So you have a control defined thus:
public partial class somecontrolname : UserControl
With your corresponding Xaml file
All you need to do to add it in code to your window is firstly you need a LayoutRoot such as Grid control in the window then just
[mylayoutcontrol].Children.Add(new somecontrolname());
Maybe I got wrong idea what you are trying to do, your example code doesn't make much sense to me, looks like you are trying to load the xaml source file