Multilevel WPF Tree - sql

I have this Tables :
iAccess:
-----------------
Id
UserRef
GroupRef
ActionRef
HasAccess
HasDetail
iAction
---------------------
Id
WindowsRef
ActionName
ActionPName
DisplayIndex
CanHasDetail
iWindow
-------------------
Id
OwnerRef
WinName
WinPName
DisplayIndex
iUser
------------------------
Id
GroupRef
LoginName
Password
IsEnable
HasFullAccess
GenerationDate
Image
How can I show the following resut in WPF Treeview
Expected Result :
-LoginName1
-WinName1
-ActionName1
-ActionName2
-WinName2
-ActionName1

you can use HierarchicalDataTemplate
<TreeView x:Name="MainTreeView" HorizontalAlignment="Stretch" Margin="10" VerticalAlignment="Stretch" ItemsSource="{Binding Departments}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Positions}" DataType="{x:Type VM:Department}">
<Label Content="{Binding DepartmentName}"/>
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Employees}" DataType="{x:Type VM:Position}">
<Label Content="{Binding PositionName}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate DataType="{x:Type VM:Employee}">
<Label Content="{Binding EmployeeName}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Position class:
public class Position : ViewModelBase
{
private List<Employee> employees;
public Position(string positionname)
{
PositionName = positionname;
employees = new List<Employee>()
{
new Employee("Employee1"),
new Employee("Employee2"),
new Employee("Employee3")
};
}
public List<Employee> Employees
{
get
{
return employees;
}
set
{
employees = value;
OnPropertyChanged("Employees");
}
}
public string PositionName
{
get;
set;
}
}
Department class
public class Department : ViewModelBase
{
private List<Position> positions;
public Department(string depname)
{
DepartmentName = depname;
positions = new List<Position>()
{
new Position("TL"),
new Position("PM")
};
}
public List<Position> Positions
{
get
{
return positions;
}
set
{
positions = value;
OnPropertyChanged("Positions");
}
}
public string DepartmentName
{
get;
set;
}
}
MainViewModel class:
public class MainWindowViewModel : ViewModelBase
{
private List<Department> departments;
public MainWindowViewModel()
{
Departments = new List<Department>()
{
new Department("DotNet"),
new Department("PHP")
};
}
public List<Department> Departments
{
get
{
return departments;
}
set
{
departments = value;
OnPropertyChanged("Departments");
}
}
}
you can read full article in http://www.c-sharpcorner.com/article/populating-hierarchical-data-in-treeview-in-wpf-using-mvvm/

Related

How to access the parent viewmodel from inside a ListView.ItemTemplate?

I have this simple ListView filled from an ObservableCollection. Once the list is bound, I would like to access the parent vm view model from inside this ItemTemplate so that I can bind the command called cmd_delete_mesh. How is this done for a UWP Xaml app (not wpf)?
<ListView x:Name="mesh_list" SelectedItem="{x:Bind vm.selected_mesh, Mode=TwoWay}" ItemsSource="{x:Bind vm.meshes}">
<ListView.ItemTemplate>
<DataTemplate>
<ListViewItem>
<Button Command="{Binding cmd_delete_mesh}"/>
You can do like so:
<ListView x:Name="mesh_list" SelectedItem="{x:Bind vm.selected_mesh, Mode=TwoWay}" ItemsSource="{x:Bind vm.meshes}">
<ListView.ItemTemplate>
<DataTemplate>
<ListViewItem>
<Button Command="{Binding ElementName=mesh_list, Path=DataContext.vm.cmd_delete_mesh}"/>
I do this from code unfortunately... I’ll post an example of my code soon
You could define your command in your model and declare an event in it. In your ViewModel, when you initialize the 'meshes' collection, you could register this event for every item in this collection. Then, when the command is executed, you just need to raise the event and do some operations in its event handler.
I made a simple code sample for your reference:
<ListView x:Name="mesh_list" SelectedItem="{x:Bind ViewModel.selected_mesh, Mode=TwoWay}" ItemsSource="{x:Bind ViewModel.meshes,Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:SubTest">
<ListViewItem>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Bind Name }"></TextBlock>
<Button Command="{x:Bind cmd_delete_mesh}" Content="delete"/>
</StackPanel>
</ListViewItem>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
ViewModel = new Test("test data");
}
private Test ViewModel { get; set; }
}
public class Test : ViewModelBase
{
public string Name { get; set; }
private SubTest _selected_mesh;
public SubTest selected_mesh
{
get { return _selected_mesh; }
set
{
if (_selected_mesh != value)
{
_selected_mesh = value;
RaisePropertyChanged("selected_mesh");
}
}
}
public ObservableCollection<SubTest> meshes { get; set; } = new ObservableCollection<SubTest>();
public Test(string name)
{
this.Name = name;
for (int i = 0; i < 10; i++)
{
var sub = new SubTest() { Name = "String " + i };
sub.DeleteParentItem += Test_DeleteParentItem;
meshes.Add(sub);
}
}
private void Test_DeleteParentItem()
{
if (selected_mesh != null)
{
DeleteItem(selected_mesh);
}
}
private void DeleteItem(SubTest subTest)
{
//TODO...
}
}
public class SubTest
{
public RelayCommand cmd_delete_mesh { get; set; }
public string Name { get; set; }
public event Action DeleteParentItem;
public SubTest()
{
cmd_delete_mesh = new RelayCommand(DeleteItem);
}
private void DeleteItem()
{
if (DeleteParentItem != null)
{
DeleteParentItem.Invoke();
}
}
}
Please note that the ViewModelBase and RelayCommand are from mvvmlight.
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;

