Prism 7: Can’t display view - wpf

I'm trying to display a view with prism region manager. The problem is that Views are added to the RegionManager and ActiveViews is set but nothing is displaying in MainView(StartWindowView).
My Bootstrapper:
public class Bootstrapper: UnityBootstrapper
{
private readonly Action<Window> aR;
public Bootstrapper(Action<Window> AR)
{
aR = AR;
}
protected override DependencyObject CreateShell()
{
return Container.TryResolve<Views.StartWindowView>();
}
protected override void InitializeShell()
{
aR(Container.TryResolve<Views.StartWindowView>());
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterType(typeof(object), typeof(Views.TestView),"PlotListView");
Container.RegisterType(typeof(object), typeof(Views.SettingsView), "SettingsView");
Container.RegisterType<IAutoCadService, AutoCadService>
(new ExternallyControlledLifetimeManager());
Container.RegisterType<IPlotListViewModel, PlotListViewModel>
(new ExternallyControlledLifetimeManager());
}
}
My MainWindow(StartWindowView) with RegionManager.RegionName="ContentRegion":
Window x:Class="PlottingFastAutoCAD2016.Views.StartWindowView"
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"
Background="LightSkyBlue"
x:Name="window"
xmlns:res="clr-namespace:PlottingFastAutoCAD2016.ViewModels"
d:DataContext="{x:Static res:StartWindowViewModelDesign.Instanc}"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
ResizeMode="NoResize"
SizeToContent="WidthAndHeight"
d:DesignHeight="500"
d:DesignWidth="600">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Button Width="50"
Grid.Column="0"
Padding="0"
HorizontalAlignment="Left"
BorderThickness="0"
Height="Auto"
Click="Button_Click"
Command="{Binding ElementName=window,
Path=DataContext.NavigationCommand}"
CommandParameter="PlotListView"
Background="Transparent">
<StackPanel VerticalAlignment="Stretch"
Margin="3">
<Image Stretch="Fill"
Source="/PlottingFastAutoCAD2016;component/Resources/Icon/printer-.png"/>
<TextBlock Text="Plot"
HorizontalAlignment="Center"
Foreground="White"/>
</StackPanel>
</Button>
<Button Width="50"
Grid.Column="1"
Padding="0"
BorderThickness="0"
Height="Auto"
Command="{Binding ElementName=window,
Path=DataContext.NavigationCommand}"
CommandParameter="SettingsView"
Background="Transparent">
<StackPanel VerticalAlignment="Stretch"
Margin="3">
<Image Stretch="Fill"
Source="/PlottingFastAutoCAD2016;component/Resources/Icon/settings.png"/>
<TextBlock Text="Settings"
HorizontalAlignment="Center"
Foreground="White"/>
</StackPanel>
</Button>
</Grid>
<ItemsControl prism:RegionManager.RegionName="ContentRegion"
Grid.Row="1"
x:Name="contentRegion"
/>
</Grid>
</Window>
My ModelView:
public class StartWindowViewModel : BindableBase, IStartWindowViewModel
{
private readonly IRegionManager regionManager;
public StartWindowViewModel(IRegionManager regionManager)
{
this.regionManager = regionManager;
NavigationCommand = new DelegateCommand<string>(Navigate);
}
private void Navigate(string uri)
{
regionManager.RequestNavigate("ContentRegion", new Uri(uri, UriKind.Relative),
r => {
if (r != null) ;
//MessageBox.Show("Result: "+r.Result);
else MessageBox.Show("Error: " + r.Error.Message);
});
}
public DelegateCommand<string> NavigationCommand { get; set; }
}
Anyone have idea what is going on? I have spent three days to resolve it but no luck.

Related

Data no showing in UserControl

