In WPF, displaying only empty fields - c#

In WPF, I have a ListView which is bounded to a Dictionary (InpLangList) and a CheckBox bounded with a boolean(IsShowEmptyFields) property.
Eg. private Dictionary<string, string> _langList = new Dictionary<string, string>();
<ListView ItemsSource="{Binding InpLangList, Mode=TwoWay}" >
<ListView.View>
<GridView>
<GridViewColumn Header="Id" Width="Auto" DisplayMemberBinding="{Binding Key}" />
<GridViewColumn Header="Values" Width="Auto" DisplayMemberBinding="{Binding Value}" />
</GridView>
</ListView.View>
</ListView>
public Dictionary<string, string> InpLangList
{
get { return _langList ; }
set
{
_langList = value;
NotifyPropertyChanged();
}
}
(...)
InpLangList.Add("id1","One");
InpLangList.Add("id2","");
InpLangList.Add("id3","");
InpLangList.Add("id4","Four");
InpLangList.Add("id5","Five");
(...)
private bool _isShowEmptyFields;
public bool IsShowEmptyFields
{
get { return _isShowEmptyFields; }
set
{
_isShowEmptyFields = value;
NotifyPropertyChanged();
}
}
What I need is, if Checkbox is checked, then I want to display only the empty fields,
i.e.
InpLangList.Add("id2","");
InpLangList.Add("id3","");
should be displayed in the ListView
else entire InpLangList should be displayed in the ListView.

Use CollectionView:
ViewModel:
// Actual data source
Dictionary<string, string> inpLangList = new Dictionary<string, string>();
// A presentation of your data that you can group, sort, filter, etc
public ICollectionView InpLangList { get; set; }
private bool _isShowEmptyFields;
public bool IsShowEmptyFields
{
get { return _isShowEmptyFields; }
set
{
_isShowEmptyFields = value;
// if the presentation of your data is assigned - filter it
InpLangList?.Refresh();
}
}
// ViewModel constructor
public VM()
{
inpLangList.Add("id1", "One");
inpLangList.Add("id2", "");
inpLangList.Add("id3", "");
inpLangList.Add("id4", "Four");
inpLangList.Add("id5", "Five");
// note what's going next:
// assigning the data source to it's presentation (view)
InpLangList = CollectionViewSource.GetDefaultView(inpLangList);
// assigning filter that will be applied to your data source
// before the showing it within the UI
InpLangList.Filter = (obj) =>
{
if (!(obj is KeyValuePair<string, string> pair))
return false;
return !IsShowEmptyFields || string.IsNullOrEmpty(pair.Value);
};
}
View:
<CheckBox IsChecked="{Binding IsShowEmptyFields}" Content="Empty only"/>
<ListView ItemsSource="{Binding InpLangList}" >
<ListView.View>
<GridView>
<GridViewColumn Header="Id" Width="Auto" DisplayMemberBinding="{Binding Key}" />
<GridViewColumn Header="Values" Width="Auto" DisplayMemberBinding="{Binding Value}" />
</GridView>
</ListView.View>
</ListView>

Related

C# WPF Loop & Delete Checked ListView Items

As someone who has recently switched from WinForms to WPF, I'm still struggling and going nuts trying to figure out a way to loop through and delete checked ListView items.
This method gives me error: "ListView does not contain a definition for CheckedItems..."
if (lvFilesList != null)
{
foreach (ListViewItem lvItem in lvFilesList.CheckedItems)
{
lvItem.Checked = False;
}
}
My XAML Code:
<ListView Height="400" Width="400"
Name="lvFilesList"
ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="chk" IsChecked="{Binding IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></CheckBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}"/>
<GridViewColumn Header="File" DisplayMemberBinding="{Binding File}"/>
<GridViewColumn Header="Author" DisplayMemberBinding="{Binding Author}"/>
</GridView.Columns>
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock FontWeight="Bold" Text="Group"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
It looks odd that the ItemsSource of your ListView is directly bound to the current DataContext by
ItemsSource="{Binding}"
The DataContext would usually hold a view model object with a collection-type property like
public class Item
{
public bool IsChecked { get; set; }
// other properties like ID, File, Author
}
public class ViewModel
{
public ObservableCollection<Item> Items { get; }
= new ObservableCollection<Item>();
}
and the Binding would be
ItemsSource="{Binding Items}"
Then the view model could have a method that deletes all checked items, like
public void DeleteCheckedItems()
{
var checkedItems = Items.Where(item => item.IsChecked).ToList();
checkedItems.ForEach(item => Items.Remove(item));
}
Note that you usually assign an instance of the view model class to the DataContext of your main view, e.g. in the MainWindow constructor:
private readonly ViewModel viewModel = new ViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = viewModel;
viewModel.Items.Add(new Item { ID = 1, ... });
viewModel.Items.Add(new Item { ID = 2, ... });
}

