I need to use a different panel for a particular section/group in my ListView. How do I do that (using XAML, C#, or anything)? I already tried using GroupedStyleSelector but it didn't work (I researched about it but it turned out it's not designed for this purpose). Here's my XAML right now:
<ListView ItemsSource="{Binding Source={StaticResource cvs}}">
<ListView.GroupStyle>
<GroupStyle HidesIfEmpty="True">
<GroupStyle.Panel>
<ItemsPanelTemplate>
// I want to change this for a particular group
<uwp:SGStaggeredPanel/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
I'm thinking of subclassing the panel, but the problem is how do I get a reference to the current group?
https://learn.microsoft.com/en-us/windows/communitytoolkit/extensions/listviewbase
The above article talks about a WCT goody that allows you to dynamically change the Tamplate of the item that is about to be rendered, this particular example is a statically expressed extension that simply works as an attached property to a listview and cycles through two different templates
But you can easily extend ListView into a templated control and then more easily have access to the Viewmodel that houses your Itemsource, from then you can go on to change the
private static void ItemTemplateContainerContentChanging(Windows.UI.Xaml.Controls.ListViewBase sender, ContainerContentChangingEventArgs args)
which is where all the magic takes place.
Notation for implementation
Note 0:
if you don't know mvvm and binding, forget you ever read this and go study it up instead.
Note 1:
All child controls that have no explicitly defined Data Context will inherit their parents.
Note 2:
You will be able to Map incoming controls in the aforementioned function by tracking the incoming args.ItemIndex and then cross checking it with the binded source (Observable list etc) that is housed on the underlying datacontext.
Note 3:
To convert this into a tamplated/custom control you will have to pretty much make your own implementation of ListView like this MyListview:ListView
The Dependency properties will have to be converted to conventional ones,
just type 'propdp' and double tap Tab, to bring up the default tamplate.
You will still have to reference all the different DataTamplates from XAML like its shown in the showcase app listed bellow.
Note 4:
Cut the slack off that showcase code, the stretch direction and the zebra stripes for example are not needed in your case.
https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/master/Microsoft.Toolkit.Uwp.UI/Extensions/ListViewBase/ListViewExtensions.cs
this is the exact location of the code piece i talked about, to check it out in action and play with it, Download 'Windows Community Toolkit' from the store, it is in the Extensions section.
Related
When a named XAML element is used in a WPF application, it can be accessed from anywhere. For example:
<Grid>
<Grid>
<TreeViewItem Name="itemScreen" />
The element itemScreen will be directly accessible in MainWindow(), although it is several levels deep in the XAML hierarchy.
How does WPF enable this to work in C#?
There's a mechanism called NameScope.
https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/wpf-xaml-namescopes
Simple markup you put in a window which has no templating or styling will all have the one namescope.
If you dig through that link it will explain about styles and templates in more detail. Essentially, they have their own namescope.
This is probably as far as you want to go with an explanation at this stage but there are a couple of oddities like when you "inherit" a style using basedon.
I wouldn't worry about them just yet but throw it to the back of your mind for later.
ps
That control is a private member of your window and the name doesn't have to be unique across the entire application.
I want to create a template (resource dictionary) for my app. where my type inherits the button type and I then can call it through:
<my-custom-type inherit from button>
</my-custom-type inherit from button>
And of course in WPF.
More specifically, I would like to create copies of the control in the image below with simple XAML syntax as above.
There are two approaches to this, each with their own pros and cons:
Templates allow you to reuse a section of XAML. There is (almost always) no code-behind, and you certainly won't be deriving from Button. For example, if you wanted to have a bordered text box repeated in an ItemsControl:
<DataTemplate x:Key="MyDataTemplate">
<Border>
<TextBox/>
</Border>
</DataTemplate>
Or in a button class you use ContentTemplate:
<Button ContentTemplate={StaticResource MyTemplate}>
</Button>
And you would use it as XTemplate="{StaticResource MyDataTemplate}" in an existing control that used templates. This is usually the way to go. Note that the name of the property won't be Template, but ItemTemplate, or ContentTemplate or something similar.
The exception is if you want custom behavior, in which case you use a UserControl. This technically could inherit from Button though you usually wouldn't. Subclassing a basic control should only be done if you are sure you actually want to do that. Once your user control is created, the syntax would look similar to what you have in your question:
<local:MyButton>
</local:MyButton>
Note that "local" is a made-up xmlns. Your user control would consist of whatever controls you wanted, and you can expose "attributes" to the using code via dependency properties.
Im building an application where I want to head for a design, that could remind of a dockpanel.
What I want, is having buttons in the left side (or left panel) representing different areas of the application (e.g "Milk", "Bread") and then have different "views" in the middle-panel.
What I already have tried, is making an application with a "Frontpage", and buttons changing the whole window/usercontrol - this however will not give me static areas/panels.
I do not want to use a tabcontrol with the tabtitemstrip being vertical - however it is kinda the same functionality im looking to have.
Any ideas?
Below is a picture with the wished design, to kinda give an idea of my thoughts.. Any help appreciated :)
http://s57.photobucket.com/user/RolleKn/media/wpfdesign_zps3737b014.jpg.html
If you use WPF, use ContainerControl or ContentPresenter for that.
In general, "switching Visibility On/Off" is not a good way to go. It forces the UI to create all objects, even those invisible ones, and to handle their data and events, etc.
And you need to switch it all manually.
WPF provides you with many mechanisms that can save you this. Some are smarter than others, some not.
One of the most basic mechanism in WPF is the Control and its Template property. You can replace whole your Grid+Contents+SwitchingVisibility idea with a single Control and switching its Template:
<Window.Resources>
<ControlTemplate x:Key="panel1"> ..carrots.. </ControlTemplate>
<ControlTemplate x:Key="panel2"> ..cucubers.. </ControlTemplate>
<ControlTemplate x:Key="panel3"> ..donkey.. </ControlTemplate>
...
</Window.Resources>
<Grid x:Name="LayoutRoot">
<Control x:Name="foo" />
</Grid>
Now, if you get the foo and set its .Template and set it to panel1, then the "carrots" will show up. if you set it to panel3, donkeys. And so on.
It's very powerful, but it will not be really handy due to some other things I won't cover. There are books and tutorials that explain Templates in depth. Also, this mechanism is really not designed for such task. It's the most basic one, and a good thing to know if you want to work in WPF, but there are more suitable ones here.
Second next powerful and still basic mechanism is ContentControl/ContentPresenter. They work almost in the same way (actually CC uses CP internally), so I'll skip it.
ContentControl is a smart control that knows how to automatically select a correct Template with respect to the data you are tryng to present.
So:
<Window.Resources>
<DataTemplate DataType="CarrotData"> ..carrots.. </..>
<DataTemplate DataType="CucumberData"> ..cucubers.. </..>
<DataTemplate DataType="DonkeyData"> ..donkey.. </..>
...
</Window.Resources>
<Grid x:Name="LayoutRoot">
<ContentControl x:Name="foo" Content="{Binding ..}" />
</Grid>
Note the change from 'ControlTemplate' to 'DataTemplate'.
Now, with this setting, you don't even need to switch templates manually. You just get the "foo" and set its Content to either:
a CarrotData object, that contains the carrot-related data
a CucumberData object, that contains the cucumber-related data
a DonkeyData object, that contains the donkey-related data
Once you set the data to be shown (i.e. foo.Content = carrots[5]), the ContentControl will pick the relevant template to be shown.
You can bind the Content property to just about anything. If you have some dataclass that contains carrots/donkeys and has a property CurrentThing, you can bind to it and ContentControll will switch the views automatically along with the changes to CurrentThing.
That's basics. There's much more to it, in almost any point I tried to briefly cover. For now, leave ControlTemplates. Read about DataTemplates and Bindings. Read about ContentPresenter (shows 1 template for 1 item) and ItemsControl (shows N items+templates). Then, read a little on MVVM pattern.
You will quickly see that "having everything in one Grid" and "switching Visibility" is an odd way to do it.
However, I wouldn't be fair if I didn't mention that everything has a cost included. Extensive use of templates and bindings makes your app a bit slower compared to what you could get when you do everything manually. But usually, doing it manually is just not really worth it.
How would I make an XAML layout which had bound properties and events? I'm going out of my mind.
First of all, it's for a chat application and a single room chat works fine, in the sense that I can design the layout of the application in XAML with name properties here there and everywhere in order to control it in C# but when it comes to repeating this layout multiple times because of multiple rooms, it becomes a bit of a problem. I was doing it solely by C# this lead to hundreds of lines of just defining controls and adding them to the window, and one problem with that would be the fact that name properties would collide.
I was going to go with modifying a ControlTemplate of a random control for example a Frame, but then I run into the issue of defining custom properties and events.
I just have no idea how I can do what I want to do. I've asked for help in many places to no avail.
I am honestly going out of my mind, and on the verge of giving up entirely.
My aim is to have a tabcontrol with multiple rooms, I need to be able to access controls in each room with ease so I can modify the content. I'm just getting no where.
Edit
Public chat template is obviously different to the private chat template, hence why I've failed so badly at this.
You can do it using MVVM pattern which is preferable when dealing with WPF.
However, this requires some experience and a lot of mind-warping.
Luckily, you can always use classic approach if you are coming from the Windows Forms world.
Just create an user control for the chat room which contains GUI, data, logic, event handlers, ...
Place instances of this chat room user control inside tab container and you are done.
Sounds like a perfect place for a data template!
First off, you need a "ChatRoom" class that contains all the state information for a given room. Then your main ViewModel needs to have a collection of these objects. Finally, set up your tab control with a DataTemplate that is probably nearly identical to your current window.
The TabControl would look like:
<TabControl ItemsSource="{Binding ActiveRooms}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
... (All your chat room stuff)
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
That way, whenever you create a new room (ActiveRooms should be an ObservableCollection, by the way) it automatically a new set of controls and binds them to the new room's instance properties.
I am currently customizing a ListBox. With that I mean adding an image-element, second line-element etc. to one listItem.
The itemSource is a List in C#, therefore I have no preview of the items in Expression Blend/VS. And that's the pain.
Because I have always to edit the XAML and then deploy to check. And this goes on and on until the last pixel is correct.
Isn't there a way, of editing a ListBox with custom items (with a dynamic itemSource) live in Blend/VS?
That would really fasten up my developing.
If you want to see how your controls look like in design time, you must use SampleData. There are several ways to do it, it depends on your framework.
Let's say you have a page named MainPage.xaml. If you don't have view model already, create a new one and name it MainViewModel.cs. Define all public properties that will be used for binding.
Once you have your view model, create new file in a folder named SampleData and name it MainViewModelSampleData.xaml.
Now, in the MainPage.xaml add the following attribute to the page element:
d:DataContext={d:DesignData Source=SampleData/MainViewModelSampleData.xaml}
Also set Build Action for MainViewModelSampleData.xaml to DesignData.
Now, if you want to display data in your MainPage, you need to define all properties in the sample data file. For example:
// view model contains public properties Title of type string and Children of type
// PersonViewModel which contains properties Name and Age (string and int respectively)
<local:MainViewModel xmlns:local="clr-namespace:myapp"
Title="Title">
<local:MainViewModel.Children>
<local:ChildViewModel Name="John" Age="31" />
</local:MainViewModel.Children>
</local:MainViewModel>
You should now see your page filled with data in your design view. This way by using MVVM you can create mock data quickly. That will ensure that you can design your view around existing data without running the application.
Read more on the following links:
31 Days of Mango | Day #18: Using Sample Data
Modify sample data
Generate sample data
Using Blend Sample data at Design time and real data at Runtime
I now know how to do that.
If anyone if you guys ever stumble upon this problem, do this:
Copy all the XAML you wrote in the stackpanel of your itemtemplate
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
//...
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
And copy it up to <ListBox> //Here </ListBox>
There you can edit it in the designer.
And when you're done, just copy the code back to the StackPanel.