When i run the code, no data is shown in the UI. Data is there in the Person object but not showing in UI.
The list is getting populated. There are 10 items in the person object and i can see 10 items being created in the UI but the name and age are not showing.
In visual studio preview i can see data
UserControl XAML
<UserControl x:Class="BlankApp1.Views.PersonUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Margin="10 3"/>
<TextBlock Text="{Binding Age}" Margin="10 3" Grid.Column="1"/>
</Grid>
</UserControl>
Model
public class PersonModel : ObservableBase
{
private string name;
public string Name
{
get { return name; }
set { Set(ref name, value); }
}
private int age;
public int Age
{
get { return age; }
set { Set(ref age, value); }
}
}
MainViewModel
public class MainWindowViewModel : BindableBase
{
private string _title = "Prism Application";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public MainWindowViewModel()
{
Mock();
}
public ObservableCollection<PersonModel> Persons { get; set; }
= new ObservableCollection<PersonModel>();
private Random rand = new Random();
private void Mock()
{
for (int i = 0; i < 10; i++)
{
Persons.Add(new PersonModel
{
Name = string.Format("Person {0}", i),
Age = rand.Next(20, 50)
});
}
}
}
MainView XAML
<Window x:Class="BlankApp1.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
xmlns:local="clr-namespace:BlankApp1.ViewModels"
xmlns:model="clr-namespace:BlankApp1"
xmlns:view="clr-namespace:BlankApp1.Views"
prism:ViewModelLocator.AutoWireViewModel="True"
Title="{Binding Title}" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.Resources>
<DataTemplate DataType="{x:Type model:PersonModel}">
<view:PersonUserControl/>
</DataTemplate>
</Grid.Resources>
<TextBlock Text="ItemsControl Example" FontWeight="Bold" Margin="4 10"/>
<Border BorderThickness="1" BorderBrush="Silver" Margin="4" Grid.Row="1">
<ScrollViewer HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Persons}"/>
</ScrollViewer>
</Border>
<TextBlock Text="ListBox Example" FontWeight="Bold" Margin="4 10" Grid.Column="1"/>
<ListBox ItemsSource="{Binding Persons}" Margin="4" Grid.Row="1" Grid.Column="1">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
</Window>
prism:ViewModelLocator.AutoWireViewModel="True" sets the DataContext of the PersonUserControl to a view model which means that the binding to the properties of the PersonModel object that you create in the MainWindowViewModel fails.
So you should remove prism:ViewModelLocator.AutoWireViewModel="True" from the XAML markup.

Binding user control from parent datacontex WPF

