so i had the same problem as this person.. WPF: Bind Collection with Collection to a ListBox with groups
I tried to implement the suggested answer to my problem but found the error "The property 'Content' is set more than once". The only difference is id like to implement this in a User Control like so:
here is my c# code:
public class Dog
{
public int dogID { get; set; }
public String Name { get; set; }
List<Puppy> puppies { get; set; }
}
public class Puppy
{
public String Name { get; set; }
}
and this is XAML:
<UserControl x:Class="PetStore.Menu"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<CollectionViewSource x:Name="dogs" Source="{Binding}" >
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Name" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<DataTemplate x:Key="dogTemplate" DataType="Project">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
<ListBox ItemsSource="{Binding Source={StaticResource dogs}}">
<ListBox.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource dogTemplate}" />
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="Puppy">
<ListBox ItemsSource="{Binding puppies}">
<ListBox.ItemTemplate>
<DataTemplate DataType="Puppy">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>
Any help is greatly appreciated!!
You're missing the UserControl.Resources tag:
<UserControl x:Class="Tackle.View.Menu"
...>
<UserControl.Resources> <!-- You're missing this -->
<CollectionViewSource x:Key="dogs" Source="{Binding}" > <!-- Change x:Name to x:Key here -->
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Name" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<DataTemplate x:Key="dogTemplate" DataType="Project">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<!-- here goes your window content -->
The error message tells you what you did wrong: you attempted to set the Content property more than once. When you declare an element as a direct child of a control, then you are implicitly setting whichever property is specified in the [ContentProperty("...")] attribute on that control type. For ContentControl (and its subclass UserControl), that property is Content. If you want to set a different property, or add something to a collection/dictionary property, you must specify the property name. This means either using the Property="value" attribute syntax or the <Owner.Property> element syntax.
Related
I can't make the {Binding Title} in the HeaderTemplate appear.
This is the class connected to the BindingContext:
class SensorGroup
{
public string Title { get; set; }
public IList<Sensor> Sensors { get; set; }
}
XAML:
<ListView Header=""
ItemsSource="{Binding Sensors}">
<ListView.HeaderTemplate>
<DataTemplate>
<Grid>
<Label Text="{Binding Title}"/>
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
...
</ListView>
If I replace it with <Label Text="Some static text"/>, the text appears.
I have found this related question, which links to this other question. But I could not make it work. I tried:
<ContentPage.Resources>
<Label x:Key="MyTitle"
Binding="{Title}"/>
</ContentPage.Resources>
...
<Grid>
<StaticResource ResourceKey="MyTitle"/>
</Grid>
It gives me an error saying that the binding with Title cannot be found.
Sounds you like just need to do:
<ListView Header="{Binding .}"
ItemsSource="{Binding Sensors}">
That is if your ContentPage's BindingContext is set to the SensorGroup class.
The above is telling the ListView.Header to be bound to what ever the ContentPage.BindingContext is set to. That means that the ListView.HeaderTemplate controls will also use what ever ContentPage.BindingContext is set to.
Let me know if that does not make any sense.
I've been using design time XAML data for a few weeks now and it seems to work fine except for some cases such as the current one where I want a listbox to display items based on a collection view declared as a resource.
Basically I want to display a list of "Things" grouped by Category.
public class Thing
{
public string Category { get; set; }
public string Name { get; set; }
}
And then I expose this via a dummy class ListOfThings
public class ListOfThings
{
public string ListName { get; set; }
public ObservableCollection<Thing> Things { get; set; }
}
I have a dummy XAML file for the data as follows (XMLFile1.xaml)
<local:ListOfThings xmlns:local="clr-namespace:ListBoxGroupExample"
ListName="TheListOfThings">
<local:ListOfThings.Things>
<local:Thing Name="Item1" Category="Catagory1" />
<local:Thing Name="Item2" Category="Catagory1" />
<local:Thing Name="Item3" Category="Catagory2" />
</local:ListOfThings.Things>
In the window I have a listbox with a group style for an expander for each group
<Window x:Class="ListBoxGroupExample.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:local="clr-namespace:ListBoxGroupExample"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="525"
Height="350"
d:DataContext="{d:DesignData Source=/DesignData/XMLFile1.xaml}"
mc:Ignorable="d">
<Window.Resources>
<CollectionViewSource x:Key="GroupedData" Source="{Binding Path=Things}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Category" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
<Grid>
<StackPanel>
<ListBox ItemsSource="{Binding Source={StaticResource GroupedData}}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True">
<Expander.Header>
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}" />
</Expander.Header>
<ItemsPresenter Margin="5,0,0,0" />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListBox.GroupStyle>
</ListBox>
</StackPanel>
</Grid>
This works at run time (I create an instance of ListOfThings, populate the Observable collection to have the same structure as the XAML design data) but at design time I get nothing.
If I change the ItemSource to directly bind to the ObservableCollection of Things rather than the collection view, it works but of course I get no grouping.
ItemsSource="{Binding Path=Things}"
Am I misunderstanding something with static resources in that they are not available at design time? Hence why the binding to the collectionview does not render?
Or is the binding syntax to Source incorrect?
Appears to work in Visual Studio/Blend 2013:
Pun intended.
I want to create a simple TreeView using the HierarchicalDataTemplate class.
Here's my problem XAML:
<Window.Resources>
<ObjectDataProvider
x:Key="myDataProvider"
ObjectType="vm:ContractViewModel" />
</Window.Resources>
<Window.DataContext>
<Binding Source="{StaticResource myDataProvider}" Path="Contract" />
</Window.DataContext>
<StackPanel
Orientation="Vertical"
VerticalAlignment="Top">
<ListBox MinWidth="400" Margin="10"
ItemsSource="{Binding Commissions}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Id}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TreeView>
<HierarchicalDataTemplate DataType="{x:Type m:Contract}"
ItemsSource="{Binding Commissions}">
<TextBlock Text="{Binding Id}" />
</HierarchicalDataTemplate>
</TreeView>
</StackPanel>
I'm using the MVVM pattern. The StaticResource "myDataProvider" returns an instance of a Contract (custom) class. Here's my model:
internal class Contract
{
public string Name { get; set; }
public ObservableCollection<Commission> Commissions { get; set; }
}
internal class Commission
{
public string Id { get; set; }
}
FYI - my model is actually more complex; my classes contain more members than shown, they have constructors, and they implement INotifyPropertyChanged.
In my test, I load two Commission objects into a Contract object. The listbox works as expected: I can see the Id of each Commission object w/in Contract. The TreeView doesn't work: it returns a "System.Windows.HierarchicalDataTemplate" string in the TreeView control where I'd expect each Commission Id to be listed.
I've referred to other posts and MSDN to no avail. I'd be appreciative of your help!
From what I can tell is that you're not using the TreeView correctly in XAML. You need to put your HierarchicalDataTemplate at the TreeView.Resources level and assign a ItemsSource
As shown here you want to set the Template of the item.
Try to do something like this instead:
<TreeView ItemsSource="{Binding Contracts}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type m:Contract}"
ItemsSource="{Binding Commissions}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type m:Commission}"
ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Id}" />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
I personally do it like this--using RadTreeView:
<telerik:RadTreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type vm:BaseType}"
ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Title}" />
</HierarchicalDataTemplate>
</telerik:RadTreeView.ItemTemplate>
I use Caliburn Micro for my WPF application. I implemented a little UserControl:
<UserControl Name="ImageButtonUserControl"
x:Class="SportyMate.Utility.Controls.ImageButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<Grid>
<Button>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ElementName=ImageButtonUserControl, Path=Image}" />
<TextBlock Text="{Binding ElementName=ImageButtonUserControl, Path=Text}" />
</StackPanel>
</Button>
</Grid>
</UserControl>
Now I want to use these Control in my view:
<uc:ImageButton Name="Cancel" Image="/Images/Icons/cancel_16x16.png" Text="Abbrechen" Margin="3" />
When I want to open my view (in my case it's opened as a dialog) it doesn't work. The View does not openend.
When I remove the Name-Attribute everthing is fine, but the Button have no binding to an action. Can anyone tell me what I have to do for a correct binding? A regular Button worked.
You are on a completely wrong way. You shouldn't create a user control for such a simple modification. You need to create a DataTemplate and use it for a Button.ContentTemplate. First you need to define a helper type for button content:
public class ImageButtonContent
{
public BitmapImage Image { get; set; }
public string Label { get; set; }
}
After that you can use it for DataTemplate:
<Window x:Class="Trys.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Trys="clr-namespace:Trys"
Title="MainWindow"
Height="350"
Width="525">
<Window.Resources>
<Trys:ImageButtonContent x:Key="YourImageButtonHere"
Label="Your ImageButtonHere">
<Trys:ImageButtonContent.Image>
<BitmapImage UriSource="your-icon.png" />
</Trys:ImageButtonContent.Image>
</Trys:ImageButtonContent>
<DataTemplate x:Key="ImageButton"
DataType="{x:Type Trys:ImageButtonContent}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}"
Margin="5" />
<TextBlock Text="{Binding Label}"
VerticalAlignment="Center"
Margin="10,0,0,0" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Button ContentTemplate="{StaticResource ImageButton}"
Content="{StaticResource YourImageButtonHere}"
Height="50"
Width="250" />
</Grid>
</Window>
I used a resource for an object, but you can use a property on your ViewModel. The result is:
And this just a normal button. You can use for it all power of Caliburn.Micro conventions like Click event default binding. Enjoy!
I'm using WPF, MVVM & PRISM.
I got a datatemplate in my View linked to a ViewModel UC2002_RFPBeheren_ViewModel cause the page were this code is included is linked to another ViewModel and I want the Button to have UC2002_RFPBeheren_ViewModel as ViewModel.
The datacontext of this page is UC2002_RFPBeheren_ProjectInfo_ViewModel but I want the SaveButton to use the ViewModel UC2002_RFPBeheren_ViewModel
Here is my code:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources/RFPModuleResources.xaml" />
<ResourceDictionary>
<DataTemplate x:Key="SaveButton" DataType="{x:Type vm:UC2002_RFPBeheren_ViewModel}">
<Button Command="{Binding SaveRFPCommand}">Save</Button>
</DataTemplate>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<ContentControl ContentTemplate="{StaticResource SaveButton}"/>
<Button Command="{Binding CloseTabCommand}">Close</Button>
</StackPanel>
Although the SaveButton displays but don't reacts on my command.
Do I forget something or is there another way to solve this?
Thanks in advance ;) !
=================================================================================
EDIT:
So I made some changes but it still doesn't work.
Code example:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources/RFPModuleResources.xaml" />
<ResourceDictionary>
<DataTemplate x:Key="SaveButton" DataType="{x:Type vm:UC2002_RFPBeheren_ViewModel}">
<Button Command="{Binding SaveRFPCommand}">Save</Button>
</DataTemplate>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
I set this property in the ViewModel of the page
public UC2002_RFPBeheren_ViewModel MySaveVM { get; set; }
My stackpanel looks now like this:
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<ContentControl Content="{Binding MySaveVM}" ContentTemplate="{StaticResource SaveButton}"/>
<Button Command="{Binding CloseTabCommand}">Close</Button>
</StackPanel>
what happens if you set your UV2002_RFPBeheren_ViewModel instance as the content for the ContentPresenter?
<ContentControl Content="{Binding MyUV2002_RFPBeheren_ViewModel}"/>
the DataTemplate just say how your Viewmodel should be displayed, but you have to set the DataContext or Binding to the instance of your viewmodel.
EDIT:
example
public class VMFoo
{
public UV2002_RFPBeheren_ViewModel MySaveVM {get; set;}
}
xaml
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources/RFPModuleResources.xaml" />
<ResourceDictionary>
<DataTemplate x:Key="SaveButton" DataType="{x:Type vm:UC2002_RFPBeheren_ViewModel}">
<Button Command="{Binding SaveRFPCommand}">Save</Button>
</DataTemplate>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.DataContext>
<x:local VMFoo/>
</UserControl.DataContext>
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<ContentControl Content="{Binding MySaveVM}"/>
<Button Command="{Binding CloseTabCommand}">Close</Button>
</StackPanel>
EDIT: Small working sample
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfApplication1="clr-namespace:WpfApplication1" Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<DataTemplate DataType="{x:Type WpfApplication1:UV2002_RFPBeheren_ViewModel}">
<Button Command="{Binding SaveRFPCommand}">Save</Button>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.DataContext>
<WpfApplication1:VMFoo/>
</Grid.DataContext>
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<ContentControl Content="{Binding MySaveVM}"/>
<Button Command="{Binding CloseTabCommand}">Close</Button>
</StackPanel>
</Grid>
</Window>
Viewmodels
public class VMFoo
{
public VMFoo()
{
this.MySaveVM = new UV2002_RFPBeheren_ViewModel();
}
public UV2002_RFPBeheren_ViewModel MySaveVM { get; set; }
}
public class UV2002_RFPBeheren_ViewModel
{
private DelegateCommand _save;
public ICommand SaveRFPCommand
{
get{if(this._save==null)
{
this._save = new DelegateCommand(()=>MessageBox.Show("success"),()=>true);
}
return this._save;
}
}
}
This is because of the way that ContentControl's work. It is assumed that the things in the ContentTemplate are related to the Content and so the DataContext is set to the Content and therefore that is the DataContext that the button within the template has access to. You haven't specified a Content so the value is null and so the DataContext is explicitly set to null. You can see this in a basic example. One thing you can do is to bind the Content of the ContentControl to the DataContext - see the last contentcontrol in the example.
<StackPanel DataContext="Foo">
<StackPanel.Resources>
<DataTemplate x:Key="withBtn">
<Button Content="{Binding}" />
</DataTemplate>
</StackPanel.Resources>
<Button Content="{Binding}" />
<ContentControl ContentTemplate="{StaticResource withBtn}" />
<ContentControl Content="{Binding}" ContentTemplate="{StaticResource withBtn}" />
</StackPanel>
If you are using MVVM you must expose some instance of UC2002_RFPBeheren_ViewModel within your UC2002_RFPBeheren_ProjectInfo_ViewModel to bind against. Either as a property, or an item of a collection that is a property.
Everything in the view must be ultimately accessible from the ViewModel that is your data context (UC2002_RFPBeheren_ProjectInfo_ViewModel)