display content class xaml vb.net - wpf

Well i have a mainWindow written in xaml (vb.net) with 10 buttons and for each button i have a class (with buttons...) in my project. Example: when i click on button valid i display the content of the class valid in my grid. Each class is instantiated in the class mainWdow.
I also have a grid on this mainWindow.
When i click on a button in my mainWindow, i would like to display the content of the correspondig class in my grid and of course i want to be able to use this class (click on buttons...).
What's the best way to do this on vb.net / xaml please?
On this webpage http://msdn.microsoft.com/en-us/library/cc903947(v=vs.95).aspx there are some indications but it is not what i want because i don't want just only display the content on my class but i want to be able to work with the class displayed on my grid...
I give you thanks for your advices.

Ok, so first you should read up about DataTemplates from the Data Templating Overview page on MSDN. Now here is the basic principal... instead of putting your reusable XAML into Windows, declare them in DataTemplates in your Window.Resources section:
<DataTemplate x:Key="StopDataTemplate">
<!--Define your content here-->
</DataTemplate>
<DataTemplate x:Key="ValidDataTemplate">
<!--Define your content here-->
</DataTemplate>
Now you can display the content of these DataTemplates in a ContentControl:
<ContentControl Name="Content" ContentTemplate="{StaticResource ValidDataTemplate}" />
Then when you want to switch to the other view, you just need to set the ContentControl.ContentTemplate property to the other DataTemplate (from Window code behind):
DataTemplate dataTemplate = (DataTemplate)FindResource("StopDataTemplate");
Content.ContentTemplate = dataTemplate;

Well, here is what i have done to do some tests:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DataTemplate x:Key="CBTemplate">
<Grid Height="200" HorizontalAlignment="Left" Name="centralGrid" VerticalAlignment="Top" Width="200" Background="Red">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1" Text="{Binding Title}"
Margin="10" HorizontalAlignment="Left" FontSize="20"/>
</Grid>
</DataTemplate>
then in my mainWindow.xaml i have this:
<Grid x:Name="layout" Background="LightBlue" Margin="250,150,260,380">
<ContentControl Name="Content" ContentTemplate="{StaticResource CBTemplate}" />
</Grid>
And in the mainWindow.vb i have:
Class MainWindow
Private t As Thing
Sub New()
InitializeComponent()
t = New Thing("test")
layout.DataContext = t
End Sub
End Class
So my program compiles properly but there is a little problem: text="{Binding Title}" doesn't work and when i replace it with "toto", there is no problem toto is displayed...
Did i miss something in my code?

Related

Assign different ViewModels to one UserControl

I have MainWindow.xaml page with it's MainViewModel
and would like to add 2 SidePanels using one UserControl, but it should have different ViewModels.
MainViewModel alredy has 2 properties with created SidePanelViewModels:
public MainViewModel()
{
LeftSidePanel = new SidePanelViewModel(PanelSides.Left);
RightSidePanel = new SidePanelViewModel(PanelSides.Right);
}
How to set objects in this properties as DataContext for each UserControl in xaml?
Something like this doesnot work:
<Window DataContext="{Binding MainViewModel, Source={StaticResource Locator}}">
...
<Grid Visibility="{Binding RightSidePanel.PanelVisibility}" Grid.Column="4" Grid.Row="2" >
<v:SidePanelViev DataContext="{Binding RightSidePanel}" />
</Grid>
</Window>
I broke all the brains thinking how to do it, Please help
ps.
Or please suggest any other approach to reach the same target..
I have solved my problem by adding both instances of SidePanelViewModel as Content of ContentControl
<Window DataContext="{Binding MainViewModel, Source={StaticResource Locator}}">
...
<Grid Visibility="{Binding RightSidePanel.PanelVisibility}" Grid.Column="4" Grid.Row="2" >
<ContentControl Content="{Binding RightSidePanel}"></ContentControl>
</Grid>
</Window>
and adding new Window.Resource what binds all classes of type SidePanelViewModel to be visualised using SidePanelViev
<Window.Resources>
<DataTemplate DataType="{x:Type vm:SidePanelViewModel}">
<v:SidePanelViev></v:SidePanelViev>
</DataTemplate>
</Window.Resources>
This works, but if somebody has better ideas, please do not hesitate to post them, I am not sure that my decision is good one

WPF: Set UserControl DataContext

