I am new to XAML and C#
I have an icon created already in a project and and I have to use this icon whenever I select one of the option from the dropdown menu.
I made a stackpanel in XAML file
<StackPanel Name="stackPanelforIcon">
</StackPanel>
In the code behind file I have different cases for the dropdown menu.
case IconOnSelect:
?????? = IconList.NewIcon;
This NewIcon is the one already created and I am using the source also for this
using IconProject.Iconlists;
On writing IconList.NewIcon I am not getting any error, it is referenced correctly.
What should I write at ?????? to reference it. Is there any other way apart from using stackPanel to include an icon
A StackPanel cannot show an icon on it's own. You need a control for it, for example an Image.
<StackPanel Name="stackPanelforIcon">
<Image x:Name=theImage" />
</StackPanel>
Then you can use your Icon in your code behind like this:
this.theImage.Source = IconList.NewIcon;
You may need to convert your value, you never said what type it actually is.
Please note that using code-behind is not the preferred way with WPF. Using MVVM is way easier and more natural working with WPF, using code-behind you will fight WPF all the way. Using MVVM, this could be:
<StackPanel Name="stackPanelforIcon">
<Image Source="{Binding CurrentImage}" />
</StackPanel>
with your ViewModel having a property called CurrentImage that you would set when you want to change it. Don't forget to implement INotifyPropertyChanged for the changes to take effect though.
Related
I am fairly new to WPF and have two questions?
Question #1:
From my XAML snip below, by button "btnRed" word's fine with my code behind. When the button is clicked, the proper view is display. However, how does one perform the same thing "programmatically"? Hence, my next question.
Question #2:
I am not sure how to make a "textbox" and "button" work together to perform the same action. What I'm trying to do is this. (1) I would like the textbox to be linked to the "DataContext" of the button, "btnDisplayView". (2) so when I type in, say, "RedView" into the textbox and click the button, the correct view is displayed.
My long term goal is to have a database, with a couple of tables. A table for "MenuItems" and a table for "Views". Instead of using buttons, I'll use the menu control. Then once a menu item is selected, it would display the correct view.
But for now, I'm startings small and trying to keep it simple:
--------- WPF - XAML START ---------------------------
<StackPanel Grid.Column="0" Orientation="Vertical">
<TextBox x:Name="txtDisplayView" Height="23" Margin="5" TextAlignment="Center"/>
<Button x:Name="btnDisplayView" Content="Display" Margin="5" Click="btnDisplay_Click"/>
<Button x:Name="btnRed" Content="Red" Margin="5" DataContext="RedView" Click="Red_Click"/>
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Vertical">
<ContentControl Margin="5" Content="{Binding}"/>
</StackPanel>
-----------WPF - XAML END -------------------------
If someone could show me how to get this to work, it would help me move my project in the right direction and would be greatly appreciated.
What you need here is:
Create a property in your DataContext that represents the selected item
Bind that property to your TextBox element
Now, you have two options. One is "WPF Friendly" and the other is more Windows Forms-ish:
Create a command (take a look at this article) that reads a parameter, which will be binded to the property you created before
On the Click event, you can read the binded property value
I personally prefer the first solution. Why? Because when you change it to a Menu, for example, your work will be only to populate the menu with your list items (the MenuItem class also has a Command property, so the implementation is the same as with a Button). You will only need to change the source!
I'm trying to get the functionality to tab to the next text box once the user has input their data for the previous text box. For example, once they filled in a company name I'd like to be able to hit Tab and set the focus on the next text box "Job Name". Is this done in the code or the form properties?
Here is some of my code. I'm unsure how to nest a KeyEventsArgs within these, which is how I've seen others set the focus to the next text boxes using the KeyPress function.
private void textBox1_TextChanged(object sender, EventArgs e)
{
CompanyName = textBox1.Text;
textBox1.AcceptsTab = true;
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
JobName = textBox2.Text;
textBox2.AcceptsTab = true;
}
From the question you've asked and the code sample provided, there seems to be somewhat of a disconnect between your approach and the desired functionality.
As you would like the user to be able to use the Tab key in order to shift keyboard focus between elements in the window, you need only provide a TabIndex attribute on each of your TextBox controls. There is no need to use the TextChanged events to achieve this and it can be done completely in XAML for simplicity's sake.
From how I interpret your question, your next follow-on will likely be:
How do I initially give focus to a control when the application
starts?
To address this, there are a couple of alternatives available, simplest of which comes in the form of the FocusManager, which again I've illustrated usage of in XAML.
For convenience, here is a XAML-only implementation with TabIndex and FocusManager implemented:
<Window x:Class="tab_navigation.MainWindow"
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"
xmlns:local="clr-namespace:tab_navigation"
mc:Ignorable="d"
Title="MainWindow" ResizeMode="NoResize" SizeToContent="WidthAndHeight" FocusManager.FocusedElement="{Binding ElementName=TbxCompanyName}">
<Grid Margin="10">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Vertical" Margin="0,0,0,10">
<Label Content="Company Name:" Target="{Binding ElementName=TbxCompanyName}" />
<TextBox Name="TbxCompanyName" TabIndex="0" Width="160" HorizontalAlignment="Left"/>
</StackPanel>
<StackPanel Orientation="Vertical">
<Label Content="Job Description:" Target="{Binding ElementName=TbxJobDescription}"/>
<TextBox Name="TbxJobDescription" TabIndex="1" Width="160" HorizontalAlignment="Left"/>
</StackPanel>
</StackPanel>
</Grid>
Give me a shout if you need any further help, although I would strongly recommend checking out some of the MSDN resources first, particularly those concerning Focus
UPDATE: In response to comment regarding implementing the solution,
WPF has a different design and best practices from that of WinForms.
I would strongly make the case that you cease using Forms and instead use a Window or UserControl derived class in place of a Form in your WPF project unless there is a very, very good reason for doing so. If you continue to use a Form inside of your WPF project, you will indeed need to implement your own keyboard navigation logic inside that form, and bridge various other gaps you'll inevitably run into when trying to get a Form behave in a commonly acceptable way.
I'll instead show you how you can achieve your request using an objectively better and more suitable approach in WPF-only, using Window or UserControl elements. There is also a complete solution zip downloadable here.
WPF is by design a lot more modular than WinForms and splits the areas of concerns nicely by default, although most developers implement a design pattern ontop of this; MVVM is the current darling of WPF, and does add quite a lot of value to a project, although it is outside the scope of your question, so I shall instead address the question itself on the grounds of how to achieve the request in its most basic forms. Do please be aware though that this is not the entirely ideal solution and I would strongly recommend you learn and implement the MVVM pattern for WPF if you are not already familiar with it.
With that disclaimer out of the way, instead of using a Form in WPF, its more useful for us to make a class which derives from Window. An even more common scenario in WPF would be that you would want to have a single window whose content changes between different views, rather than say creating multiple windows, although again that is outside the scope of the question and would rely upon reading into Binding and MVVM. I'm going to be showing you a quick and easy way to get the functionality you've asked for, I'm just trying to iterate here that this is not the norm almost all of the time.
To make a working solution, do the following to your project:
Right click your project in the solution explorer (presuming you are using Visual Studio)
'Add' a 'New Item...'.
Choose the 'Window (WPF)' template and name it. I'm going to call it CustomerInformationEntry from here out.
Open the CustomerInformationEntry.xaml file that has been created for us, remove the <Grid></Grid> tags and copy/paste this excerpt from the XAML I've already provided from above in their place:
<Grid Margin="10">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Vertical" Margin="0,0,0,10">
<Label Content="Company Name:" Target="{Binding ElementName=TbxCompanyName}" />
<TextBox Name="TbxCompanyName" TabIndex="0" Width="160" HorizontalAlignment="Left"/>
</StackPanel>
<StackPanel Orientation="Vertical">
<Label Content="Job Description:" Target="{Binding ElementName=TbxJobDescription}"/>
<TextBox Name="TbxJobDescription" TabIndex="1" Width="160" HorizontalAlignment="Left"/>
</StackPanel>
</StackPanel>
</Grid>
Add FocusManager.FocusedElement="{Binding ElementName=TbxCompanyName} to the Window element in CustomerInformationEntry.xaml.
This is our view or visual representation finished with now, and all that remains is to instanciate a new CustomerInformationEntry from our other Window or UserControl, and to then display it. In this case I'm going to be putting a button onto the MainWindow.xaml, and providing it a click event which will create the instance of our new Window:
In MainWindow.xaml add <Button Name="BtnOpenCustomerInformationEntry" Content="Enter Customer Information" Click="OpenCustomerInformationEntry"/>. In my case I'll be adding the button inside my object, although you can put it wherever you like if you've already created your initial window.
In MainWindow.xaml.cs we'll add a new private method which will be used by the Click event of your new button. Adding the following code:
private void OpenCustomerInformationEntry(object sender, RoutedEventArgs e)
{
CustomerInformationEntry myWindow = new CustomerInformationEntry();
myWindow.Show();
}
That's it, you now have a button in your MainWindow.xaml which when clicked uses the OpenCustomerInformationEntry method defined in MainWindow.xaml.cs, which in turn makes an instance of your CustomerInformationEntry window and displays it.
If you would still rather stick with the Forms approach, you can do that by using WindowsFormsHost, usage of which is discussed here.
Best Regards,
JC
In my WPF app we are using an adorner for displaying validation messages, in the particular case there is a single row grid that has multiple controls some of which have validation. The problem I'm having is that I want to force the width of the error message control to be the same as the grid but can't seem to find a way to reference that grid from the adorner template. Here is a sample of what I tried:
<ControlTemplate x:Key="Local_TopAdornedTemplateWide">
<StackPanel>
<AdornedElementPlaceholder x:Name="adornedElement"/>
<TextBlock MaxWidth="{Binding Path=ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType=Grid}, ElementName=adornedElement}"
TextWrapping="Wrap"
Text="{Binding Converter={StaticResource Local_ValidationErrorMessageConverter}}"
Style="{DynamicResource Error_Text}"
Padding="2 1 0 0"
Visibility="{Binding ElementName=adornedElement, Mode=OneWay, Path=AdornedElement.IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
/>
</StackPanel>
</ControlTemplate>
This causes the application to crash with an XamlParseException.
Ideally the solution would not be specific to a grid so that it would get the width of any container type, but for now grid is the only use case.
Edit:
Here is an example of another template we use in the application; this template would not work for my case as it would limit the error to be the width of a single column of the aforementioned grid:
<ControlTemplate x:Key="Local_TopAdornedErrorTemplate">
<StackPanel>
<AdornedElementPlaceholder x:Name="adornedElement"/>
<TextBlock MaxWidth="{Binding ElementName=adornedElement, Path=ActualWidth}"
TextWrapping="Wrap"
Text="{Binding Converter={StaticResource Local_ValidationErrorMessageConverter}}"
Style="{DynamicResource Error_Text}"
Padding="2 1 0 0"
Visibility="{Binding ElementName=adornedElement, Mode=OneWay, Path=AdornedElement.IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
/>
</StackPanel>
</ControlTemplate>
Using snoop I captured the following two screenshots (I could not take one of the full stack to prevent posting anything proprietary)
This shot shows the grid I mentioned previously, within this it is the FinancialTextBox item that is being adorned
This shot shows two things, the item selected in blue is the highest ancestor of the grid in the previous shot, the yellow highlight is the Textbox from the content template
With those two it seems to be apparent that (based on information from Contango's answer) the two items aren't not in the same visual tree which would lead me to believe my question is not possible. However the second template I added (which does work) points that at least some visual information from the adorned element lives on in the place holder.
So now my question boils down to a) does this information include the parent of the adorned element and b) how can this be accessed via a binding on a different element?
This ended up being a lot simpler than the path I was trying to go down.
I was doing some reading on the AdornedElementPlaceholder class and came across this entry on MSDN and noticed that the class actually has a property called parent, with that I tried the following binding and it works perfectly:
MaxWidth="{Binding ElementName=adornedElement,
Mode=OneWay,
Path=AdornedElement.Parent.ActualWidth}"
WPF is quite powerful and flexible.
You can bind any property in any XAML tag to any property in any other XAML tag.
For example, you could write a test app that binds the Text property of an input box to the Text property of a label, so as you type something into the text box, the label would change automatically (assuming you use UpdateSourceTrigger=PropertyChanged). This is a direct XAML to XAML binding, with no C# in sight.
Similarly, you could bind the width of your error box to the width of the parent control, whatever that may be.
Google RelativeSource and AncestorType, this is a great link:
http://druss.co/2013/10/wpf-binding-examples/
See if you can grok how the Visual Tree and Logical Tree works in WPF, once you understand that, you will understand more of how binding works.
I'd also recommend using the free tool Snoop to look at the Visual Tree. XAML Spy is excellent, but not free.
Snoop can tell you if there is anything that has a bad binding at runtime (you set the filters up, and it will list all bad bindings).
You can use Snoop to get the full XAML path of your source (the XAML you wrote above), then get the full XAML path of the target (i.e. the ActualWidth of your Grid), then compare them: it may be quickly apparent that one is not the ancestor of the other, as they are on different branches of the visual tree, or that there is some other issue which is preventing a simple walk up the visual tree from working.
If you just want to get something working, as a proof of concept, try naming the target XAML grid using x:Name, and reference it by name instead of AncestorType.
I have a simple question. I want to add an icon to a C# WPF Button control. I do not want to have to write C# code, or edit XAML to do this.
However, when I click on the button in the Designer, there is no option under properties to set an image. How do you do this through the Visual Studio GUI?
The easiest/best way to do this is to add an Image control as the Content of the Button.
The property window is somewhat limited in what it can do, and only supports text for that property. This does include bindings, so you could use an Image StaticResource. I couldn't find an easy way to create one from the property designer either though.
So basically, you are stuck with editing XAML. Either with a direct Content property or by creating an element in Resources Its not that bad! Just write:
<Button>
<Button.Content>
<Image ImageSource="..."/>
</Button.Content>
</Button>
Now of course, you could create a custom button that exposed that property via the designer, but thats even more XAML. Its WPF, you are going to have to write XAML, so learning how should be a priority.
Visual Studio 2015:
create a button.
create an image.
set the source of the image to the right file of your resources (e.g. a .png file that you included to your project)
drag the image over the button.
A text shows that asks you to press ALT to replace the text of the button with the image.
I currently don't know how to get both, image and text, for a button.
in XAML, it looks like this:
<Button x:Name="button12" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75">
<Image x:Name="image" HorizontalAlignment="Left" Height="24" VerticalAlignment="Top" Width="24" Source="gfx/new.png"/>
</Button>
you could install FontAwesome on your Computer
Goto http://fontawesome.io and download. Open the downloaded ZIP file and inside the font folder there should be .otf file, Install that!
and in the content of the button you could simply type the desired icons code!
For eg:
if you want your button to look like this
then install FontAwesome Font
and in your button tag type Content="" FontFamily="FontAwesome"
More codes can be found here http://fontawesome.io/cheatsheet/
I have a treeview at the left side of the screen, and when I click on any of the TreeViewItem, I want the right side of the screen to change accordingly.
For example, clicking on 'Project' would display on the right half of the screen, a label for project name along with the project name in a text box, and a similar label-textbox pair for some other fields. Clicking on a sub-option of 'Project' such as 'Task 1' should change the right half of the screen such that instead of labels and textboxes for project name and details, it should now be for task name/details. Atm, I only care about label-textbox pairs but in the future I'll need some more sophisticated options, maybe buttons and tables.
What I thought of was to have a grid premade for each option, when I clicked on 'Project' there would be a grid which displays all the info for a Project. And when I then clicked on 'Task 1', the Project grid should be hidden and the Task grid should be displayed with the fields filled out.
Is this possible? What should I be using to create templates that I can then choose from?
Firoz already mentioned the important bit. A rough guess is that you're not using MVVM pattern, so to minimize the adaption effort, you could add a Content Control to your window and set the content of this control whenever a selection is made. You can put any User Control in there.
Using MVVM would mean you bind that Content Control to a property on your ViewModel (of type UIElement or UserControl) and set an instance whenever a bound selected values changes. Speaking of selected Value, I think the default TreeView is not really Binding-friendly, so you might end up with behaviours that do the binding for you.
What you are asking to do is quite easy and possible, but I don't think you are thinking quite big enough.
As your project grows and the number of different things that you want to show expands, then you are going to need to show and hide more and more controls. This is quite quickly going to get unmanageable. Instead think about some other controls deal with this, in some ways you are doing something very like a tabbed dialog, just with a hierarchical set of tabs.
A tabbed dialog has a panel and a set of tabs, when you click on each tab, the content of the panel changes. In fact you can create UserControls one for each specialised set of UI that you want to display, e.g. you could have a ProjectControl that displays all of your project textboxes, labels, buttons etc.
In addition WPF has this neat feature called DataTemplates, these define how a type of data should look when it is displayed. So if you where to have a
public class MyProject
{
public string Name {get;set;}
}
Then you could define
<DataTemplate DataType="{x:Type MyProject}>
<TextBox Text="{Binding Name}"/>
</DataTemplate>
And WPF will automatically convert the data into to its visual form if you set it as the content of the tab panel.
However this type of displaying content in a panel is not the only WPF control that does this. There is also something called a NavigationFrame, which also can be used wrapped into a Window as a NavigationWindow. This control provides you ways to navigate to the next Page to display. Pages can be just like the UserControls in a tabbed dialog, but can also be URIs, enabling you to link in content from the web if you wish. In addition you can call NavigateTo from other controls enabling you build much more usable interfaces.
I worked through the process of building a full windows control panel style interface in
http://alski.net/post/2012/01/11/WPF-Wizards.aspx
and http://alski.net/post/2012/01/13/WPF-Wizards-part-2-Glass.aspx
I've added later VS2012 style glows in
http://alski.net/post/2013/09/14/WPF-Re-creating-VS2012Office-2013-window-glow.aspx
And then released the entire source code as open source at
http://winchrome.codeplex.com/
This comes with support for embedding Navigation panels with
<WinChrome:SearchableNavigationWindow
x:Class="WinChrome.Win7Demo.MainWindow"
...
xmlns:WinChrome="clr-namespace:WinChrome;assembly=WinChrome"
Style="{StaticResource Win7NavigationWindow}">
<WinChrome:SearchableNavigationWindow.Navigation>
<view:Navigation x:Name="navigationTree"/>
</WinChrome:SearchableNavigationWindow.Navigation>
(Full source code)
Where the navigation window is embedded as, but can also be a TreeView.
<UserControl x:Class="WinChrome.View.Navigation" ...>
<ScrollViewer HorizontalScrollBarVisibility="Disabled" Padding="12,0"
VerticalScrollBarVisibility="Auto" >
<StackPanel>
<Button
Margin="0,12,0,0" Style="{StaticResource LinkNavigatorButtonStyle}"
Content="Home"
Command="{Binding
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Win7Demo:MainWindow}, AncestorLevel=1},
Path=GoHomeCommand}" />
</StackPanel>
</ScrollViewer>
(Full source code)