I have the following XAML, a TabControl which binds to an ObservableCollection and creates my tabs just fine.
<Window x:Class="BA_Auditing.AuditWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="BizeAsset - Audit Results" Height="700" Width="1120" WindowStartupLocation="CenterScreen" WindowState="Maximized">
<Grid>
<TabControl Name="ModuleTabControl" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5" ItemsSource="{Binding}" >
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock Text="{Binding DISPLAY_NAME}"/>
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Search:" HorizontalAlignment="Right"/>
<TextBox x:Name="tbxSearch" Grid.Column="1"/>
</Grid>
<TextBlock Grid.Row="2" Text="Items Selected: 0 of 908" />
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>
Next I'd like to populate each tab area with the next level of controls, which will include a Label, TextBox another TabControl and a TextBlock.
I previously wrote this in WinForms and this is what it looks like:
What XAML do I need add to do this?
That is because I am designing it dynamically via binding rather than literally adding a TabItem
[EDIT]
I have tried to enter controls into the TabControl.ContentTemplate however nothing displays in the body of the TabItem.
I think if you had "clicked" on the "WW - Wastewater" tab you would have seen something being generated (the Search box, etc) - that's because the tab wasn't selected by default.
Anyway, here is a bit of code which gets you a bit closer to what you want - it's just to get you started, you'll need to add the other plumbing code (change notification, etc).
I don't know what you intend to have in the "Services" tab, etc...so don't know if you can handle them all in the same way i.e. as "Assets". Also you might want to explicitly define the names of the grid columns rather than have them auto-generated - there are some techniques elsewhere you can find to do that.
<Window x:Class="WpfApp38.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:WpfApp38"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TabControl Name="ModuleTabControl" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5" ItemsSource="{Binding}" SelectedIndex="0" >
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock Text="{Binding DISPLAY_NAME}"/>
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Search:" HorizontalAlignment="Right"/>
<TextBox x:Name="tbxSearch" Grid.Column="1"/>
</Grid>
<TabControl Grid.Row="1" ItemsSource="{Binding SubCategories}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DISPLAY_NAME}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<ItemContainerTemplate>
<DataGrid AutoGenerateColumns="True" ItemsSource="{Binding Assets}">
</DataGrid>
</ItemContainerTemplate>
</TabControl.ContentTemplate>
</TabControl>
<TextBlock Grid.Row="2" Text="Items Selected: 0 of 908" />
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp38
{
public class InfrastructureCateogry
{
public string DISPLAY_NAME { get; set; }
public ObservableCollection<AssetCategory> SubCategories { get; set; }
}
public class AssetCategory
{
public string DISPLAY_NAME { get; set; }
public ObservableCollection<AssetRecord> Assets { get; set; }
}
public class AssetRecord
{
public string AssetID { get; set; } // make it an int
public string AssetType { get; set; }
public string LastUpdateBy { get; set; } // make this a DateTime object
public string LastUpdateDate { get; set; } // make this a DateTime object
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ObservableCollection<InfrastructureCateogry> infrastructurecategories = new ObservableCollection<InfrastructureCateogry>();
public MainWindow()
{
InitializeComponent();
var x = new InfrastructureCateogry()
{
DISPLAY_NAME = "AR - Roads and Bridges",
SubCategories = new ObservableCollection<AssetCategory>
{
new AssetCategory
{
DISPLAY_NAME = "Lines",
Assets = new ObservableCollection<AssetRecord>
{
new AssetRecord
{
AssetID = "20040927104600",
AssetType = "Gravity Main",
LastUpdateDate = "07/05/2015 17:01:55 PM"
},
new AssetRecord
{
AssetID = "20150507170116",
AssetType = "Relined",
LastUpdateDate = "07/05/2015 17:01:15 PM"
}
}
},
new AssetCategory
{
DISPLAY_NAME = "Points"
},
new AssetCategory
{
DISPLAY_NAME = "Plant/Components"
},
new AssetCategory
{
DISPLAY_NAME = "Services"
}
}
};
infrastructurecategories.Add(x);
var x2 = new InfrastructureCateogry();
x2.DISPLAY_NAME = "WW - WasteWater";
infrastructurecategories.Add(x2);
this.DataContext = infrastructurecategories;
}
}
}
Related
This is my first question on stackoverflow.
I have a Usercontrol that contains a viewModel as a staticresource. Than I have a Window that contains this UserModel. I want to send commands from the Window to the viewmodel that is used by the usercontrol. So I bound the Viewmodel class to the Usercontrol and to the Window as a static Resource. But the viewmodell ist instanciated 2 times. Once from the Window and once from the usercontrol. What am I doing wrong?
Here is the xaml of the usercontrol:
<UserControl x:Class="ScanVM.ScanView"
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"
xmlns:t="clr-namespace:ScanVM"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="501.305">
<UserControl.Resources>
<t:ScanVM x:Key="ABC"/>
</UserControl.Resources>
<DockPanel DataContext="{Binding Source={StaticResource ABC}}">
<Grid ShowGridLines="True" Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="5*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="10*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Label Content="Geräte:" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right" Margin="0,10,10,0"/>
<DataGrid ItemsSource="{Binding Path=ScanIDs, Mode=OneWay}" Grid.Column="1" HorizontalAlignment="Left" Margin="10,10,0,0" Grid.Row="1" VerticalAlignment="Top" AutoGenerateColumns="false" Height="152" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ScanIds}" ClipboardContentBinding="{x:Null}" Header="Bezeichnung" MinWidth="200"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</DockPanel>
This is the code of my window:
<Window x:Class="ScanViewer.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:ribbon="clr-namespace:System.Windows.Controls.Ribbon;assembly=System.Windows.Controls.Ribbon"
xmlns:self="clr-namespace:ScanViewer"
xmlns:t="clr-namespace:ScanVM;assembly=ScanVM"
mc:Ignorable="d"
Title="Scan-Viewer" Height="682.225" Width="694">
<Window.Resources>
<t:ScanVM x:Key="ABC"/>
</Window.Resources>
<Window.CommandBindings>
<CommandBinding
Command="self:MainWindow.ExitCommand"
CanExecute="ExitCommand_CanExecute"
Executed="ExitCommand_Execute"/>
</Window.CommandBindings>
<DockPanel>
<ribbon:Ribbon DockPanel.Dock="Top">
<Ribbon.ApplicationMenu>
<RibbonApplicationMenu Visibility="Collapsed">
<RibbonApplicationMenuItem Header="Beenden"/>
<RibbonApplicationMenu.FooterPaneContent>
<RibbonButton Label="Exit"/>
</RibbonApplicationMenu.FooterPaneContent>
</RibbonApplicationMenu>
</Ribbon.ApplicationMenu>
<RibbonTab Header="Start">
<RibbonGroup Header="Programm">
<RibbonButton Label="Beenden" Margin="0,5,0,0" Command="self:MainWindow.ExitCommand" />
</RibbonGroup>
<RibbonGroup Header="Scannen">
<RibbonButton Label="Daten Scannen" Margin="0,5,0,0" Command="{Binding ScanCmd, Source={StaticResource ABC}}"/>
</RibbonGroup>
</RibbonTab>
</ribbon:Ribbon>
<Grid DockPanel.Dock="Top" Height="464">
<t:ScanView DataContext="{Binding Source={StaticResource ABC}}"/>
</Grid>
</DockPanel>
And this is the code of my Viewmodel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Windows.Input;
using System.Threading;
using MVVMBase;
namespace ScanVM
{
public class ScanVM : ViewModelBase
{
private ICommand _doWorkCmd;
private ICommand _scanCmd;
private bool scanAllowed = false;
public List<int> ScanIDs
{
get;
set;
}
public ScanVM()
{
_doWorkCmd = new DelegateCommand((param) => DoWork());
_scanCmd = new DelegateCommand((param) => Scan());
}
public bool NWScanAllowed(object executeAllowed)
{
return scanAllowed;
}
public ICommand WorkCmd
{
get { return _doWorkCmd; }
}
public ICommand ScanCmd
{
get
{
return _scanCmd;
}
}
private void Scan()
{
scanAllowed = true;
}
private void DoWork()
{
}
}
}
The answer depends on what you want to do with the shared object.
You can either move ABC to App.xaml inside <Application.Resources> tag to share it throughout your project.
Or you can remove the one in user control and use the ABC in window's resources.
You will need a valid reference path to address the ABC in window resource from user control in this case.
which brings us to these two situations:
The valid path is possible to find:
So let's say if your user control is a part of the mentioned window (and if the window's DataContext is set to ABC) then inside the user control you will reference it like this:
<DockPanel DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext}">
The valid path is impossible to find and you just want the static resource. If you insist on doing it this way it is better to just move the resource to App.xaml than to try to tweak this out.
I try to figure out how MVVM works and want to start simple.
I made a Model, a View and a ViewModel. I hooked up the view to a window. this works more or less.
in the view i have a textbox which i want to fill with the value of a property. The textbox keeps empty!?
This is what i have:
Model:
namespace Qbox_0001.Model
{
public class RegistratieModel
{
}
public class Registratie : INotifyPropertyChanged
{
//Fields
private string programmaNaam;
//eventhandler die kijkt of een property wijzigt
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
//Properies
public string ProgrammaNaam
{
get { return programmaNaam; }
set
{
if (programmaNaam != value)
{
programmaNaam = value;
RaisePropertyChanged("ProgrammaNaam");
}
}
}
}
}
The View:
<UserControl x:Name="UserControlRegistratie" x:Class="Qbox_0001.Views.RegistratieView"
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"
xmlns:local="clr-namespace:Qbox_0001.Views"
mc:Ignorable="d" Height="1000" Width="860" MaxWidth="860" HorizontalContentAlignment="Left" VerticalContentAlignment="Top">
<Grid x:Name="GridRegistratie">
<Grid.RowDefinitions>
<RowDefinition x:Name="RowDef_Menu" Height="21*" MaxHeight="21" MinHeight="21"/>
<RowDefinition x:Name="RowDef_TabControl" Height="500*" MinHeight="500"/>
<RowDefinition x:Name="Rowdef_Bottom" Height="40*" MaxHeight="40" MinHeight="40"/>
</Grid.RowDefinitions>
<Grid x:Name="Grid_Registratie_WorkArea" Grid.Row="1">
<TabControl x:Name="TabControl_Registratie">
<TabItem Header="Registratie">
<Grid x:Name="Grid_Tab_Registratie">
<Border>
<Grid>
<Grid.RowDefinitions>
<RowDefinition x:Name="GridRowDef_Algemeen" MinHeight="68" Height="68*" MaxHeight="68"/>
<RowDefinition x:Name="GridRowDef_Locatie" MinHeight="120" Height="120*" MaxHeight="120"/>
<RowDefinition x:Name="GridRowDef_AantalDagen" MinHeight="105" Height="105*" MaxHeight="105"/>
<RowDefinition x:Name="GridRowDef_MaxDagen" MinHeight="105" Height="105*" MaxHeight="105"/>
<RowDefinition x:Name="GridRowDef_Lokaal" MinHeight="100" Height="100*" MaxHeight="100"/>
<RowDefinition x:Name="GridRowDef_LicBestand" Height="150*" MaxHeight="150" MinHeight="150"/>
</Grid.RowDefinitions>
<GroupBox x:Name="GroupBox_algemeen" Header="Algemeen" Margin="10,4,10,3">
<Grid>
<Label x:Name="Label_Klant" Content="Klant:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Padding="0,5,5,5"/>
<Label x:Name="Label_Programma" Content="Programma:" HorizontalAlignment="Left" Margin="356,10,0,0" VerticalAlignment="Top"/>
<Label x:Name="Label_Versie" Content="Versie:" HorizontalAlignment="Left" Margin="645,10,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="textBox_KlantNaam" HorizontalAlignment="Left" Height="23" Margin="49,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="288"/>
<!-- the textbox keeps empty -->
<TextBox x:Name="TextBox_ProgrammaNaam" Text="{Binding ElementName=RegistratieViewModel, Path=ProgrammaNaam, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Height="23" Margin="431,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="190" IsEnabled="False" />
<TextBox x:Name="TextBox_Versie" HorizontalAlignment="Left" Height="23" Margin="695,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" IsEnabled="False" />
</Grid>
</GroupBox>
</Grid>
</Border>
</Grid>
</TabItem>
<TabItem Header="Licentie(s)">
<Grid x:Name="Grid_Tab_Licentie" Background="#FFE5E5E5"/>
</TabItem>
</TabControl>
</Grid>
</Grid>
</UserControl>
In the View.cs:
namespace Qbox_0001.Views
{
/// <summary>
/// Interaction logic for RegistratieView.xaml
/// </summary>
public partial class RegistratieView : UserControl
{
public RegistratieView()
{
InitializeComponent();
this.DataContext = new Qbox_0001.ViewModel.RegistratieViewModel();
}
}
}
The ViewModel
using Qbox_0001.Model; //
using System.Collections.ObjectModel; //
namespace Qbox_0001.ViewModel
{
public class RegistratieViewModel
{
public RegistratieViewModel()
{
loadRegistratieOnderdelen();
}
public ObservableCollection<Registratie> RegistratieOnderdelen //Registratie = "public class Registratie : INotifyPropertyChanged" van de Model
{
get;
set;
}
public void loadRegistratieOnderdelen()
{
ObservableCollection<Registratie> regOnderdelen = new ObservableCollection<Registratie>();
regOnderdelen.Add(new Registratie { ProgrammaNaam = "Test" });
}
}
}
I can see a couple of problems with your code.
You are populating a local ObservableCollection (inside your loadRegistratieOnderdelen() method) with data but since its local, it is not a member of the DataContext and hence unavailable to the View. You have to use public properties like RegistratieOnderdelen which you already declared in your RegistratieViewModel.
Next you are using an ObservableCollection whereas you might just want to use a property of type String. Collections are used when you want to represent lists, for example inside a ListView or an ItemsControl. Your view indicates that you want to bind a single text value so a public property of type String makes more sense.
Best, Nico
The DataContext is a RegistratieViewModel. This class has a RegistratieOnderdelen property that returns a collection of Registratie objects.
You could bind to the ProgrammaNaam property of one such item but you need to specify which item to bind to, for example the first one:
<TextBox x:Name="TextBox_ProgrammaNaam" Text="{Binding Path=RegistratieOnderdelen[0].ProgrammaNaam, UpdateSourceTrigger=PropertyChanged}" ... />
How do I make a scrollable form similar to that of the Phone Contact input panel in Windows Phone 8.1?
The current method of StackPanel inside a ScrollViewer restricts scrolling when the SIP launches and I have to hit back button to choose other TextBoxes.
This is not an idea UX situation and I've tried a few options of the web.
Increasing the StackPanel's height beyond its necessary size by about
350 pixels - didn't work, as it displaces the form unevenly and
doesn't return to normal
Creating a ListBox as suggested in another site online didn't change anything either
Increasing the down margin of the last control didn't help either
check the below code which has worked fine for me.
Chat.xaml.cs
using System;
using System.ComponentModel;
using System.Windows.Controls;
using System.Windows.Input;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using Microsoft.Phone.Controls;
using PhoneApplicationPage = Microsoft.Phone.Controls.PhoneApplicationPage;
namespace LIV.View
{
// ReSharper disable once RedundantExtendsListEntry
public partial class Chat : PhoneApplicationPage
{
private bool _flag;
public Chat()
{
InitializeComponent();
}
#region Static Chat Header WorkAround
public double OldHeight;
private TranslateTransform _translateTransform;
#region TranslateY dependency property
public static readonly DependencyProperty TranslateYProperty = DependencyProperty.Register(
"TranslateYProperty", typeof(double), typeof(Chat), new PropertyMetadata(default(double), PropertyChangedCallback));
private static void PropertyChangedCallback(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var chat = o as Chat;
if (chat != null)
{
chat.UpdateTopMargin((double)e.NewValue);
}
}
public double TranslateY
{
get { return (double)GetValue(TranslateYProperty); }
set { SetValue(TranslateYProperty, value); }
}
#endregion
private void ChatPage_OnLoaded(object sender, RoutedEventArgs e)
{
var transform = ((Application.Current).RootVisual).RenderTransform as TransformGroup;
if (transform != null)
{
_translateTransform = transform.Children.OfType<TranslateTransform>().FirstOrDefault();
if (_translateTransform != null)
{
var binding = new Binding("Y")
{
Source = _translateTransform
};
BindingOperations.SetBinding(this, TranslateYProperty, binding);
}
}
}
private void UpdateTopMargin(double translateY)
{
LayoutRoot.Margin = new Thickness(0, -translateY, 0, 0);
}
#endregion
}
}
Chat.xaml
<phone:PhoneApplicationPage x:Class="LIV.View.Chat"
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:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="Black"
Loaded="ChatPage_OnLoaded"
Orientation="Portrait"
SupportedOrientations="Portrait"
shell:SystemTray.BackgroundColor="#FF5CBFBB"
shell:SystemTray.ForegroundColor="White"
shell:SystemTray.IsVisible="True"
mc:Ignorable="d">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Background="#FF5CBFBB">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel>
<TextBlock Foreground="White" Text="{Binding ChatUser.Name}" />
<TextBlock Foreground="White" Text="{Binding ChatTime}" />
</StackPanel>
<Button Grid.Column="1"
BorderThickness="0"
Command="{Binding TerminateCommand}"
Foreground="White">
End Chat
</Button>
</Grid>
<Grid x:Name="ContentPanel" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox x:Name="MessageListBox"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding Messages}"
ScrollViewer.VerticalScrollBarVisibility="Visible"
Style="{StaticResource BottomListBoxStyle}">
</ListBox>
<StackPanel x:Name="MessageTextPanel"
Grid.Row="1"
Background="#FF5CBFBB">
<Grid Margin="0,0,0,-10">
<TextBlock FontSize="15" Text="{Binding UserStatus}" />
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox></TextBox>
</Grid>
</StackPanel>
</Grid>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
check: ScrollViewer not scroll up while Keyboard is active
When normal
When SIP open
How about only extending the bottom margin of the StackPanel when the SIP is shown? IIRC there is no straightforward API to test for that, but you could use the focus state of the TextBoxes to check when it appears or disappears.
I'm working on a new functionality for Visual Studio Add-in. Initially the project's target framework was 3.5. But I was asked to add a Tool Window with quite complicated UI using WPF and switch to 4.0 framework (maybe this is important)
I'm trying to bind hierarchical data to the Tree View inside my Tool Window which is originally a WPF User Control.
But I see the following error:
"System.Windows.Data Error: 40 : BindingExpression path error: 'PoolList' property not found on 'object' ''OpjectPool' (Name='')'. BindingExpression:Path=PoolList; DataItem='OpjectPool' (Name=''); target element is 'TreeView' (Name='treeView1'); target property is 'ItemsSource' (type 'IEnumerable')"
This is a Class which represents data I need to bind to the tree view.
class CodeItem
{
public TextPoint StartPoint { get; set; }
public TextPoint EndPoint { get; set; }
public string Name { get; set; }
public vsCMElement Kind { get; set; }
public CodeElements ChildClasses { get; set; }
public ProjectItem ProjectItem { get; set; }
public List<CodeItem> CodeItems { get; set; }
public string Label { get; set; }
public CodeItem(CodeElement el)
{
StartPoint = el.StartPoint;
EndPoint = el.EndPoint;
Name = el.Name;
Kind = el.Kind;
ChildClasses = el.Children;
ProjectItem = el.ProjectItem;
Label = Kind.ToString();
CodeItems = new List<CodeItem>();
if (ChildClasses.Count != 0)
{
foreach (CodeElement elem in ChildClasses)
{
if (elem.Kind.ToString() == "vsCMElementClass")
{
CodeItems.Add(new CodeItem(elem));
}
}
}
}
}
Here is my UserControl code:
public partial class OpjectPool : UserControl
{
public ObservableCollection<CodeItem> PoolList = new ObservableCollection<CodeItem>();
public OpjectPool()
{
Project pr = ... // getting VS Project we want to work with;
foreach (ProjectItem item in pr.ProjectItems.Item("Objects").ProjectItems)
{
if (item.FileCodeModel != null)
{
CodeItem rootPoolItem = new CodeItem(item.Name);
foreach (CodeElement el in item.FileCodeModel.CodeElements)
{
if (el.Kind.ToString() == "vsCMElementClass" || el.Kind.ToString() == "vsCMElementNamespace")
{
CodeItem ci = new CodeItem(el);
rootPoolItem.CodeItems.Add(ci);
}
}
PoolList.Add(rootPoolItem);
}
}
InitializeComponent();
this.treeView1.DataContext = this;
}
}
And Here is a XAML code:
<UserControl x:Class="******.OpjectPool"
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">
<Grid Height="Auto" Name="maingrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Column="0" Height="Auto" HorizontalAlignment="Stretch" Name="scrollViewer1" VerticalAlignment="Stretch" Width="Auto" HorizontalScrollBarVisibility="Visible">
<TreeView Height="Auto" Name="treeView1" Width="Auto" ItemsSource="{Binding PoolList}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding CodeItems}" >
<TreeViewItem Header="{Binding Label}"/>
</HierarchicalDataTemplate >
</TreeView.ItemTemplate>
</TreeView>
</ScrollViewer>
<ScrollViewer Grid.Column="1" Height="Auto" HorizontalAlignment="Stretch" Name="scrollViewer2" VerticalAlignment="Stretch" Width="Auto" HorizontalScrollBarVisibility="Visible" Grid.ColumnSpan="1">
<DataGrid AutoGenerateColumns="False" Height="Auto" Name="dataGrid1" Width="Auto" FrozenColumnCount="3" />
</ScrollViewer>
<ScrollViewer Grid.Column="2" Height="Auto" HorizontalAlignment="Stretch" Name="scrollViewer3" VerticalAlignment="Stretch" Width="Auto" HorizontalScrollBarVisibility="Visible" Grid.ColumnSpan="1">
<DataGrid AutoGenerateColumns="False" Height="Auto" Name="dataGrid2" Width="Auto" />
</ScrollViewer>
<GridSplitter Grid.Column="1" Name="gridSplitter1" ResizeDirection="Columns" BorderBrush="Black" Background="Black" Margin="0,0,0,0" Grid.ColumnSpan="1" HorizontalAlignment="Left" Width="2" />
<GridSplitter Grid.Column="2" Name="gridSplitter2" ResizeDirection="Columns" BorderBrush="Black" Background="Black" Margin="0,0,0,0" Grid.ColumnSpan="1" HorizontalAlignment="Left" Width="2" />
</Grid>
PoolList is not null and contains a full hierarchical structure I need to bind.
Interesting that error message says about real and not null property of the object
As error states:
BindingExpression path error: 'PoolList' PROPERTY not found on 'object' ''OpjectPool' (Name='')'. BindingExpression:Path=PoolList;
PoolList is not a property.
I have a custom control that has two listViews employing GridViewRowPresenters. I need the row heights of the two listViews to be the same. The catch is I wont know what the heights will be until run time.
That is, both will have their heights set to Auto and when the control is rendered one listView will have its rows at ActualHeight = 30 the other at ActualHeight = 40. I want them both to be 40.
If the ListViews use a shared item template, all you would have to do is wrap your GridViewRowPresenter in a grid and then use a SharedSizeGroup on that grid's only row. Here's how it can be achieved.
XAML
<UserControl x:Class="WpfApplication1.UserControl2"
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"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<UserControl.Resources>
<GridViewColumnCollection x:Key="GridViewColumns">
<GridViewColumn Width="100"
DisplayMemberBinding="{Binding Path=Text}"
Header="Text" />
</GridViewColumnCollection>
<DataTemplate x:Key="RowTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" SharedSizeGroup="RowSizeGroup" />
</Grid.RowDefinitions>
<Border BorderBrush="Black" BorderThickness="1">
<GridViewRowPresenter Columns="{StaticResource GridViewColumns}" />
</Border>
</Grid>
</DataTemplate>
</UserControl.Resources>
<Grid IsSharedSizeScope="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<GridViewHeaderRowPresenter Columns="{StaticResource GridViewColumns}" />
<ListView Grid.Row="1"
ItemTemplate="{StaticResource RowTemplate}"
ItemsSource="{Binding Path=Items1}" />
<ListView Grid.Row="2"
ItemTemplate="{StaticResource RowTemplate}"
ItemsSource="{Binding Path=Items2}" />
</Grid>
</UserControl>
Code-Behind (for reference, but not really important)
using System.Collections.ObjectModel;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for UserControl2.xaml
/// </summary>
public partial class UserControl2
{
public UserControl2()
{
InitializeComponent();
DataContext = this;
Items1 = new ObservableCollection<object>
{
new Item {Text = "Hello World!"},
new Item {Text = "Hello \nWorld!"}
};
Items2 = new ObservableCollection<object>
{
new Item {Text = "Testing 1\n2\n3"}
};
}
private class Item
{
public string Text { get; set; }
}
public ObservableCollection<object> Items1 { get; private set; }
public ObservableCollection<object> Items2 { get; private set; }
}
}
If you want to set the height of your rows explicitly, just replace <RowDefinition Height="Auto" SharedSizeGroup="RowSizeGroup" /> with <RowDefinition Height="40" SharedSizeGroup="RowSizeGroup" /> where 40 in this case is the specific height.