I have the following MainWindow that lays out a left side navigation panel and a right side display area (both of these are UserControls).
Can someone explain how to assign the DataContext of the navigation panel (LinksView.xaml) to that of LinksViewModel.cs. I would like to bind a Command (BtnCompanyClickCommand) to the button and define BtnCompanyClickCommand in LinksViewModel.cs.
I have tried various methods that I found on StackOVerflow to set the DataContext but none of these solutions seem to work (binding RelativeSource, naming view and binding to name, etc.).
MainWindow.xaml
<StackPanel Orientation="Horizontal">
<vw:LinksView DataContext="{Binding RelativeSource={RelativeSource Self}}"/>
<ContentControl Content="{Binding CurrentUserControl}" />
</StackPanel>
LinksView.xaml
<StackPanel Orientation="Vertical">
<Button Content="Company" Width="75" Margin="3" Command="{Binding ElementName=Links,Path=BtnCompanyClickCommand}" />
</StackPanel>
FormsDictionary.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:SidekickAdmin.ViewModel"
xmlns:vw="clr-namespace:SidekickAdmin.View">
<DataTemplate DataType="{x:Type vm:CompanySummaryViewModel}">
<vw:CompanySummaryView>
<ContentControl Content="{Binding }" />
</vw:CompanySummaryView>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:LinksViewModel}">
<vw:LinksView />
</DataTemplate>
</ResourceDictionary>
EDIT
So I finally came across this explanation of how to set the DataContext of a UserControl which has to be done on the first child item of the UserControl.
Here is the modified LinksView.xaml that works.
<StackPanel Orientation="Vertical">
<StackPanel.DataContext>
<vm:LinksViewModel /> <!-- Bind the items in StackPanel to LinksViewModel -->
</StackPanel.DataContext>
<Button Content="Company" Width="75" Margin="3" Command="{Binding BtnCompanyClickCommand}" />
</StackPanel>
However, I am still not clear on why I have to set the DataContext of the child element and not the UserControl and why the DataTemplate for LinksView (set in FormsDictionary.xaml) doesn't tie into the DataContext of LinksViewModel. Any explanation would be appreciated.
First you have to refer to your DataContext (LinksViewModel.cs) in your XAML code.
You can do that either by directly instantiating it or use a ResourceDictionary. In the latter case you instantiate your DataConext either inside some .cs file or inside the ResourceDictionary .xaml file and store it in a named ResourceDictionary where you can find the reference later.
Second you simply have to associate the DataContext property of a View element like your LinksView.xaml with the corresponding DataContext.
This is pretty high-level and without any code but that's the basic idea behind it.
there should be an instance of LinksViewModel in MainWindowViewModel:
MainWindowViewModel.cs:
class MainWindowViewModel
{
public MainWindowViewModel()
{
LinksVM = new LinksViewModel();
}
public LinksViewModel LinksVM { get; private set; }
}
MainWindow.xaml
<StackPanel Orientation="Horizontal">
<vw:LinksView DataContext="{Binding LinksVM}"/>
<ContentControl Content="{Binding CurrentUserControl}" />
</StackPanel>
LinksView.xaml
<StackPanel Orientation="Vertical">
<Button Content="Company" Width="75" Margin="3" Command="{Binding BtnCompanyClickCommand}" />
</StackPanel>
since LinksView is explicitly created in MainWindow, there is no need in DataTemplate - it can be removed
<DataTemplate DataType="{x:Type vm:LinksViewModel}">
<vw:LinksView />
</DataTemplate>

WPF Listbox & MVVM binding

I am following MVVM in C# and am attempting to display a view in a listbox.
I am setting the listbox itemsource (in code, not in binding and using the viewmodels collection) and then set the datatemplate to be my view in xaml. The issue I'm encountering is my view always loads with its default constructor values, if I remove the datacontext from the view however it loads fine.
Below is the listbox I am creating in xaml
<ListBox Name="lbCatalogues" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<view:CatalogueRowView/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This is the xaml for my view. If I remove the DataContext it works
<UserControl.DataContext>
<model:CatalogueModel />
</UserControl.DataContext>
<Grid Name="Container" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<!-- Catalogue_ID, UploadedTime, Client_ID, Name, Desc, Filesize -->
<Label Name="lblCatalogueID" Content="{Binding Path=CatalogueID}" Grid.Column="0"/>
<Label Name="lblUploadedTime" Content="{Binding Path=UploadedTime}" Grid.Column="1"/>
<Label Name="lblCatalogueName" Content="{Binding Path=Name}" Grid.Column="2"/>
<Label Name="lblCatalogueDescription" Content="{Binding Path=Description}" Grid.Column="3"/>
<Label Name="lblFilesize" Content="{Binding Path=Filesize}" Grid.Column="4"/>
<Grid/>
This is the code where I am setting the listbox ItemSource:
lbCatalogues.ItemsSource = catalogueViewModel.Records;
My question is how can I get the view to load correctly within the listbox so that each item in the listbox has a DataContext linked to that listbox Itemsource?
You already know the answer: simply remove <UserControl.DataContext> from your UserControl
You are telling your UserControl to use a new instance of CatelogueModel for the DataContext, and this overrides any DataContext that is set when you use your UserControl. See MSDN's list of Dependency Property Precedence for more info
I do not ever recommend setting the DataContext inside a UserControl. It goes against how WPF is meant to work by having separate UI and data layers, and is a problem for anyone trying to use your UserControl
As for your question about each item in the ListBox linking to the ItemsSource, DataTemplates simply tell WPF how to draw an object. The data behind the object still remains.
For example, your ListBox contains a list of Record objects, and your DataTemplate is telling the ListBox to draw each one of those records with CatelogueRowView. The actual data behind the CatelogRowView is still your data object from catelogueViewModel.Records
lbCatalogues.ItemsSource = catalogueViewModel.Records; instead of this Simply bind ItemsSource of ListBox as ItemsSource="{Binding Records}" in xaml. I hope this will help.