Im trying to bind/link a datagrid from my main window
MainForm:
<dx:DXWindow
x:Class="LicenceManagerWPF.Forms.frmCustomerLicense"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
dx:ThemeManager.ThemeName="Office2016"
xmlns:ctr="clr-namespace:LicenceManagerWPF.Controls"
Title="CustomerLicence" Height="800" Width="1000"
WindowStartupLocation="CenterScreen" Loaded="DXWindow_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition MinHeight="200" Height="200*"/>
<RowDefinition Height="200*"/>
<RowDefinition MinHeight="25" Height="25"/>
</Grid.RowDefinitions>
<StackPanel x:Name="Stack_Top" Orientation="Horizontal" Grid.Row="0" >
<dx:SimpleButton x:Name="btnRefresh" Style="{StaticResource ResourceKey=BtnSmall}" ToolTip="Refresh Licenses" Glyph="{dx:DXImage Image=Refresh_32x32.png}" Content="Resfresh" />
<dx:SimpleButton x:Name="btndNew" Style="{StaticResource ResourceKey=BtnSmall}" ToolTip="New License" Glyph="{dx:DXImage Image=New_32x32.png}" Content="New Customer" />
<dx:SimpleButton x:Name="btnDelete" Style="{StaticResource ResourceKey=BtnSmall}" ToolTip="Delete Licence" Content="Delete" Glyph="{dx:DXImage Image=Cancel_32x32.png}"/>
<dx:SimpleButton x:Name="btnEdit" Style="{StaticResource ResourceKey=BtnSmall}" ToolTip="Edit Customer" Glyph="{dx:DXImage Image=EditContact_32x32.png}" />
<TextBlock Text="Customer: " FontSize="20" Margin="5"/>
<TextBlock Text="{Binding Customer.Name}" FontSize="20"/>
</StackPanel>
<ctr:Licences TblLicenses ="{Binding LicensesTable}" Grid.Row="1">
</ctr:Licences>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ctr:LicenseDetail x:Name="ct_LicenseDetail" Grid.Column="0"/>
<ctr:LicenceLog x:Name="ct_LicenseLog" Grid.Column="1"/>
</Grid>
</Grid>
I created this control:
<UserControl x:Class="LicenceManagerWPF.Controls.Licences"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
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="500"
x:Name="ctrl_Licenses">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="70" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="Licence List" Grid.Row="0" FontSize="22" Margin="10" TextAlignment="Left" VerticalAlignment="Center" />
<dxg:GridControl x:Name="grdLicences" ItemsSource="{Binding Path=TblLicenses,ElementName=ctrl_Licenses}" Grid.Row="1"/>
</Grid>
I asaigned the control in one row of the grid in the main window.
The main window is linked(data context) to one class that has this methods
private DataTable GetLicensesTable()
{
var dt = new DataTable();
dt.Columns.AddRange(new DataColumn []{
new DataColumn("SerialNumber",typeof(string)),
new DataColumn("Product",typeof(string)),
new DataColumn("Status",typeof(string)),
new DataColumn("ActivationMode",typeof(string)),
new DataColumn("MaxComputers", typeof(int)),
new DataColumn("NumActive",typeof(int)),
new DataColumn("Description",typeof(string))
});
_Licenses.ForEach((x) => {
var rw = dt.NewRow();
rw["SerialNumber"] = x.SerialNumber;
rw["Product"] = x.Product.Name;
rw["Status"] = x.Status;
rw["ActivationMode"] = Enum.GetName(typeof(ActivationModeEnum), x.ActivationMode); //x.ActivationMode;
rw["MaxComputers"] = x.MaxComputers;
rw["NumActive"] = Activated(x.Product.ProductId);
rw["Description"] = x.Description;
dt.Rows.Add(rw);
});
return dt;
}
public DataTable LicensesTable{
get { return GetLicensesTable(); }
}
what i want is to display the table in the grid that is in the usercontrol.
It is posible?
I tryed this in the code behind my main window:
private void DXWindow_Loaded(object sender, RoutedEventArgs e)
{
if (_CustomerLicense != null)
{
this.DataContext = _CustomerLicense;
this.ct_LicensesList.grdLicences.ItemsSource = _CustomerLicense.LicensesTable();
}
else
{
this.DataContext = _CustomerLicense.LicensesTable();
}
}
it says that tblLicenses is not reconized or not accesible.
Runnin the part of the code behin it works but i think its incorrect the way that im using the control.
Regards
Try this:
<dxg:GridControl x:Name="grdLicences" ItemsSource="{Binding Path=DataContext.LicensesTable, RelativeSource={RelativeSource AncestorType=Window}}" Grid.Row="1"/>
It should work provided that the DataContext of the window has a LicensesTable property.

WPF MVVM ListBox does not display last record

