Unable to load XAML through XamlReader - c#

I have a WPF application. Source is here. My requirement is, if the use click the Save button, I want to capture the current window's XAML including inputs and save it to the database. After that in application, somewhere else, I need to load back that window from DB. I tried this using XamlWriter. Its working fine if I didnt name the controls in Xaml. If I add x:Name attribute in Xaml for any control, it gives exception as shown below. Please help.

if you put a Console.WriteLine(window); behind var window = XamlWriter.Save(this); like so:
var window = XamlWriter.Save(this);
Console.WriteLine(window);
you get this printed:
<MainWindow Title="MainWindow" Width="525" Height="350" Visibility="Visible" xmlns="clr-namespace:XamlReaderSample;assembly=XamlReaderSample" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation"><av:Grid><av:StackPanel Margin="0,10,0,0">
<av:TextBox Width="100" xml:space="preserve" /><av:TextBox Width="100" Margin="0,10,0,0" xml:space="preserve" />
<av:Button Name="btnSave" Width="80" Margin="0,10,0,0">Save</av:Button>
</av:StackPanel></av:Grid></MainWindow>
within this code there is a button named btnSave. in the rest of your code you try to create a new window from that code. once you try to create that window, you have a 2nd button (besides the one you did click) with that name. and that causes the error.

I tried like this and it worked.
var win = new Window();
win.Name = this.Name;
win.Content = this.Content;
var xaml = XamlWriter.Save(win);
But still I cant do like this if the window have a DataGrid in it, since DataGrid doesnt support serialization. Need to find out some other method.

Related

How do I tab between text boxes on a form in C#?

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

Open WPF Window in StackPanel [duplicate]

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?

Where to put WPF Dynamic Control Creation Code

I am just in the process of teaching myself WPF. I have reached the point of adding controls dynamically and have hit a brick wall on something really simple. I code that should create a button (shown below):
Button button = new Button() { Height = 80, Width = 150, Content = "Test" };
parentControl.Add(button);
My question is what is parentControl actually called? I am using the standard Visual Studio 2012 WPF template and my main window is called MainWindow. I have no objects in the Window besides what comes in the template
So far I have looked at:
WPF runtime control creation
Dynamic control creation in WPF
WPF MVVM Dynamic control creation
Dynamic creation of control
Where should I put WPF specific code when using MVVM?
Steps Of Control Creation Process WPF
Where to put code in (primarily) windowless WPF app?
The closest I have found it: WPF runtime control creation.
All of these questions just assume you know such a basic thing but I don't. Please help.
I think I understand your question. If your XAML code looks like:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
</Window>
Then your codebehind should be something like:
public MainWindow()
{
InitializeComponent();
Button button = new Button() { Height = 80, Width = 150, Content = "Test" };
//In case you want to add other controls;
//You should still really use XAML for this.
var grid = new Grid();
grid.Children.Add(button);
Content = grid;
}
However, I warmly suggest you to use XAML as much as you can. Furthermore, I wouldn't add controls from the constructor but I'd use the Loaded event of the window. You can add a handler to the event in codebehind from the constructor, or directly in XAML. If you wanted to have the same result as above in XAML, your code would be:
<Window
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>
<Button Height="80" Width="180" Content="Test"/>
</Grid>
</Window>

How to manipulate a window object from another class in WPF

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)
{
}

Update UI by code in WPF

I'm trying to update some user control in wpf by code, with no luck.
That's the xaml:
<UserControl x:Class="SimuladorNocs.UI.Diagram.PropertiesWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:PropertyGrid="clr-namespace:Deepforest.WPF.Controls"
>
<DockPanel>
<StackPanel x:Name="stackPanel" Width="300" Height="600" HorizontalAlignment="Center">
<PropertyGrid:PropertyGridControl Height="300" x:Name="MyPropertyGrid" />
</StackPanel>
</DockPanel>
and that's the c# code:
public void SetInstance(object obj){
MyPropertyGrid = new PropertyGridControl { Instance = obj, Height = 300 };
stackPanel.Children.Clear();
stackPanel.Children.Add(MyPropertyGrid); }
In the end, the property appers to be changing, but I was unable to see the changes in the UI. I also tried to create a new object instead of using the existing MyPropertyGrid, did not work, also tried not clearing the stackpanel without success...
What am I missing?
Thanks
stackPanel.InvalidateVisual();
Please add this at the last line.
I don't have the specified propertygrid control but it seems that the UI doesn't get updated. did you try "UpdateLayout()" on that control and on the stack panel itself ?
Swapped out the PropertyGridControl for a Label and it worked fine. I suggest you do the same. If it works, it's more a question of what the PropertyGridControl is doing wrong...

Categories