Dynamic Presentation of Label as per the Data coming from web services Xamarin Forms

i am trying to render list of information inside a frame the information which comes up from database is in two parts ie "Description" : "Value"
so the row inside list make i group of description and value and some may not have
so can anyone help me how can i add the label to grid or stack as per the data which i get from my services because it could be 3 sometimes and it could be 5 sometime and creating label and binding them would be a static job
There is a very clean answer if you can use xamarin forms3.5 or greater, BindableLayout.
Xaml file
<ListView
x:Name="listView"
HasUnevenRows="True"
ItemsSource="{Binding Category}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Name}" TextColor="Blue" />
<StackLayout BindableLayout.ItemsSource="{Binding users}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label Text="{Binding Name}" />
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In my ViewModel
public class DynamicSwitchViewModel:BaseViewModel
{
public DynamicSwitchViewModel(ContentPage view):base(view)
{
ObservableCollection<User> users1 = new ObservableCollection<User>();
users1.Add(new User() { Name = "karan3" });
users1.Add(new User() { Name = "karan4" });
users1.Add(new User() { Name = "karan5" });
ObservableCollection<User> users2 = new ObservableCollection<User>();
users2.Add(new User() { Name = "karan1" });
users2.Add(new User() { Name = "karan2" });
users2.Add(new User() { Name = "karan3" });
users2.Add(new User() { Name = "karan4" });
users2.Add(new User() { Name = "karan5" });
ObservableCollection<User> users3 = new ObservableCollection<User>();
users3.Add(new User() { Name = "karan1" });
users3.Add(new User() { Name = "karan2" });
users3.Add(new User() { Name = "karan3" });
Category = new ObservableCollection<Category>();
Category.Add(new Category() { Name = "1",users=users1 });
Category.Add(new Category() { Name = "2",users=users2 });
Category.Add(new Category() { Name = "3",users=users3 });
}
private ObservableCollection<Category> category;
public ObservableCollection<Category> Category
{
get { return category; }
set { SetProperty(ref category, value); }
}
}
public class Category
{
public ObservableCollection<User> users { get; set; }
public string Name { get; set; }
}
public class User
{
public string Name { get; set; }
}

MVVM INotifyPropertyChanged not working