I find the problem I have very strange.
I have a WPF application using MVVM pattern.
I retrieve data from my database using Linq-to-SQL and display the Description field data in a ListBox using binding.
It works, but not completely. For some reason the last record's does not display. I have verified it is fetched from the database. It cannot be selected; its not there at all.
The only way to get the record to appear is by setting focus to the ListBox and either scrolling the mouse scroller or actually moving down using the keyboard to past the last record (which is supposed to be the second last record). Once you do that, the record appears.
Another way to get the record to show up is update any of the records in the ListBox. I have a TextBox bound in two-way mode to the SelectedItem of the ListBox, So when I select an item, change the text in the TextBox and click the Update button, it calls the Command to do the database update, which works fine, but then also the missing record of the last record shows up.
Is there a rendering problem with ListBox and ListView, because I have tried both? Why does it seem like the ListBox needs to be "redrawn" before the last items appears?
CategoryModel.cs
public class CategoryModel
{
public int CategoryID { get; set; }
public string Description { get; set; }
public List<CategoryModel> categories = new List<CategoryModel>();
readonly SalesLinkerDataContext _dbContext = new SalesLinkerDataContext();
public void GetCategories()
{
categories.Clear();
var result = _dbContext.tblSalesCategories.ToList();
foreach (var item in result)
{
categories.Add(new CategoryModel
{
CategoryID = item.CategoryID,
Description = item.Description.Trim()
});
}
}
internal void Update(CategoryModel cm)
{
try
{
var category = (from a in _dbContext.tblSalesCategories
where a.CategoryID == cm.CategoryID
select a).FirstOrDefault();
if (category != null)
{
category.Description = cm.Description;
_dbContext.SubmitChanges();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
CategoriesViewModel.cs
public class CategoriesViewModel : ViewModelBase, IPageViewModel
{
public CategoryModel Categories = new CategoryModel();
private DelegateCommand _getCategoriesCommand;
private DelegateCommand _updateCategoryCommand;
/// <summary>
/// Describes the name that will be used for the menu option
/// </summary>
public string Name
{
get { return "Manage Categories"; }
}
public string Description
{
get { return Categories.Description; }
set
{
Categories.Description = value;
OnPropertyChanged("Description");
}
}
public List<CategoryModel> ReceivedCategories
{
get { return Categories.categories; }
set
{
Categories.categories = value;
OnPropertyChanged("ReceivedCategories");
}
}
public ICommand GetCategoriesCommand
{
get
{
if (_getCategoriesCommand == null)
{
_getCategoriesCommand = new DelegateCommand(GetCategories, CanGetCategories);
}
return _getCategoriesCommand;
}
}
private bool CanGetCategories()
{
return true;
}
private void GetCategories()
{
Categories.GetCategories();
ReceivedCategories = Categories.categories;
}
public ICommand UpdateCategoryCommand
{
get
{
if (_updateCategoryCommand == null)
{
_updateCategoryCommand = new DelegateCommand(UpdateCategory, CanUpdateCategory);
}
return _updateCategoryCommand;
}
}
private bool CanUpdateCategory()
{
return true;
}
private void UpdateCategory()
{
Categories.Update(Categories);
}
}
CategoriesView.xaml
<UserControl x:Class="SalesLinker.CategoriesView"
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:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="600" Background="White" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding GetCategoriesCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="45"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Margin="20,0,0,0" FontSize="20" HorizontalAlignment="Center" Content="Categories"/>
<ListView x:Name="LstCategories" ItemsSource="{Binding ReceivedCategories, Mode=TwoWay}" Grid.Column="0" Grid.Row="1"
VerticalAlignment="Stretch"
Background="LightGray"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
SelectionChanged="LstCategories_OnSelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Stretch" >
<TextBlock Text="{Binding Description }"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Command="{Binding AddCategoryCommand}" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" Height="50" Width="50" Margin="0,20,0,0" Background="Transparent" BorderThickness="0" BorderBrush="Transparent" >
<Image Source="/Images/Plus.png"/>
</Button>
<Button Command="{Binding RemoveCategoryCommand}" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" Height="50" Width="50" Margin="0,75,0,0" Background="Transparent" BorderThickness="0">
<Image Source="/Images/Minus.png"/>
</Button>
<Grid Grid.Row="1" Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="0" Grid.Column="0" Content="Description:"/>
<TextBox DataContext="CategoryModel" Grid.Row="0" Grid.Column="1" Width="250" Height="Auto" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0,0,0"
Text="{Binding SelectedItem.Description, ElementName=LstCategories}"/>
<Button Command="{Binding UpdateCategoryCommand}"
Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" Margin="10,0,0,0" Height="20" Width="120" Content="Update Description"/>
</Grid>
</Grid>
I am very new to MVVM so hopefully I am just not seeing something simple.
For some reason the last record's does not display. I have verified it is fetched from the database.
If your fetch all data from database, then it can be concluded that why you cannot see your last item is as you use using not correct layout. I mean static layout.
I suggest you to use dynamic layout, not static. I mean it is bad:
<Grid.RowDefinitions>
<RowDefinition Height="45"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
The following code is better and it affords you to see all items to be seen and to be resized accoriding the display and Width and Height of your Window or UserControl:
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
Let me show the full example:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Margin="20,0,0,0" FontSize="20" HorizontalAlignment="Center" Content="Categories"/>
<ListView x:Name="LstCategories" ItemsSource="{Binding ReceivedCategories, Mode=TwoWay}" Grid.Column="0" Grid.Row="1"
VerticalAlignment="Stretch"
Background="LightGray"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Stretch" >
<TextBlock Text="{Binding Description }"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Command="{Binding AddCategoryCommand}" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" Height="50" Width="50" Margin="0,20,0,0" Background="Transparent" BorderThickness="0" BorderBrush="Transparent" >
<Image Source="/Images/Plus.png"/>
</Button>
<Button Command="{Binding RemoveCategoryCommand}" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" Height="50" Width="50" Margin="0,75,0,0" Background="Transparent" BorderThickness="0">
<Image Source="/Images/Minus.png"/>
</Button>
<Grid Grid.Row="1" Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1.5*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Label VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="0" Grid.Column="0" Content="Description:"/>
<TextBox DataContext="CategoryModel" Grid.Row="0" Grid.Column="1" Height="Auto" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0,0,0"
Text="{Binding SelectedItem.Description, ElementName=LstCategories}"/>
<Button Command="{Binding UpdateCategoryCommand}"
Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" Content="Update Description"/>
</Grid>
Update:
In order to dispel any doubts, I've made a test to show that all items are shown:
I've made some test model class:
public class FooClass
{
public string Description { get; set; }
}
And I've populated your ListView in a loop:
public MainWindow()
{
InitializeComponent();
PopulateCollection();
}
private void PopulateCollection()
{
List<FooClass> fooColl = new List<FooClass>();
for (int i = 0; i <= 1000; i++)
{
fooColl.Add(new FooClass() { Description=i.ToString()});
}
LstCategories.ItemsSource = fooColl;
}
XAML:
<ListView x:Name="LstCategories" Grid.Column="0" Grid.Row="1"
VerticalAlignment="Stretch"
Background="LightGray"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Stretch" >
<TextBlock Text="{Binding Description }"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The result is:

Custom Data Binding to more than one thing WPF C#

I have a XAML file which has two things,
a Combo Box
a stackpanel
How to I make it such that a change in the combo box will automatically get the stackpanel to switch from one stack panel to another stackpanel.
My comboBox is something like
<ComboBox x:Name="MCbConnect" SelectedIndex="{Binding EnConnectionType}" Loaded="m_cbConnect_Loaded" SelectionChanged="m_cbConnect_SelectionChanged" Width="100"></ComboBox>
where EnConnectionType is a property like this
private ConnectionType _enConnectionType;
public ConnectionType EnConnectionType
{
get { return _enConnectionType; }
set { SetProperty(ref _enConnectionType, value, "EnConnectionType"); }
}
And ConnectionType is
public enum ConnectionType { Rs232 = 0, Can = 1, Ethernet = 2 };
So i have implemented INotifyChanged interface here already. But I dont know how to bind this data with a stackpanel container which will allow me to switch to a different stackpanel view automatically in the background.
Example of a XAML that i would like to switch to is
<GroupBox x:Class="Gui.CtrlCommSocketSettings"
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:src="clr-namespace:Akribis.Gui"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
Header="Comm Settings"
mc:Ignorable="d"
d:DesignHeight="80" d:DesignWidth="300">
<Grid Height="70" VerticalAlignment="Top">
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Right"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Margin" Value="0,0,3,0"/>
</Style>
<Style TargetType="TextBox">
<Setter Property="Width" Value="120"/>
<Setter Property="Margin" Value="0,1"/>
</Style>
<Style TargetType="CheckBox">
<Setter Property="Margin" Value="0,4"/>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Server:" Name="MTextBlockServer"/>
<TextBlock Grid.Row="1" Text="Port:"/>
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Server}" Name="MTextBoxServer"/>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Port}"/>
</Grid>
with cs file with something like
namespace Gui
{
public partial class CtrlCommSocketSettings
{
public CtrlCommSocketSettings()
{
InitializeComponent();
}
}
}
I dont want to do this programatically as I know i want to avoid coupling between the model and the view together.
example of what i dont want to do but have at the moment:
in the main XAML, I have an empty stackpanel
<StackPanel Orientation="Vertical" Name="MCtrlCommSettings"></StackPanel>
and i am explicitly adding to this stackpanel by doing something like
MCtrlCommSettings.Children.Clear();
MCtrlCommSettings.Children.Add(_serverCtrlCommSettings);
How do i go about doing this automatically? Like how InotifyChanges will update between views and model automatically. Any suggestion will be gladly welcomed.
Reading online, it seems i need to implement some kind of an observable list
I'd suggest to go with DataTemplates and separate ViewModels for each connection type. Just specify DataTemplates with target type of each ViewModel, and after that use ContentControl, with content property binded CurrentConnection property of your main view model, which would depend on the SelectedValue of the ConnectionType combobox.
UPDATE
Source code to illustrate the solution:
XAML
<Window x:Class="MVVMExample.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:MVVMExample"
mc:Ignorable="d"
Title="MainWindow" Height="250" Width="425">
<Window.Resources>
<DataTemplate DataType="{x:Type local:Rs232ConnectionViewModel}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Rs232Port:" />
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Rs232Port}" />
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type local:CanConnectionViewModel}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="CanParam:" />
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding CanParam}" />
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type local:EthernetConnectionViewModel}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Server:" />
<TextBlock Grid.Row="1" Text="Port:"/>
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding EthernetServer}" />
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding EthernetPort}"/>
</Grid>
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ComboBox x:Name="MCbConnect" SelectedValue="{Binding CurrentConnectionType}" ItemsSource="{Binding ConnectionTypes}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ConnectionType}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ContentControl Grid.Row="1" Content="{Binding CurrentConnectionType}" />
</Grid>
</Window>
C#
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class MainWindowViewModel : INotifyPropertyChanged
{
ObservableCollection<ConnectionTypeViewModel> _connectionTypes;
public ObservableCollection<ConnectionTypeViewModel> ConnectionTypes
{
get { return _connectionTypes; }
private set { _connectionTypes = value; }
}
public MainWindowViewModel()
{
ConnectionTypes = new ObservableCollection<ConnectionTypeViewModel>(new ConnectionTypeViewModel[]
{
new Rs232ConnectionViewModel() { ConnectionType = ConnectionType.Rs232, Rs232Port="COM1"},
new CanConnectionViewModel() { ConnectionType = ConnectionType.Can},
new EthernetConnectionViewModel() { ConnectionType = ConnectionType.Ethernet, EthernetServer="tcp://xxxx"},
});
CurrentConnectionType = ConnectionTypes[2];
}
private ConnectionTypeViewModel _currentConnectionType;
public ConnectionTypeViewModel CurrentConnectionType
{
get { return _currentConnectionType; }
set
{
_currentConnectionType = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentConnectionType)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class ConnectionTypeViewModel : INotifyPropertyChanged
{
private ConnectionType _connectionTypeName;
public ConnectionType ConnectionType
{
get { return _connectionTypeName; }
set { _connectionTypeName = value; OnPropertyChanged(); }
}
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class Rs232ConnectionViewModel : ConnectionTypeViewModel
{
private string _rs232Port;
public string Rs232Port
{
get { return _rs232Port; }
set { _rs232Port = value; OnPropertyChanged(); }
}
}
public class CanConnectionViewModel : ConnectionTypeViewModel
{
private string _canParam;
public string CanParam
{
get { return _canParam; }
set { _canParam = value; OnPropertyChanged(); }
}
}
public class EthernetConnectionViewModel : ConnectionTypeViewModel
{
private string _ethernetServer;
public string EthernetServer
{
get { return _ethernetServer; }
set { _ethernetServer = value; OnPropertyChanged(); }
}
private string _ethernetPort;
public string EthernetPort
{
get { return _ethernetPort; }
set { _ethernetPort = value; OnPropertyChanged(); }
}
}
public enum ConnectionType { Rs232 = 0, Can = 1, Ethernet = 2 };

Command binding is not working

I have a user control where one text box and button is there
<UserControl x:Class="Search.View.SearchView"
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:viewModel="clr-namespace:Search.ViewModel" x:Name="SearchUserControl"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="250" DataContext="{DynamicResource SearchViewModel}">
<UserControl.Resources>
<viewModel:SearchViewModel x:Key="SearchViewModel"></viewModel:SearchViewModel>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Grid.Column="0" HorizontalAlignment="Right">
<TextBox x:Name="TxtSearch" Height="20" Width="100"></TextBox>
<Button x:Name="BtnSearchButton" Content="Search" Height="20" Command="{Binding SearchCommand}" Width="Auto" Margin="5,0,5,0" ></Button>
</StackPanel>
</Grid>
</UserControl>
in in my ViewModel file :
public RelayCommand SearchCommand { get; set; }
public SearchViewModel()
{
SearchCommand = new RelayCommand(TestSearch);
}
public void TestSearch(object p)
{
}
when i am using this user control on any view . Command binding is not working any help will be highly appreciated

Resources