I'm new in WPF and C#. I know a lot of VB.NET and I'm used to the way when I call a form object like textboxes, etc. I'm calling it from another form. Now, I'm using WPF, I'm confused. Because I have a Main Window. And I want to add and item to a listbox in the Main Window from a Class. In VB.Net , its just like this.
IN FORM2
Form1.Textbox.Text = "";
Wherein I can't do it in WPF. Can someone please Help me. Thanks!
WPF windows defined in XAML have their controls publicly accessible from other classes and forms, unless you specifically mark them with the x:FieldModifier attribute as private.
Therefore, if you make an instance of your main window accessible in another class, be it a Window or anything else, you'll be able to populate controls from within this second class.
A particular scenario is when you want to update the contents of a control in your main window from a child window that you have opened on top of it. Is such a case, you may set the child window's Owner property to the current, main window, in order to access it while the child is visible. For instance, let's say you have defined these two windows:
// MainWindow
<Window x:Class="TestApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox Name="mainListBox" Height="250" HorizontalAlignment="Stretch" VerticalAlignment="Top"/>
<Button Content="Open Another Window" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="20" Click="OpenAnotherWindow_Click"/>
</Grid>
</Window>
and
// AnotherWindow
<Window x:Class="TestApplication.AnotherWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="AnotherWindow" Height="300" Width="300">
<Grid>
<Button Content="Add New Item to Main Window" HorizontalAlignment="Center" VerticalAlignment="Center" Click="AddNewItem_Click"/>
</Grid>
</Window>
each in its own XAML file.
In MainWindow's code behind, inside the button click handler, you show an instance of AnotherWindow as a dialog and set its Owner property to MainWindow's instance:
private void OpenAnotherWindow_Click(object sender, RoutedEventArgs e)
{
AnotherWindow anotherWindow = new AnotherWindow();
anotherWindow.Owner = this;
anotherWindow.ShowDialog();
}
Now, you can access the MainWindow's instance from AnotherWindow's Owner property, in order to add a new item to the ListBox control defined on it, in the button click handler in AnotherWindow's code behind:
private void AddNewItem_Click(object sender, RoutedEventArgs e)
{
MainWindow mainWindow = Owner as MainWindow;
mainWindow.mainListBox.Items.Add(new Random().Next(1000).ToString());
}
It simply adds a new random number to the ListBox, in order to show how the code accesses and modifies the control's data in MainWindow.
Pure WPF solution, but also may be easiest in your case, is using a Data Binding in WPF.
Every form's control is binded to some data on ModelView (pure MVVM approach) or to data (more or less like yuo can do it in WindowsForms). So the "only" thing you have to do is to read/write data binded to controls on UI of that form.
For example, you have TextBox on Windows and want to read a data from it.
This TextBox is binded to some string property of the class that is responsible for holding the data for the controls on that form (just an example, in real world could be 1000 other solutions, based on developer decisions). So what you need, is not to say: "window give textbox" and after read TextBox's content, but simply read binded string property.
Sure it's very simply description of a stuff. But just to give you a hint. Follow databinding link provided above to learn more about this stuff. Do not afraid of a lot of stuff there, it's after all is not a complicated idea and also pretty intuitive. To make that stuff to work in simply case you will not need to make huge efforts by me. The stuff becomes really complex when you end up into real world applications.
This will get all active windows:
foreach (Window item in Application.Current.Windows)
{
}
Related
I have a WPF application, which uses User Settings, and binds it to a <TextBox> like this:
<Window x:Class="SampleApp.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"
mc:Ignorable="d">
<Grid>
<TextBox x:Name="textbox" Text="{Binding Source={StaticResource Settings}, Path=Default.Folder}"/>
</Grid>
</Window>
The App.xaml looks like this:
<Application x:Class="SampleApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:SampleApp.Properties"
ShutdownMode="OnExplicitShutdown"
Startup="Application_Startup">
<Application.Resources>
<properties:Settings x:Key="Settings"/>
</Application.Resources>
</Application>
And here's the App.xaml.cs:
public partial class App : Application
{
public App()
{
}
private void Application_Startup(object sender, StartupEventArgs e)
{
new MainWindow().ShowDialog();
}
}
This works really great one way: My TextBox always displays the content of MySetting when the window is shown.
The other way around doesn't quite work as I intend. What does work, is when the user manually writes into the TextBox.
What doesn't work, is when I programmatically make changes to the TextBox, like this:
textbox.Text = folderBrowserDialog.SelectedPath;
In this case, MySetting doesn't update until the user types into the TextBox.
My current solution is to do this:
Properties.Settings.Default.MySetting = textbox.Text;
But it defeats the point of having a two-way data binding.
What should I do to have data binding work both ways, even when I'm programmatically changing the user control?
But it defeats the point of having a two-way data binding.
No, not really.
The point of two-way binding is so that when the code modifies the source property the UI's target property is updated, and when the user modifies the target property, the source property is updated.
Two-way binding is definitely not there so that you can assign a value programmatically to the target property and have it reflected in a source property that you could have and should been setting instead.
It should be very rare for someone writing WPF code to ever have to name or interact with a UI element defined in XAML. And when that does happen, it should be only to implement user interface features, such as drag-select, drag & drop, key handling, etc.
Putting it another way: in the MVVM paradigm, the view model data structure is the only thing that non-UI code ought to be dealing with. The binding mechanism provides the mediator between the business logic, represented by the view model (and optionally, a model behind that), and the user interface, represented by the XAML.
Indeed, typically if you were to set the target property explicitly, it would discard the binding, causing it to not work at all.
So, the right way to do this is, in the code-behind, to only ever interact with the MySetting property. If you want to update the value shown to the user, then you need to change the code-behind property that is bound to that value.
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
So iv looked around for a bit and found out that MDI is obselete for WPF, Basically what i am trying to do is show a specific page in a grid object on load, and once a menu item from my drop down menu is selected, the content of the grid will be changed to the content from a different page (this is depending on which menu item is selected).
To go into more detail (perhaps this will help) The area where the window will be shown will need to have the window with no borders, or titles, or buttons to minimize/close etc.. only showing the content of this window, it won't be resizeable but fixed, i have a menu of which as i said earlier, when a different menu item is clicked, the relevant window should be displayed in the fixed area. Additionally if any buttons or events inside this content that is displayed happen (i.e a button causes a different window to show for example) then the content in the fixed area should be replaced by this new window's content
This is the first time i have done something like this and from what i've read it sounds like this is something very tricky for a WPF application, I hope i can get some sort of insight or direction i should be going so that i can make this possible.
Thanks.
You can try for example ChildWindow from Extended WPF Toolkit Community Edition.
Edit #1:
But whenever i try to create a WindowContainer in the Xaml it has
problems with the namespace prefix with "xctk:WindowContainer" so
how do i create the appropriate namespace prefix to use it?
You have to add that namespace:
xmlns:xctk=http://schemas.xceed.com/wpf/xaml/toolkit
For example:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
Title="MainWindow" Height="350" Width="525">
<Grid>
<xctk:WindowContainer>
<xctk:ChildWindow Height="100" Width="250" Left="10" Top="10">
<TextBlock Text="Hello World ..." />
</xctk:ChildWindow>
</xctk:WindowContainer>
</Grid>
</Window>
Edit #2:
You can of course change some properties (for example):
<xctk:ChildWindow
Height="100"
Width="250"
Left="10"
Top="10"
Name="chWindow"
CloseButtonVisibility="Hidden"
WindowStyle="None"
BorderThickness="0">
Edit #3:
Ok yeah, so with everything referenced it is giving me errors still..
Try it simpleā¦ Create Wpf Application, add Extended WPF Toolkit 2.4 NuGet package, in MainWindow.xaml add previous code and in MainWindow.xaml.cs add next code:
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
this.chWindow.Show();
}
}
}
I am currently writing a desktop application, but I cannot seem to get my head around what to use when redirecting someone to a new section of the application.
My options appear to be
Window
Page
UserControl
but I don't understand what the difference between them is, and when I should use each one.
Could someone explain the differences for me, and give an example of what situations/applications you may use each one for?
A Window object is just what it sounds like: its a new Window for your application. You should use it when you want to pop up an entirely new window. I don't often use more than one Window in WPF because I prefer to put dynamic content in my main Window that changes based on user action.
A Page is a page inside your Window. It is mostly used for web-based systems like an XBAP, where you have a single browser window and different pages can be hosted in that window. It can also be used in Navigation Applications like sellmeadog said.
A UserControl is a reusable user-created control that you can add to your UI the same way you would add any other control. Usually I create a UserControl when I want to build in some custom functionality (for example, a CalendarControl), or when I have a large amount of related XAML code, such as a View when using the MVVM design pattern.
When navigating between windows, you could simply create a new Window object and show it
var NewWindow = new MyWindow();
newWindow.Show();
but like I said at the beginning of this answer, I prefer not to manage multiple windows if possible.
My preferred method of navigation is to create some dynamic content area using a ContentControl, and populate that with a UserControl containing whatever the current view is.
<Window x:Class="MyNamespace.MainWindow" ...>
<DockPanel>
<ContentControl x:Name="ContentArea" />
</DockPanel>
</Window>
and in your navigate event you can simply set it using
ContentArea.Content = new MyUserControl();
But if you're working with WPF, I'd highly recommend the MVVM design pattern. I have a very basic example on my blog that illustrates how you'd navigate using MVVM, using this pattern:
<Window x:Class="SimpleMVVMExample.ApplicationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SimpleMVVMExample"
Title="Simple MVVM Example" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:HomeViewModel}">
<local:HomeView /> <!-- This is a UserControl -->
</DataTemplate>
<DataTemplate DataType="{x:Type local:ProductsViewModel}">
<local:ProductsView /> <!-- This is a UserControl -->
</DataTemplate>
</Window.Resources>
<DockPanel>
<!-- Navigation Buttons -->
<Border DockPanel.Dock="Left" BorderBrush="Black"
BorderThickness="0,0,1,0">
<ItemsControl ItemsSource="{Binding PageViewModels}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.ChangePageCommand,
RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding }"
Margin="2,5"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
<!-- Content Area -->
<ContentControl Content="{Binding CurrentPageViewModel}" />
</DockPanel>
</Window>
Window is like Windows.Forms.Form, so just a new window
Page is, according to online documentation:
Encapsulates a page of content that can be navigated to
and hosted by Windows Internet Explorer, NavigationWindow, and Frame.
So you basically use this if going you visualize some HTML content
UserControl is for cases when you want to create some reusable component (but not standalone one) to use it in multiple different Windows
All depends on the app you're trying to build. Use Windows if you're building a dialog based app. Use Pages if you're building a navigation based app. UserControls will be useful regardless of the direction you go as you can use them in both Windows and Pages.
A good place to start exploring is here: http://windowsclient.net/learn
We usually use One Main Window for the application and other windows can be used in situations like when you need popups because instead of using popup controls in XAML which are not visible we can use a Window that is visible at design time so that'll be easy to work with
on the other hand we use many pages to navigate from one screen to another like User management screen to Order Screen etc In the main Window we can use Frame control for navigation like below
XAML
<Frame Name="mainWinFrame" NavigationUIVisibility="Hidden" ButtonBase.Click="mainWinFrame_Click">
</Frame>
C#
private void mainWinFrame_Click(object sender, RoutedEventArgs e)
{
try
{
if (e.OriginalSource is Button)
{
Button btn = (Button)e.OriginalSource;
if ((btn.CommandParameter != null) && (btn.CommandParameter.Equals("Order")))
{
mainWinFrame.Navigate(OrderPage);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
That's one way of doing it We can also use a Tab Control instead of Fram and Add pages to it using a Dictionary while adding new page check if the control already exists then only navigate otherwise add and navigate. I hope that'll help someone
Most of all has posted correct answer. I would like to add few links, so that you can refer to them and have clear and better ideas about the same:
UserControl:
http://msdn.microsoft.com/en-IN/library/a6h7e207(v=vs.71).aspx
The difference between page and window with respect to WPF:
Page vs Window in WPF?
I am working on my first project in MVVM and I've chosen to use the MVVM Light Toolkit. I have a GameViewModel that handles business on the main screen of my game. I need to find out how to open a new window (AdventurerView) with an instance of Adventurer as a parameter when a command is executed, have it bound to AdventurerViewModel, and display and return data. Instances of this window will be opened and closed frequently. I have been stuck on this for a couple of days now and it's driving me crazy. I would like to learn how to do this in an MVVM-friendly way, preferably with the tools provided by MVVM Light or pure XAML.
I've tried using MVVM Light's ViewModelLocator but since AdventurerView is a window it won't work; it says "Can't put a Window in a Style", though the program still compiles and runs. Could there be something I could change to make that work? Or is there another way to bind them in XAML? Or another approach entirely? I would really love to be able to move on from this. I have also tried using MVVM Light's messenger to no avail (which still doesn't tackle the View/ViewModel issue).
I just need to be able to create a window that is bound to AdventurerViewModel and display/return the appropriate data.
AdventurerView.xaml is in its default state at the moment, but I feel that if I could bind the appropriate data that might help (DataContext).
AdventurerViewModel is pretty bare-bones as well
class AdventurerViewModel : ViewModelBase
{
#region Members
private Adventurer _adv;
#endregion
#region Properties
public Adventurer Adv
{
get { return _adv; }
set { _adv = value; }
}
#endregion
#region Construction
public AdventurerViewModel(Adventurer adv)
{
this._adv = adv;
}
#endregion
}
App.xaml with the non-working DataTemplate at the bottom:
<Application StartupUri="MainWindow.xaml"
xmlns:views="clr-namespace:AoW.Views"
xmlns:vm="clr-namespace:AoW.ViewModels"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="AoW.App"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Application.Resources>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
<DataTemplate DataType="{x:Type vm:GameViewModel}">
<views:GameView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:TitleViewModel}">
<views:TitleView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:AdventurerViewModel}">
<views:AdventurerView />
</DataTemplate>
</Application.Resources>
</Application>
The command in GameViewModel that will hopefully make this all happen (the messagebox just confirms that the command is firing):
private void ExecuteShowAdvCommand(Adventurer adv)
{
System.Windows.MessageBox.Show(adv.Name);
}
I don't really know what else to include.
Ok I put together a demo that should make this hopefully easier for you Download Link
Functionality:
3 Windows in Total (MainWindow, ModalWindow, NonModalWindow)
MainWindow has a TextBox you can type whatever you want into.
2 buttons on the top will open the Modal / NonModal Window accordingly
Each window when opened will display the message that was in MainWindow's TextBox in a TextBlock inside them.
In each window you can tick a CheckBox to update the value in result's textblock in MainWindow (For the Modal Window this will kick in when modal window is closed. For NonModal changes can be seen asap)
That's it for functionality,
Concepts:
Registering Multiple VM's with the SimpleIoC and using GetInstance(...) to request them out.
Messenger class usage with a custom message type OpenWindowMessage
Opening Modal / Non Modal Windows from a parent VM staying true to the MVVM principles
Passing data between windows(just shown in NonModal)
Important Note:
- The method used in this example to set the non DP DialogResult from the modal window is not MVVM friendly cos it uses code-behind to set the DialogResult property on a Window.Closing event which should be avoided(If needing to be "testable"). My preferred approach is a bit long and is very well documented HERE(Mixture of question and answer). Hence why I ignored it for the sake of this sample.
Follow up to Viv, I modified the sample to include an example of opening the window without using a code behind.
Sample project is here.
I'm utilizing the ViewModelLocator singleton with a static method that news up the viewmodel and window and Data Context instead of the code behind.
Blog Post with Details.
Let me know which method is preferable. I dislike using code behind, but there could be pro's and con's I'm missing.