mvvm navigation treeview

i'm trying to implement a navigation menu using a treeview.
on the left panel there is a treeview and on the right panel the matched view.
since it's MVVM i'm having a difficult to switch between the correct views.
clicking on Menu1 - should display View1.xaml view
clicking on Menu2 - should display View2.xaml view
my code looks like that:
MainView.xaml
<Window x:Class="Menu.View.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Views="clr-namespace:Menu.View"
Title="MainView" Height="300" Width="300">
<Window.Resources>
<DataTemplate DataType="{x:Type Views:Page1}">
<Views:Page1 />
</DataTemplate>
<DataTemplate DataType="{x:Type Views:Page2}">
<Views:Page2 />
</DataTemplate>
</Window.Resources>
<DockPanel>
<Grid DockPanel.Dock="Left">
<TreeView>
<TreeViewItem Header="Menu 1" />
<TreeViewItem Header="Menu 2" />
<TreeViewItem Header="Menu 3" />
</TreeView>
</Grid>
<Grid DockPanel.Dock="Right">
<Views:Page1 />
<Views:Page2 />
</Grid>
</DockPanel>
</Window>
Page1.xaml (the view that should be visible when clicking "Menu 1")
<Grid>
<Label FontSize="24" FontWeight="Bold">1</Label>
</Grid>
Page2.xaml (the view that should be visible when clicking "Menu 2")
<Grid>
<Label FontSize="24" FontWeight="Bold">2</Label>
</Grid>
for every page i have its own ViewModel and i have the main one called MainViewModel.
how should i implement such thing in a MVVM mode ?
I think here is the mistake. You should have put your ViewModels in the DataType. so when you fill the DataContext the DataTemplate do his job. something like :
<DataTemplate DataType="{x:Type ViewModels:Page1ViewModel}">
<Views:Page1 />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:Page2ViewModel}">
<Views:Page2 />
</DataTemplate>
instead of :
<Views:Page1 />
<Views:Page2 />
add a ContentControl and do a binding to it's content like this :
<ContentControl Content="{Binding MyViewModel}"></ContentControl>
myView is property in your MainViewViewModel (which has to implement INotifyPropertyChanged) can be like this :
object _MyView;
public object MyViewModel
{
get
{
return _MyView;
}
set
{
_MyView = value;
OnPropertyChanged("MyViewModel");
}
}
now, in each TreeViewItem add a Command that do update it's Content for ex :
in your MainViewViewModel add CallView1Command property and implement it (see how dealing with commands)
so in Command's excute method you can update MyViewModel according to the View you want to show.
I recommend using Unity to instanciate ViewModels.
Not very well explained, but, Hope it helps anyway

How to modify silverlight combobox data display

I have a combobox defined as follows:
<ComboBox x:Name="cboDept" Grid.Row="0" Margin="8,8,8,8" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120"
ItemsSource="{Binding Source={StaticResource cvsCategories}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Width="Auto" Height="Auto">
<sdk:Label Content="{Binding CategoryID}" Height="20" />
<sdk:Label Content="{Binding CategoryName}" Height="20" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
It works fine. However, once I select an item in the list, I want a different template to be applied to the combobox selected item being shown to the user (the item shown after the disappearance of popup). In the above case, I want only CategoryName to be displayed in the ComboBox once I select the respective item.
Can anyone let me know on how to achieve this?
thanks
What you need to do is create a ResourceDictionary containing a few defined templates yourself. In the below, ComboBoxTemplateOne and ComboBoxTeplateTwo are user controls that are set out to display the combobox in the manor you want.
<UserControl.Resources>
<ResourceDictionary>
<DataTemplate x:Key="TemplateOne">
<local:ComboBoxTemplateOne />
</DataTemplate>
<DataTemplate x:Key="TemplateTwo">
<local:ComboBoxTemplateTwo />
</DataTemplate>
</ResourceDictionary>
</UserControl.Resources>
You will then need to create your own class that inherits from ContentControl "DataTemplateSelector", overriding OnContentChanged
Protected Overrides Sub OnContentChanged(ByVal oldContent As Object, ByVal newContent As Object)
MyBase.OnContentChanged(oldContent, newContent)
Me.ContentTemplate = SelectTemplate(newContent, Me)
End Sub
You will then need to create another class that inherits from the above DataTemplateSelector which overrides SelectTemplate ("TemplateSelectorClass"), which will return the DataTemplate defined above ("TemplateOne" or "TemplateTwo").
Also in this derived class, you will need to define a property for each of the templates you have
Public Property ComboboxTemplateOne As DataTemplate
Then head back to your XAML and n the blow XAML
<local:TemplateSelectorClass ComboboxTemplateOne="{StaticResource TemplateOne}" Content="{Binding Path=ActiveWorkspace}>
This should work, as it is effectively doing the same work as setting the "DataTemplate" property in WPF (which doesn't exist in SilverLight)
I realise there are a fair few steps here and its quite fiddly, but hopefully this will get you there. Any questions just shout.

Resources