ListView with Dictionary

Hello I'm looking for a way to use listview with Dictionary.
public class ServiceDataObject : IEquatable<ServiceDataObject>
{
public int ServiceID { get; set; }
public string ServiceName { get; set; }
public bool Status { get; set; }
public string ReccomendedStatus { get; set; }
public string WhoMade { get; set; }
public bool Equals(ServiceDataObject other)
{
if (other == null) return false;
return (this.ServiceID.Equals(other.ServiceID));
}
}
public static Dictionary<int, ServiceDataObject> ServiceData = new Dictionary<int, ServiceDataObject>();
This is how my dictionary looks like.
lvUsers.ItemsSource = Order_CONTROLS.ServiceData;
This is how I assign data to listview
And lvUsers listview:
<ListView Margin="10" Name="lvUsers">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<RadioButton IsChecked="{Binding Status}" GroupName="{Binding ServiceName}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<DataTemplate.Resources>
<local:InvertBooleanConverter x:Key="InvertBooleanConverter" />
</DataTemplate.Resources>
<RadioButton IsChecked="{Binding Status, Converter={StaticResource InvertBooleanConverter}}" GroupName="{Binding ServiceName}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Reccomendation" Width="120" DisplayMemberBinding="{Binding ReccomendedStatus}" />
<GridViewColumn Header="Description" Width="50" DisplayMemberBinding="{Binding ServiceName}" />
</GridView>
</ListView.View>
Problem is that it does not print data to items only correct, only number of rows are correct, but no data output, can anyone tell what I did wrong and if possible without using LIST(T)?
The solution is to set Values Collection to ItemsSource of the ListView:
lvUsers.ItemsSource = Order_CONTROLS.ServiceData.Values;
Remember also that Dictionary isn't Observable -> INotifyCollectionChanged & INotifyPropertyChanged interfaces aren't implemented.
So if you add a new element to the dictionary, your view will not see this change.

wpf Bind Listbox in Listview column subclass Object

i have a properties 'AllShobeh'
public struct listViewShobehItem
{
string _code;
string _name;
string _tell;
string _address;
List<string> _atms;
public string Code
{
get
{
return _code;
}
set
{
_code = value;
}
}
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
public string Tell
{
get
{
return _tell;
}
set
{
_tell = value;
}
}
public string Address
{
get
{
return _address;
}
set
{
_address = value;
}
}
public List<string> Atms
{
get
{
return _atms;
}
set
{
_atms = value;
}
}
}
ObservableCollection<listViewShobehItem> _AllShobeh = new ObservableCollection<listViewShobehItem>();
public ObservableCollection<listViewShobehItem> AllShobeh
{
get { return _AllShobeh; }
set
{
_AllShobeh = new ObservableCollection<listViewShobehItem>(value);
OnPropertyChanged("AllShobeh");
}
}
My Code in constructor :
AllShobeh = new ObservableCollection<listViewShobehItem>(from a in STATICS.db.shobehs
select new listViewShobehItem() {Code = a.code,Name=a.name,Tell=a.tell,Address=a.address,Atms=(from at in STATICS.db.atms
where at.shobehCode==a.code
select at.code + " - " + at.name).ToList()});
listviewShobeh.DataContext = this;
this.DataContext = this;
listviewShobeh.ItemsSource = AllShobeh;
i want show AllShobeh in a listview and show Atms in last column of listView in Listbox ...
this is my Xaml Code :
<ListView Name="listviewShobeh" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Margin="5" SelectionMode="Single">
<ListView.View>
<GridView>
<GridViewColumn x:Name="colCode" Header="code" DisplayMemberBinding="{Binding Path=Code}"/>
<GridViewColumn Header="name" DisplayMemberBinding="{Binding Path=Name}"/>
<GridViewColumn Header="tell" DisplayMemberBinding="{Binding Path=Tell}"/>
<GridViewColumn Header="address" DisplayMemberBinding="{Binding Path=Address}"/>
<GridViewColumn Header="atms" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Expander>
<ListBox ItemsSource="{Binding ElementName=listviewShobeh,Path=Atms}" DisplayMemberPath="{Binding Path=.}"/>
</Expander>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
i cant bind Allshobeh.Atms to listBox Atms column ...
My Question In Pic
Delete ElementName and DisplayMemberPath from your binding.
<DataTemplate>
<Expander>
<ListBox ItemsSource="{Binding Path=Atms}" />
</Expander>
</DataTemplate>
Also, more importantly, you're confused about DataContext and ViewModel class, let me know if you need specific help about this point.

WPF ListView Column of Text Some Rows Underlined Some Not

