Create instance using key in the xaml - c#

Given ResourceDictionary:
<GroupBox x:Key="Group"
x:Shared="False">
<ItemsControl ItemsSource="{Binding Items}">
...
</ItemsControl>
</GroupBox>
<ItemsControl x:Key="Test"
x:Shared="False"
ItemsSource="{Binding Items}">
...
</ItemsControl>
Both ItemsControl content is identical. Is it possible to avoid duplicating same xaml (... is quite big)? Is it possible to create Test instance from within Group.

You could use a ContentControl:
<ItemsControl x:Key="Test"
x:Shared="False"
ItemsSource="{Binding Items}">
</ItemsControl>
<GroupBox x:Key="Group" x:Shared="False">
<ContentControl Content="{StaticResource Test}" />
</GroupBox>
Note that the ItemsControl resource must be defined before the GroupBox resource.
As pointed out by #grek40, you could also set the Content property of the GroupBox directly to the ItemsSource resource provided that the GroupBox doesn't contain any other controls.

Actually, you can directly set the content
<GroupBox x:Key="Group" x:Shared="False" Content="{StaticResource Test}">
I'm not really a fan of x:Shared (bugged me some times), so how about using some DataTemplate instead?
<DataTemplate x:Key="TestTemplate">
<ItemsControl ItemsSource="{Binding Items}">
<!-- Whatever it is you have inside... -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Background="Yellow"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
<GroupBox Content="{Binding}" ContentTemplate="{StaticResource TestTemplate}">
</GroupBox>

Related

WPF bind to property of the ItemsPanel of an ItemsControl

I've written a code example below:
<StackPanel>
<TextBlock>Appointments today</TextBlock>
<ItemsControl ItemsSource="{Binding Appointments}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controls:CalendarMonthDayEventsItemsPanel OutsideViewportCount="..." />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border>
<TextBlock Text="{Binding Title}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<StackPanel Orientation="Horizontal">
<TextBlock>+</TextBlock>
<TextBlock Text="{Binding ......}" /> <!-- Should show number of items in ItemsControl that are outside view, using CalendarMonthDayEventsItemsPanel.OutsideViewportCount -->
<TextBlock>more items</TextBlock>
</StackPanel>
</StackPanel>
I Created a custom Panel, the CalendarMonthDayEventsItemsPanel, and I use that panel as the itemspanel of the ItemsControl. In the panel's layout code, I determine how many items (panel childs) are outside the bounds of the panel. The property OutsideViewportCount contains the number of items that are outside of the visible bounds of the CalendarMonthDayEventsItemsPanel.
Now I want to show the value of OutsideViewportCount in a TextBlock that's below the ItemsControl.
This means I have to create some kind of binding, but everything I tried doesn't work.
Does someone have a solution or a better approach to achieve the same result?
Maybe you can make use of Tag property of ItemsPanel to relay the value of ItemsPanel as a workaround.
<ItemsControl x:Name="A"
ItemsSource="{Binding Appointments}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:CalendarMonthDayEventsItemsPanel OutsideViewportCount="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Path=Tag, Mode=OneWayToSource}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
...
</ItemsControl>
<StackPanel Orientation="Horizontal">
<TextBlock>+</TextBlock>
<TextBlock Text="{Binding ElementName=A, Path=Tag, Mode=OneWay}"/>
<TextBlock>more items</TextBlock>
</StackPanel>

ContentControl.Content not binding correctly in MVVM

I have an MVVM app. I want a collection of buttons to be represented from the ViewModel and be dynamic.
Which means I want to populate the window with controls from the ViewModel.
I tried creating a content control and binding it's Content property to a Grid which I will put buttons in. The binding did not work, it remains empty.
I tried binding it to a simple string, still nothing. I should mention that other simple bindings do work, so that's why it's weird.
The creation of the UserControl:
<TabControl HorizontalAlignment="Left" Height="696" Margin="429,0,0,32" VerticalAlignment="Bottom" Width="552" ItemsSource="{Binding TabCollection}">
<TabControl.Resources>
</TabControl.Resources>
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<cattab:CategoryTab/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>`
The binding in the UserControl:
<ContentControl HorizontalAlignment="Left" Height="286" Margin="98,152,0,-396" VerticalAlignment="Top" Width="313">
<ContentControl Content="{Binding Favorites}" Margin="0,30,0,0" VerticalAlignment="Top"/>
</ContentControl>`
MainViewModel:
//**** Initilize TabCollection with fake data (temporary)
TabCollection.Add(new CategoryTabViewModel { Header = "בדיקה11" });
TabCollection.Add(new CategoryTabViewModel { Header = "בדיקה2" });
UserControl ViewModel:
public CategoryTabViewModel()
{
SearchText = "bbbaaaa";
Favorites.Add(new Button());
}
The binding of SearchText works, on Favorites it's not
Try to use an ItemsControl
Here's a good tutorial: http://www.wpf-tutorial.com/list-controls/itemscontrol/
<ItemsControl HorizontalAlignment="Left" Height="286" Margin="98,152,0,-396" VerticalAlignment="Top" Width="313" Content="{Binding Favorites}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controlsToolkit:WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Use a WrapPanel to manage your layout: http://www.wpftutorial.net/WrapPanel.html
After reading your updates I can say that your code is not MVVM compliant because your ViewModel layer is aware of the View layer (you create Buttons in your ViewModel)
What you need to do:
XAML of your CategoryTab
<ItemsControl ItemsSource="{Binding Favorites, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button/><!--Show whatever you want here-->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If you want to create new Button every time an object is added to Favorites you will need to make Favorites an ObservableCollection.

