I want to rearrange the ObservableCollection which is completed in nature - wpf

I am working on WPF MVVM.
I am fetching the records from database and
I have binded ObservableCollection to xaml Itemsource.
Fetch List Code :
private async void getKYCUserDetails()
{
var data = _DataService.Client;
var AllKYCUserList = await data.For<vwKYCUserDetails>().FindEntriesAsync();
lstTempKYCUserDetails= new ObservableCollection<vwKYCUserDetails>(AllKYCUserList);
}
I want to rearrange the ObservableCollection such that System must show clients whose details are complete in nature on top of the report so user can act as per JIT approach.
Xaml :
<syncfusion:SfDataGrid x:Name="dgKYCUser"
ItemsSource="{Binding Path = lstTempKYCUserDetails,Mode=TwoWay}"
SelectedItem="{Binding SelectedItem,Mode=TwoWay}"
NavigationMode="Row"
SelectionMode="Multiple"
ColumnSizer="Auto"
HeaderRowHeight="30"
AllowFiltering="True"
AllowSorting="True"
AllowGrouping="True"
ShowGroupDropArea="True"
HeaderStyle="{StaticResource headerStyle}"
AllowResizingColumns="True"
AllowDraggingColumns="True"
AllowDrop="True"
AutoGenerateColumns="False"
Foreground="#3e4345"
AllowEditing="True"
FrozenColumnCount="2"
BorderBrush="Red"
Background="White"
>
I have multiple columns in sfDatagrid in that I am converting boolean value to image using Converter and show image.
e.g
<syncfusion:GridImageColumn
ImageHeight="20" Width="30" ShowHeaderToolTip="True"
MappingName="bMobileVerify" HeaderText="Mobile Verified"
ValueBinding="{Binding bMobileVerify, Converter={StaticResource ImageConverter}}"
/>
The ImageConverter Code :
public class ImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((Boolean)value == true)
{
return new BitmapImage(new Uri(string.Format(#"..\..\Images\{0}", "check.png"), UriKind.Relative));
}
else if ((Boolean)value == false)
{
return new BitmapImage(new Uri(string.Format(#"..\..\Images\{0}", "crosssqr.png"), UriKind.Relative));
}
return new BitmapImage(new Uri(string.Format(#"..\..\Images\{0}", "TransparentBackground.png"), UriKind.Relative));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I want the records which has most ticks should on the top likewise it should have arranged, I don't have any clue how to rearrange it.

you can use ICollectionView
ICollectionView view = CollectionViewSource.GetDefaultView(lstTempKYCUserDetails);
view.SortDescriptions.Add(new SortDescription("tickscounter", ListSortDirection.Descending));

Related

WPF Multi-Binding / Aggregate Binding to Collection

I have a Control that I want to automatically disappear if another control has no visibile children. I'm not sure how to implement that though. I feel as though I need to create a binding that returns bindings for each child element's visible property and then aggregates them into a MultiValueConverter. I think it is working but it seems as though when I add items to my collection, the collection binding isn't being re-evaluated. Has anyone done this before?
Below is my code:
<Grid.Resources>
<local:BindingExpander x:Key="BindingExpander"/>
<local:TestConverter x:Key="TestConverter" />
</Grid.Resources>
<Button Content="Button" HorizontalAlignment="Left" Margin="237,166,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click">
<Button.Visibility>
<MultiBinding Converter="{StaticResource TestConverter}">
<Binding ElementName="lstItems" Path="Items" Converter="{StaticResource BindingExpander}" ConverterParameter="Visibility"/>
</MultiBinding>
</Button.Visibility>
</Button>
<ListBox x:Name="lstItems" HorizontalAlignment="Left" Height="100" Margin="601,130,0,0" VerticalAlignment="Top" Width="100" DisplayMemberPath="Content"/>
and:
public class TestConverter : IMultiValueConverter {
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
var ret = Visibility.Collapsed;
foreach (var item in values) {
if(item is IEnumerable IE) {
foreach (var Child in IE) {
}
}
}
return ret;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
public class BindingExpander : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
var ret = new List<Binding>();
if(value is IEnumerable IE) {
foreach (var item in IE) {
ret.Add(new Binding(parameter.ToString()) {
Source = item,
Mode = BindingMode.OneWay
});
}
}
return ret;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
````
I have a Control that I want to automatically disappear if another
control has no visibile children..
Simply create a Boolean property which reports the status of what the other control is binding to such as:
public bool HasItems { get { return _SomeArray?.Any(); }}
This property can be as elaborate as needed, but a basic one above for the example is shown.
Then bind the visibility flag of the control in question to the HasItems.
Note that the HasItems does not have the plumbing for INotifyPropertyChanged. In the code(s) where items are added to the _SomeArray simply put in a call to PropertyChanged("HasItems")
On my blog I provide a basic example of that (Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Binding) which looks like this where someone would bind to IsMemebershipAtMax such as what you are doing:
public bool IsMembershipAtMax
{
get { return MemberCount > 3; }
}
public int MemberCount
{
get { return _MemberCount; }
set
{
_MemberCount = value;
OnPropertyChanged();
OnPropertyChanged("IsMembershipAtMax");
}
}
public List<string> Members
{
get { return _Members; }
set { _Members = value; OnPropertyChanged(); }
}

WPF Dependency Property for Image source with IValueConverter

I intend to create Usercontrol with boolean dependency property called IsPowerOn, When I change it True the PowerOn image load to Image.source and when I set IsPowerOn to Fals, the PowerOff image load to Image.source.
Here is my UserControl:
<UserControl x:Class="...UcPower"
...
<UserControl.Resources>
<local:PowerBoolean2Image x:Key="PowerBoolean2Image"/>
</UserControl.Resources>
<Grid>
<Image x:Name="imgPower" Source="{Binding Source, Converter={StaticResource PowerBoolean2Image}, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:UcPower}}}" />
</Grid>
And Code behind:
public static readonly DependencyProperty IsPowerOnProperty = DependencyProperty.Register("IsPowerOn", typeof(bool), typeof(UcPower),
new FrameworkPropertyMetadata(false) { BindsTwoWayByDefault = true });
public bool IsPowerOn
{
get
{
return (bool)GetValue(IsPowerOnProperty);
}
set
{
SetValue(IsPowerOnProperty, value);
}
}
And IValueConverter:
public class PowerBoolean2Image : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is bool))
{
return null;
}
if (value.Equals(true))
{
// Power On
return new BitmapImage(new Uri("pack://application:,,,/Resources/Power-On.png"));
}
else
{
// Power Off
return new BitmapImage(new Uri("pack://application:,,,/Resources/Power-Off.png"));
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
But it doesn't work I expect, whats the wrong with me?
You should bind to the IsPowerOn property:
<Image Source="{Binding IsPowerOn, ...}" />
instead of
<Image Source="{Binding Source, ...}" />
Besides that, the expression if (value.Equals(true)) looks rather strange. You could replace that by
if ((bool)value)
{
return new BitmapImage(new Uri("pack://application:,,,/Resources/Power-On.png"));
}
return new BitmapImage(new Uri("pack://application:,,,/Resources/Power-Off.png"));
or shorter:
return (bool)value
? new BitmapImage(new Uri("pack://application:,,,/Resources/Power-On.png"))
: new BitmapImage(new Uri("pack://application:,,,/Resources/Power-Off.png"));
When I use this code in IValueConverter I get Error: IOException: Cannot locate resource 'resources/power-on.png'. and cant see my form in design mode:
Uri("pack://application:,,,/Resources/Power-On.png")
But I can use Assembly name to solve the problem like this code:
Uri("pack://application:,,,/ReferencedAssembly;component/Resources/Power-On.png")

Is there a way to make this image binding more performant?

I am binding a list of 500 odd nicks to a list with a status image for each. The scrolling of the list is painfully slow, and so is flicking between tabs with different lists.
This is all caused by my recent change in which I added these images.
Is there a way to speed it up?
My bitmaps (very small 16*16) :
<BitmapImage x:Key="ActiveIcon" UriSource="/WPFClient;component/Images/active.png" />
<BitmapImage x:Key="IdleIcon" UriSource="/WPFClient;component/Images/idle.png" />
<BitmapImage x:Key="AwayIcon" UriSource="/WPFClient;component/Images/away.png" />
<BitmapImage x:Key="UnknownIcon" UriSource="/WPFClient;component/Images/unknown.png" />
My List :
<ListBox ItemsSource="{Binding Users}">
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel>
<Image Source="{Binding Status, Converter={StaticResource UserStatusToIconConverter}}" Height="16" Width="16" Margin="0,0,5,0" />
<TextBlock Text="{Binding Nick}" />
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My converter :
public class UserStatusToIconConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string userStatus = value.ToString();
string iconName = "UnknownIcon";
switch (userStatus)
{
case "Active":
iconName = "ActiveIcon";
break;
case "Idle":
iconName = "IdleIcon";
break;
case "Away":
iconName = "AwayIcon";
break;
}
return iconName;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
NOTE: The code also DOES NOT work as it currently stands, no image is actually displayed. However I assume thats a minor detail somewhere.
Try using VirtualizationStackPanel will give some improvements
<ListBox VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling">
</ListBox>
in framework 4.5 VirtualizingPanel is available and setting VirtualizingPanel.ScrollUnit="Item" will give good performance improvement
The easiest way to solve that is to change converter to:
public class UserStatusToIconConverter : IValueConverter
{
private static readonly Uri ActiveIcon = new Uri("pack://application:,,,/WPFClient;component/Images/active.png");
private static readonly Uri IdleIcon = new Uri("pack://application:,,,/WPFClient;component/Images/idle.png");
private static readonly Uri AwayIcon = new Uri("pack://application:,,,/WPFClient;component/Images/away.png");
private static readonly Uri UnknownIcon = new Uri("pack://application:,,,/WPFClient;component/Images/unknown.png");
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var userStatus = value.ToString();
switch (userStatus)
{
case "Active":
return ActiveIcon;
case "Idle":
return IdleIcon;
case "Away":
return AwayIcon;
default:
return UnknownIcon;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
The slow-down is caused by improper binding.

Bind datatemplate image to an attribute of custom object in WPF

I have a collection
private ObservableCollection<ImageData> imageDataList = new ObservableCollection<ImageData>(); where ImageData is a custom object. It has an attribute called fileName a string that stores full path of an image file. In my XAML code, I have a listbox with datatemplate as the following.
<ListBox Name="listBox_ImageList" Grid.ColumnSpan="3" Grid.Row="2" SelectionChanged="listBox_ImageList_SelectionChanged">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding fileName}" Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox, AncestorLevel=1}, Path=ActualHeight}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
After populating ImagaData objects into imageDataList, I set this.listBox_ImageList.ItemsSource = imageDataList;
However, when I run it, I don't see any images. Can you please tell me how to databind properly to a string member of an object to WPF image source?
Checkout this http://social.msdn.microsoft.com/Forums/en-AU/wpf/thread/f94cc770-8d86-4a9f-a5f9-2ee2ea146c1a
Set the DataContext to where the object where the ObservableCollection is located
DateContext = this;
Also instead of fileName bind it to a ImageSource Property or a BitmapImage Property and this is created using the fileName.
To answer your question: You cannot bind the ImageSource property to a string. It works in XAML because WPF uses a default converter from string to ImageSource when you set the value in XAML. If you want to set the value with a binding or from code you need to provide an ImageSource object.
There are 2 ways to do it via binding:
The first one is presented here (the link Juan Carlos mentioned), and it involves creating a IValueConverter that will take your string and transform it to a ImageSource. I would modify the converter code presented there with this:
public sealed class StringToImageSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
return new BitmapImage(new Uri((string)value));
}
catch
{
return DependencyProperty.UnsetValue;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
The second option is to create your ImageSource in your ImageData class and bind directly to it.
private ImageSource _imageSource
public ImageSource ImageSource
{
get
{
if (_imageSource == null)
{
_imageSource = new BitmapImage(new Uri(fileName), UriKind.RelativeOrAbsolute);
}
return _imageSource;
}
}

Converter stops filter working

I am trying to display filenames in a listbox, retrieved from a particular directory. They are stored in an ObservableCollection of FileInfo objects:
public ObservableCollection<FileInfo> ProjectFiles
{
get
{
if (SelectedFolder == null) return null;
DirectoryInfo d= new DirectoryInfo(SelectedFolder);
if (!d.Exists) return null;
return new ObservableCollection<FileInfo>(d.EnumerateFiles("*.xsi"));
}
}
I have implemented a filter on the listbox, called when text is entered or changed in a textbox "FilesFilterBy":
private void FilterFiles_TextChanged(object sender, TextChangedEventArgs e)
{
ICollectionView view = CollectionViewSource.GetDefaultView(ProjectFiles);
view.Filter = new Predicate<object>(IsTextInFilename);
}
public bool IsTextInFilename(object item)
{
string Filename = Path.GetFileNameWithoutExtension((item as FileInfo).Name);
return (Filename.ToLower().Contains(FilesFilterBy.Text.ToLower()));
}
At the same time, I want to display only the names of the files, without path or extension. To this end I have implemented a converter:
public class RemoveExtensionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Path.GetFileNameWithoutExtension(value as string);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return new NotImplementedException();
}
}
Here is how the listbox is implemented in XAML:
<Window.Resources>
<ctr:RemoveExtensionConverter x:Key="JustFileName" />
</Window.Resources>
<ListBox ItemsSource="{Binding ProjectFiles}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding FullName, Converter={StaticResource JustFileName}}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Currently the converter works - only the file names are listed, but the filter no longer has any effect. When I enter text in the FileFilterBy textbox the TextChanged event is fired but the listbox stays the same. Also, the converter is not called at that point.
What am I doing wrong?
ProjectFiles returns a new collection every time. Your FilterFiles_TextChanged handler is calling ProjectFiles to create a new collection, setting a filter on that new collection, and then throwing it away. The collection bound to the ListBox is not affected. You need to change ProjectFiles to keep the same collection object. Maybe something like this:
private ObservableCollection<FileInfo> _projectFiles;
public ObservableCollection<FileInfo> ProjectFiles
{
get
{
if (_projectFiles == null)
{
if (SelectedFolder == null) return null;
DirectoryInfo d = new DirectoryInfo(SelectedFolder);
if (!d.Exists) return null;
_projectFiles = new ObservableCollection<FileInfo>(
d.EnumerateFiles("*.xsi"));
}
return _projectFiles;
}
}
The Converter shouldn't affect the filter at all.

Resources