I've got standard MainWindow.xaml. Then I added some pages which I wanted to show in the MainWindow. There are some common elements for all views, for example, header text, header image, and the name of logged user. How can I set these elements on the MainWindow that will be visible when another view is shown?
Set the appropriate items in the resources.
Properties that need these values will be able to get them using DynamicResource.
But it will be much better if you implement the Solution in the MVVM pattern.
Then you won't even have such a task (to transfer data between views).
Related
I'm kind of a beginner with the WPF platform. I've done a few Windows Forms apps that were very basic and now I'm working on a much more complex app for my current work.
I'd like to implement an MVVM model, but I'm getting lost in the different articles on how to do so.
Here's a screenshot of the app interface:
The section on the left is a ListView containing 6 sections that correspond to different UserControl. I would like the section on the right to display the UserControl that corresponds to the selected Item.
Each UserControl is stored in a separate XAML file.
By looking online, I found that I should use a ContentControl in my MainWindow, but every attempt I've made has been unfruitful. I know there's more than one way to skin a cat.
Which method would you use? Do you have any concrete examples or sources where I can find how to make it work?
The only difference between UserControl and ContentControl is the OnCreateAutomationPeer method. This method is responsible for UI automation.
Although this method is rarely used in practice, it is customary to use UserControl to represent some complex data types.
A typical use for a UserControl is to retrieve data (in normal CLR types) through the data context.
And the Content property specifies (using XAML) a visual tree to represent that context.
And each such UserControl is declared as a derived type (just like a Window).
If necessary, additional properties (CLR and DP) and other members (event handler methods, for example) are added to such a UserControl.
The base class ContentControl itself and others of its successor are used somewhat differently.
The data in them goes directly to the Content property.
And their visualization is set by the data template in the ContentTemplate property.
While DataTemplate's can be quite complex, they are usually much simpler than the XAML markup of the UserControl.
And, besides the task of visualization, you cannot add additional logic (properties, fields, methods).
Here's a photo of the app interface: ...
In this UI, I don't see where the ContentControl can be applied.
On the left is a navigation bar consisting of buttons.
It is usually implemented directly in the Window from an ItemsControl or ListBox.
On the right (while an empty area) is the region for the page content.
Usually, when you click on a button in the navigation bar, the corresponding UserControl is set to this region.
At a lower level, deeper in the visual tree, for smaller elements, it is quite possible that a ContentControl is needed.
P.S. Just in case, I will clarify, in view of the comment below.
By area for pages, I do not in any way mean the use of Frame + Page.
This is a very specific pair and it is extremely rarely justified to use it.
In combination with MVVM, its use is even more difficult, since this pair does not support DataContext inheritance.
And this is the main way for the View to interact with the ViewModel.
I want to create an application where the user navigates through pages that are placed inside a frame element. The problem is that one page can have different layouts which basically provide the same functionality. There can be a few buttons or input controls more or less per layout, but they all should share the same code behind file.
In Windows Forms, I used to place all elements (the layout) on the same form and then hide/show the controls I required, but that's a very ugly solution and I was hoping that WPF provided something more convenient here.
I tried to create 2 Pages, deleted their respective .cs files and set their "x:Class" attribute to a custom .cs file, but that results in compiler errors (ambiguous calls to InitializeComponent() ).
So can I have multiple pages that share the same code?
You should move the logic from the code-behind class to a view model class. This pattern is known as Model-View-ViewModel and is the recommended design pattern to use when developing XAML based user interface applications.
There are plenty of online tutorials about it and this one should provide a good starting point for you: https://msdn.microsoft.com/en-us/library/hh848246.aspx.
Once you have understood the pattern and implemented your application logic in a view model class, you could then simply set the DataContext property of both pages to the same view model:
public Page1()
{
InitializeComponent();
DataContext = new ViewModel();
}
A code-behind class is simply a partial class, i.e. it is partial definition of the Page that you define in XAML and therefore you cannot "share" this one between several different pages.
Partial classes are just a way of splitting the definition of a class across several different source files: https://learn.microsoft.com/en-us/dotnet/articles/csharp/programming-guide/classes-and-structs/partial-classes-and-methods.
I am having a hard time getting multiple views to work against 1 viewmodel. I have read Naming Convention for Multi-View Support without getting much out of it, and have tried countless things in the process.
Just to take a simple example. Say I have a ViewModel for People residing in ShellViewModel, which basically contains a list of Person-objects. I want to display them in two different ways in my application.
What is the correct way to name the Views in this case, and how do I display both views in ShellView?
Anders is correct, there are a number of default conventions for Caliburn.Micro, one of them will locate and display <RootNS>.Views.[<ChildNS>].<ViewTypeName> for <RootNS>.ViewModels.[<ChildNS>].<ViewModelTypeName>.
In your case, for a single View (assuming the classes reside in namespaces derived from the folders):
<RootNS>.Views.PeopleView would by located and displayed for <RootNS>.ViewModels.PeopleViewModel.
For multiple views over the same viewmodel, the convention is that views of format <EntityName>.<Context> are displayed for viewmodels of format <EntityName>[<ViewSuffix>]ViewModel:
From your example, you could create a new folder named People, and inside it, create your views named Grid and List.
Your namespaces become <RootNS>.Views.People.Grid and <RootNS>.Views.People.List and, should then be located and displayed for <RootNS>.ViewModels.PeopleViewModel.
You typically then display the Views in something like a ContentControl, choosing the View you want to display by setting the cal:View.Context property. You'll either hard code the name, if the context isn't going to change in that particular control, or bind to a property which describes what state the ViewModel should be displayed as.
e.g.
<ContentControl cal:View.Model="{Binding Path=ActiveItem}"
cal:View.Context="List" />
See the Multiple Views over the Same ViewModel section.
As far as I can tell from the documentation you are referring to, you should not use View in your view name. Name your view classes People.Grid and People.List instead.
Trying to implement what I thought was a simple concept. I have a user control (view) bound to a view model which provides a list of data. I have added toggle buttons to the usercontrol and would like to allow the user to use these toggle buttons to switch out which template is used to show the data. All of the templates used for the data work, and they are very different from one another so it's not just simple changes to a single template. I'd like to get this as much in XAML as possible.
Here's what I have now:
Where the data appears I have <UserControl Template="{StaticResource ListSwitchingControlTemplate}" />
In that control template I have all "sub templates" - really it's just all 3 representations with their visibility set to Collapsed. Then I use a data trigger on that control template to show the currently selected view. This works, but I noticed that all 3 representations get bound - they each act like they are active (and they are I guess).
I'd rather be able to truly switch the template at run time. I tried converting the containing user control to use a ContentTemplate for itself, but that just messes up all of the binding I have elsewhere. If only UserControls could use DataTriggers I'd be ok.
Any suggestions on how to cleanly go about getting this behavior. I have an idea that I'm just missing something simple.
Thanks,
Dave
you could do it via code?
http://www.switchonthecode.com/tutorials/wpf-tutorial-how-to-use-a-datatemplateselector ???
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/4fd42590-8375-46d0-b7bc-6c217df0f0ba/
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/dbbbb5d6-ab03-49a0-9e42-686fd41e0714
One way to do this would be to use a DataTemplateSelector.
Basically, you create a class that inherits from DataTemplateSelector and override its SelectTemplate virtual function. The return value from the function is the DataTemplate you want to use and in that function you have access to the object and its properties, which you can use to decide which template to select.
There is an example on MSDN here:
http://msdn.microsoft.com/en-us/library/system.windows.controls.datatemplateselector.aspx
I am working on a PRISM / CAL solution, but the problem may be WPF specific:
If I create one instance of an control (e.g. TextBlock) and add it as child to a StackPanel, there is no way to add it as "child" to another StackPanel (parent already set error). I kind of understand the reason (it also occurs when using the RegionManager).
But what is the suggested way if a visual control is very complex and should be created only one time and used in two places? I agree that is does not really make sense to show an identical control 2 times on the screen, but there might be cases where it is useful (e.g. an "Close All" Button).
I know that in the button case, I should just create two buttons both databound to one ICommand. But does this rule also apply with much more complex controls (always create new instances)...
I stumbled on this problem when creating a layout switcher, which creates the button list and the stack panel for each GUI seperately, but uses a static ObservableCollection of buttons as source (which causes strange bugs)..
Any ideas on this topic?
Chris
This is normally handled by templates. That is, you abstract out the data into a particular type, and associate a template with that type. Then you place the instance of that data any number of times into your visual tree and have WPF render it with the template.
In short, don't add a TextBlock to your StackPanel. Instead, add an instance of your data type (eg. Customer) and associate a DataTemplate with the Customer type. There is no way to parent the same UIElement in multiple places.
You can add your control (or collection of controls) as a resource and refer to them via binding in your controls. This will implicitly create a copy (they will be Freezable and WPF will copy them).
Generally you should be using DataTemplates as Kent suggests, but if you have a special case, this will likely work.