Please assist:
I have implemented the MVVM design on a simple app using Xamarin.
I have one Model (User) and one ViewModel (UserViewModel).
Please note that this app is my first Xamarin/MVVM app and that I am new to this.
The issue that i have is that adding or removing a User, the View does NOT update.
When I add or remove a user I can confirm that the Database is updated, but not my view.
Please see my code below, what am i missing?
User Model:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool IsActive { get; set; }
public List<Role> RolesList { get; set; }
}
UserViewModel Code:
public class UsersViewModel : INotifyPropertyChanged
{
private UserServices UserServ { get; set; }
public User UserSelected { get; set; }
private ObservableCollection<User> userList;
public ObservableCollection<User> UserList
{
get
{
return userList;
}
set
{
if (userList != value)
{
userList = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public UsersViewModel()
{
UserServ = new UserServices();
UsersLoadAsync();
}
public async void UsersLoadAsync()
{
UserList = await UserServ.UsersGetAsync();
}
}
User Helper Service code (Added for completeness)
public class UserServices
{
public async Task<ObservableCollection<User>> UsersGetAsync()
{
ObservableCollection<User> UserList = await App.UserService.GetAsync();
return UserList;
}
public async Task<bool> UsersAddAsync(User user)
{
bool success = await App.UserService.PostAsync(user);
return success;
}
public async Task<bool> UsersRemoveAsync(User user)
{
bool success = await App.UserService.DeleteAsync(user.Id, user);
return success;
}
}
View Xaml Code:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:PB_Logbook"
x:Class="PB_Logbook.MainPage"
xmlns:ViewModels="clr-namespace:PB_Logbook.ViewModels;assembly:PB_Logbook">
<ContentPage.BindingContext>
<ViewModels:UsersViewModel/>
</ContentPage.BindingContext>
<StackLayout>
<ListView ItemsSource="{Binding UserList, Mode=TwoWay}" HasUnevenRows="True" ItemSelected="Item_SelectedAsync" IsPullToRefreshEnabled="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" Padding="12,6">
<Label Text="{Binding Username}" FontSize="24"/>
<Label Text="{Binding FirstName}" FontSize="18" Opacity="0.6"/>
<Label Text="{Binding LastName}" FontSize="18" Opacity="0.6"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Text="Add" Clicked="AddButton_ClickedAsync"></Button>
<Button Text="Remove" Clicked="RemoveButton_ClickedAsync"></Button>
</StackLayout>
</ContentPage>
View code behind:
public partial class MainPage : ContentPage
{
private UserServices UserServices { get; set; }
private UsersViewModel UsersVM { get; set; }
public MainPage()
{
InitializeComponent();
UserServices = new UserServices();
UsersVM = new UsersViewModel();
}
private async void AddButton_ClickedAsync(object sender, EventArgs e)
{
await AddUserAsync();
}
private async void RemoveButton_ClickedAsync(object sender, EventArgs e)
{
await RemoveUserAsync();
}
private async void Item_SelectedAsync(object sender, EventArgs e)
{
UsersVM.UserSelected = ((User)((ListView)sender).SelectedItem);
}
private async void Pull_RefreshAsync(object sender, EventArgs e)
{
//UsersVM.UsersLoadAsync();
}
private async Task AddUserAsync()
{
Random rnd = new Random();
int rndNumber = rnd.Next(1, 100);
User user = new User()
{
Username = "User " + rndNumber,
FirstName = "Firstname " + rndNumber,
LastName = "Surname " + rndNumber,
IsActive = true
};
bool success = await UserServices.UsersAddAsync(user);
if (success)
{
if (!UsersVM.UserList.Contains(user))
UsersVM.UserList.Add(user);
}
}
private async Task RemoveUserAsync()
{
bool success = await UserServices.UsersRemoveAsync(UsersVM.UserSelected);
if (success)
{
if (UsersVM.UserList.Contains(UsersVM.UserSelected))
UsersVM.UserList.Remove(UsersVM.UserSelected);
}
}
}
The issue is with adding/removing users that does not update in my view.
Thank you.
If you're new to Xamarin MVVM, this link will help you understand the basics of MVVM in Xamarin Forms
https://deanilvincent.github.io/2017/06/03/basic-understanding-of-mvvm-and-databinding-in-xamarin-forms/
I would suggest as well, please lessen your behind the codes and just implement everything including the commands in your ViewModel.
You've written that your codes are working when saving and updating but not reflecting the view right? You should put your method in fetching the list right after your save command.
Like this in your xaml
<Button Text="Save" Command="{Binding SaveCommand}"/>
In your ViewModel, you should use Command from Xamarin
public Command SaveCommand{
get{
return new Command(async()=>{
// your command save here
// then put your method for fetching the updated list: your UsersLoadAsync();
});
}
}
If you're new to MVVM, you can also check this link. It uses Xamarin MVVM. When you finish, you'll have simple weather app with simple mvvm implementations
I hope it helps you

How binding data depending on the value?

I have ObservableCollection and value that need to find the item in the collection. any ideas? (p.s converter not good idea, because i have many collections)
This functionality (applying a filter) belongs into the ViewModel. Here is an easy example for illustration.
You might also want to look at the CollectionViewSource for a more refined version of the same concept.
Xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" >
<ListBox ItemsSource="{Binding MyClasses}" DisplayMemberPath="Name" Margin="5" />
<ListBox ItemsSource="{Binding MyFilteredClasses}" DisplayMemberPath="Name" Margin="5" />
<TextBox Text="{Binding MySelectedClass.Name}" Margin="5" />
</StackPanel>
</Window>
ViewModel:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
namespace WpfApplication1
{
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private ObservableCollection<Class1> _myClasses;
public ObservableCollection<Class1> MyClasses { get { return _myClasses; } set { _myClasses = value; OnPropertyChanged("MyClasses"); } }
private List<Class1> _myFilteredClasses;
public List<Class1> MyFilteredClasses { get { return _myFilteredClasses; } set { _myFilteredClasses = value; OnPropertyChanged("MyFilteredClasses"); } }
private Class1 _mySelectedClass;
public Class1 MySelectedClass { get { return _mySelectedClass; } set { _mySelectedClass = value; OnPropertyChanged("MySelectedClass"); } }
public ViewModel()
{
MyClasses = new ObservableCollection<Class1>()
{
new Class1() { Name = "Connelly" },
new Class1() { Name = "Donnelly" },
new Class1() { Name = "Fonnelly" },
new Class1() { Name = "McGregor" },
new Class1() { Name = "Griffiths" }
};
// filter your ObservableCollection by some criteria, and bind to the result (either another list, or just one item)
MyFilteredClasses = MyClasses.Where(c => c.Name.EndsWith("onnelly")).ToList();
MySelectedClass = MyClasses.FirstOrDefault(c => c.Name.StartsWith("Mc"));
}
}
public class Class1 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private string _name;
public string Name { get { return _name; } set { _name = value; OnPropertyChanged("Name"); } }
}
}

DisplayMemberPath of telerik GridViewComboBoxColumn

I have a telerik gridview
<UserControl x:Class="TelerikGridViewComboBoxExample.MainPage"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="143*" />
<RowDefinition Height="157*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<TextBlock Text="Good Sample"/>
<telerik:RadGridView x:Name="radGridView"
AutoGenerateColumns="False" ItemsSource="{Binding Peoples}">
<telerik:RadGridView.Columns>
<telerik:GridViewComboBoxColumn
DataMemberBinding="{Binding CountryID}"
UniqueName="Country"
SelectedValueMemberPath="Id"
DisplayMemberPath="Name"/>
<telerik:GridViewDataColumn DataMemberBinding="{Binding FirstName}" UniqueName="First Name"/>
<telerik:GridViewDataColumn DataMemberBinding="{Binding LastName}" UniqueName="Last Name"/>
</telerik:RadGridView.Columns>
</telerik:RadGridView>
</StackPanel>
</Grid>
</UserControl>
and here is a xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using Telerik.Windows.Controls;
namespace TelerikGridViewComboBoxExample
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
foreach (var x in
new People[] {
new People { CountryID = 0, FirstName = "Sebastain", LastName = "Vettel" },
new People { CountryID = 1, FirstName = "Fernando", LastName = "Alonso" },
new People { CountryID = 2, FirstName = "James", LastName = "Button" }
})
{
Peoples.Add(x);
}
foreach (var x in
new Country[] {
new Country { Id = 0, Name = "Germany",Nationality = "german"},
new Country { Id = 1, Name = "Spain" ,Nationality = "Spanish"},
new Country { Id = 2, Name = "UK" ,Nationality = "English"}
})
{
Countries.Add(x);
}
this.DataContext = this;
((GridViewComboBoxColumn)this.radGridView.Columns["Country"]).ItemsSource = Countries;
}
private ObservableCollection<People> peoples = new ObservableCollection<People>();
public ObservableCollection<People> Peoples
{
get { return peoples; }
set { peoples = value; }
}
private ObservableCollection<Country> countries = new ObservableCollection<Country>();
public ObservableCollection<Country> Countries
{
get { return countries; }
set { countries = value; }
}
}
public class People
{
public int CountryID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
public string Nationality { get; set; }
}
}
Everything works ok, but I want to display in countries column value Nationality, but as now I want in combo names of countries to choose.
so :
1. user clicks at row in Country column ,
2. selects Germany
3.value in row is Germnan.
if it is not possilbe, I want to have in that row first, and last letter of name of country(for example "gy")
I'm using 2010.1.603.1040 version of telerik silverlight pack.
Is it possible?
Best regards
use switch case with using row command by including a custom field(button) in the gridview code and pass record id(from db) as the argument
google "row command in .net" for just syntax
then you can perform whatever action you wish to perform