How to bind properties of one ObservableCollection of ListView to properties of SelectedItem of another ListView?

So I have a few ListViews. The first is binded to ObservaleCollection<ComPort>. All properties of ComPort may take some predefined values. Other ListViews are responsible for that properties: they show all that possible (predefined) values and SelectedItem should be the current value of that property of ComPort from the first ObservaleCollection.
I can't attach images so here is an external picture, it would make the situation clean: http://i.stack.imgur.com/ZBRRx.png
<Window.Resources>
<ResourceDictionary x:Name="rd">
<l:ComPorts x:Key="vComPorts"/>
<l:SystemPorts x:Key="vSystemPorts"/>
<l:BaudRates x:Key="vBaudRate"/>
<l:Parities x:Key="vParities"/>
<l:DataBits x:Key="vDataBits"/>
<l:StopBits x:Key="vStopBits"/>
<l:Timeouts x:Key="vTimeouts"/>
<l:ComPort x:Key="vSelectedPort"/>
</ResourceDictionary>
</Window.Resources>
...
<ListView
Name="PortsList"
Grid.Row="1"
Grid.Column="0"
Margin="5"
VerticalAlignment="Stretch"
ItemsSource="{StaticResource vComPorts}"
DataContext="{StaticResource vComPorts}"
SelectedValuePath="PortName"
SelectedValue="{Binding ElementName=SystemPortsList, Path=SelectedItem.Value}"
SelectionChanged="PortsList_SelectionChanged"
MouseDoubleClick="PortsList_MouseDoubleClick">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox />
<TextBlock Margin="5,0,0,0" Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView
x:Name="SystemPortsList"
Margin="5"
VerticalAlignment="Stretch"
DataContext="{Binding Source={StaticResource vSelectedPort}}"
ItemsSource="{Binding Source={StaticResource vSystemPortsView}}"
SelectedItem="{Binding Source={StaticResource vSelectedPort}, Path=PortName}"
MouseEnter="SystemPortsList_Refresh"
MouseLeave="SystemPortsList_Refresh"
Grid.Row="1"
Grid.Column="1" SelectionChanged="SystemPortsList_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Name="tb" Margin="5,0,0,0" Text="{Binding Path=Name}" />
</StackPanel>
</ListView.ItemTemplate>
</ListView>
I've tried to make an instance of class ComPort for saving current value of selected item from the first ListView, but anyway I can't cope with it without help. How this task should be solved?
1) Instead of handling SelectionChanged on the PortsList ListView, bind your checkbox to the ListViewItemsPanel like so:
<CheckBox IsChecked={Binding IsSelected, RelativeSource=Parent/>
2) Add an x:Name to your first ListBox, say x:Name="ComPortLB";
3) Remove DataContext on SystemPortsList;
4) Fix SelectedItem on SystemPortsList like so:
SelectedValue="{Binding ElementName=ComPortLB, Path=SelectedValue.PortName}"
I haven't tested any of this code and I haven't done this kind of stuff for a while, so I apologize for errors, but it should get you closer. I've also had to make some assumptions about your classes since you don't provide enough information.

How to attach a different DataTemplate to the Same Hierarchical Template

Is it possible to attach different DataTemplates so that the children render differently to the same HierarchicalDataTemplate, which as I understand controls the View of the header
I am trying to do it without success::
<Window.Resources>
<DataTemplate
x:Key="ChildTemplate1">
<Label Content="Blah">
</DataTemplate>
<DataTemplate
x:Key="ChildTemplate2">
<Label Content="Blah2">
</DataTemplate>
<HierarchicalDataTemplate
x:Key="RootTemplate"
ItemTemplate={StaticResource ChildTemplate2}"
ItemsSource="{Binding Path=Children}">
<Label Content="Header">
</HierarchicalDataTemplate>
</Window.Resources>
<TreeView ItemTemplate="{StaticResource RootTemplate}">
<TreeViewItem ItemTemplate="{StaticResource ChildTemplate1}"/>
</TreeView>
So again, what I am trying to do is override the DataTemplate set in HierarchicalDataTemplate(ChildTemplate2) with ChildTemplate1

Xaml code explanation

I am working on c# xaml using silverlight and i am bit confused about the hierarchy of this xaml code:
<UserControl.Resources>
<this:MyValueConverter x:Key="TabConverter"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="Green">
<ItemsControl ItemsSource="{Binding Path=TabList, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas></Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Width="150" Background="red" Height="100" Canvas.Left="{Binding TabList, Mode=TwoWay, Converter={StaticResource TabConverter}}" Canvas.Top="100" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
When i run it gives a big green color window(sorry if technical names are not correct), whereas it should also show red color somewhere in same window as it has Border Width="150" Background="red" .Could some one please explain me what this code is doing ?
ItemsControl really just binds to a list and applies a datatemplate (border with background red) for each item in the list. As for the reason you're only seeing green, well there's probably nothing in the TabList property on your viewmodel. That way, nothing in the items template renders, and all you see is green.
You'll need to make sure that TabList is bound correctly (it exists on your datacontext, whether that's a view model or not) and that it has items in it.
Here's a simpler version of what you may want to accomplish:
<Grid x:Name="LayoutRoot" Background="Green">
<ItemsControl ItemsSource="{Binding Path=TabList, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Width="150" Background="red" Height="100" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>

Categories