I need to display databound data in a listview such that some of the cells of the same column are underlined while others are not:
How do I create a data template that will display different control types in the same cell? (Visual Studio 2013, .NET 4.5.2)
XAML:
<ListView Grid.Column="3" ItemsSource="{Binding Results.MyItemSource, Mode=OneWay}">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Width="Auto" Header=" " DisplayMemberBinding="{Binding Path=Caption, Mode=OneWay}"/>
<GridViewColumn Width="Auto" Header=" " DisplayMemberBinding="{Binding Path=Value, Mode=OneWay}" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
ItemSource:
public List<object> MyItemSource
{
get
{
return new List<object>
{
new CaptionValuePair {Caption = "Caption1", Value = new TextBlock {Text = "Value1"}},
new CaptionValuePair {Caption = "Caption2", Value = new TextBlock {Text = "Value2", TextDecorations = TextDecorations.Underline}}
};
}
}
Bound type:
public class CaptionValuePair
{
public string Caption { get; set; }
public object Value { get; set; }
}
Problem: The StackPanel is just displaying the typename of a textblock.
Instead of a StackPanel, using an ItemsControl and binding its ItemsSource property worked.
XAML:
<GridViewColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Path=Value, Mode=OneWay}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
Bound type:
public List<UIElement> Value{ get; set; }

Binding a list with another list with WPF

Straight to the point. I'm writing a program using MVVM and I have made a view like this:
Class structure:
class Company
{
int CompanyID
string Name
List<Material> MaterialList
}
class Material
{
int ID
string Name
string Description
}
Here is the XAML code of my View (deleted most of the irrelevant stuff to make it more readable):
<ListView x:Name="_companies" ItemsSource="{Binding ElementName=_this, Path=ItemsSource}" SelectedItem="{Binding ElementName=_this, Path=SelectedItem}">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding CompanyID}" />
<GridViewColumn Header="Company Name" DisplayMemberBinding="{Binding CompanyName}" />
</GridView>
...
<ListView x:Name="_materials" >
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ElementName=_companies, Path=SelectedItem.MaterialID}"/>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding ElementName=_companies, Path=SelectedItem.Name"/>
</GridView>
</ListView.View>
</ListView>
<TextBox x:name="_description" Text="{Binding Description}" IsReadOnly="True" />
</StackPanel>
And a part of my MainView:
<Window.DataContext>
<viewModels:CompanyListViewModel />
</Window.DataContext>
<Grid>
<view:CompanyListView ItemsSource="{Binding Companies}" />
Companies is a list of Company objects containing Name, ID and MaterialList. The Companies list is displayed in the _companies ListView (code above).
Now after selecting a company from the list I want to display the assigned MaterialList in the _materials ListView.
After selecting a material in _materials I want to display its description in the _description TextBox
How do I do that? I found a similar thread that explains the concept but I still can't do it in my case. Can I bind to one of the SelectedItem properties ?
Refer the below code. I have done it using MVVM. You need use SelectedItem property of the listview and bind to the chid data listview.
<StackPanel>
<ListView x:Name="_companies" ItemsSource="{Binding Companies}" >
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" />
<GridViewColumn Header="Company Name" DisplayMemberBinding="{Binding Name}" />
</GridView>
</ListView.View>
</ListView>
<ListView x:Name="_materials" ItemsSource="{Binding ElementName=_companies,Path=SelectedItem.MaterialList}" >
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}"/>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
</GridView>
</ListView.View>
</ListView>
<TextBox x:Name="_description" Text="{Binding ElementName=_materials, Path=SelectedItem.Description}" IsReadOnly="True" />
</StackPanel>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
}
class MainViewModel
{
private ObservableCollection<Company> companies;
public ObservableCollection<Company> Companies
{
get { return companies; }
set { companies = value; }
}
public MainViewModel()
{
companies = new ObservableCollection<Company>();
for (int i = 0; i < 10; i++)
{
Company comp = new Company();
comp.ID = i + 1;
comp.Name = "Comp" + i;
ObservableCollection<Material> matlist = new ObservableCollection<Material>();
for (int j = 0; j < 10; j++)
{
Material mat = new Material();
mat.ID = j + 1;
mat.Name = "Mat" + j + i;
mat.Description = "descrp" + j + i;
matlist.Add(mat);
}
comp.MaterialList = matlist;
companies.Add(comp);
}
}
}
class Company
{
private int id;
public int ID
{
get { return id; }
set { id = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private ObservableCollection<Material> materialList;
public ObservableCollection<Material> MaterialList
{
get { return materialList; }
set { materialList = value; }
}
}
class Material
{
private int id;
public int ID
{
get { return id; }
set { id = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private string description;
public string Description
{
get { return description; }
set { description = value; }
}
}

Categories