B.Balamanigandan B.Balamanigandan - 2 months ago 16
C# Question

How to return value via Dependency Property in two Way Binding WPF Custom Control C#?

I'm having a Custom Control it inherits the ListBox Control, in that I added two DependencyProperty one for getting input and another for send the processed output via binding.

Below is the Custom Control BListBox inherited by ListBox :- C# Coding

public class BListBox : ListBox
{
static BListBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(BListBox), new FrameworkPropertyMetadata(typeof(ListBox)));
}

public static readonly DependencyProperty FilterKeyProperty =
DependencyProperty.Register("FilterKey", typeof(string), typeof(BListBox), new UIPropertyMetadata(null));

public string FilterKey
{
get { return (string)GetValue(FilterKeyProperty); }
set { SetValue(FilterKeyProperty, value); }
}

public static readonly DependencyProperty FilterDictionaryProperty =
DependencyProperty.Register("FilterDictionary", typeof(Dictionary<string, ObservableCollection<CheckedListItem<string>>>), typeof(BListBox), new UIPropertyMetadata(null));

public Dictionary<string, ObservableCollection<CheckedListItem<string>>> FilterDictionary
{
get { return (Dictionary<string, ObservableCollection<CheckedListItem<string>>>)GetValue(FilterDictionaryProperty); }
set { SetValue(FilterDictionaryProperty, value); }
}

public static readonly DependencyProperty InputSourceProperty =
DependencyProperty.Register("InputSource", typeof(IEnumerable), typeof(BListBox), new UIPropertyMetadata(null));

public IEnumerable InputSource
{
get { return (IEnumerable)GetValue(InputSourceProperty); }
set { SetValue(InputSourceProperty, value); }
}

public static readonly DependencyProperty OutputSourceProperty = DependencyProperty.Register("OutputSource",
typeof(IEnumerable),
typeof(BListBox),
new FrameworkPropertyMetadata(
null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

public IEnumerable OutputSource
{
get { return (IEnumerable)GetValue(OutputSourceProperty); }
set { SetValue(OutputSourceProperty, value); }
}

ObservableCollection<dynamic> InputSourceCollection = new ObservableCollection<dynamic>();
ObservableCollection<dynamic> OutputSourceCollection = new ObservableCollection<dynamic>();
ObservableCollection<dynamic> SourceCollection = new ObservableCollection<dynamic>();

public void FilterResult(CheckedListItem<string> curFilter)
{
ObservableCollection<CheckedListItem<string>> CustomerFilters = ItemsSource != null ? ItemsSource as ObservableCollection<CheckedListItem<string>> : new ObservableCollection<CheckedListItem<string>>();

if (CustomerFilters.Count > 0)
{
if (InputSourceCollection.Count ==0)
InputSourceCollection = IEnumeratorToObservableCollection(InputSource);

OutputSourceCollection = IEnumeratorToObservableCollection(OutputSource);

if (FilterDictionary.Remove(FilterKey))
FilterDictionary.Add(FilterKey, new ObservableCollection<CheckedListItem<string>>(CustomerFilters));

RelationBetweenFiltersCheck(curFilter.Item.ToString());

List<string> _filterValueList = new List<string>();
foreach (var item in (FilterDictionary[curFilter.Key.ToString()] as ObservableCollection<CheckedListItem<string>>).Where(x => x.IsChecked == true))
{
_filterValueList.Add(item.Item);
}

List<string> keyList = new List<string>(FilterDictionary.Keys);

SourceCollection = new ObservableCollection<dynamic>();

foreach (var key in keyList)
{
foreach (var item in InputSourceCollection)
{
if (item.GetType().GetProperty(key) != null)
{
if (_filterValueList.Contains(item.GetType().GetProperty(key).GetValue(item, null).ToString()))
{
SourceCollection.Add(item);
}
}
}
}

OutputSource = SourceCollection;

RelationBetweenFiltersCheck();
}
}

private void RelationBetweenFiltersCheck(string unCheckKey = null)
{
List<string> fileterKey = new List<string>();

List<string> keyList = new List<string>(FilterDictionary.Keys);

foreach (var kItem in keyList)
{
if (fileterKey.Count == 0)
{
foreach (var item in OutputSourceCollection)
{
if (item.GetType().GetProperty(kItem) != null)
fileterKey.Add(item.GetType().GetProperty(kItem).GetValue(item, null).ToString());
}
}
else if (fileterKey.Count > 0)
{
foreach (var item in OutputSourceCollection)
{
if (item.GetType().GetProperty(kItem) != null)
fileterKey.Add(item.GetType().GetProperty(kItem).GetValue(item, null).ToString());
}
}
}

if (!string.IsNullOrEmpty(unCheckKey))
{
if (fileterKey.Any(s => unCheckKey.Contains(s)))
fileterKey.Remove(unCheckKey);
else
fileterKey.Add(unCheckKey);
}

foreach (var item in FilterDictionary)
{
ObservableCollection<CheckedListItem<string>> cList = new ObservableCollection<CheckedListItem<string>>();
cList = item.Value;
foreach (var sItem in cList)
{
sItem.IsChecked = fileterKey.Any(s => sItem.Item.Contains(s));
}
}
}


private ObservableCollection<dynamic> IEnumeratorToObservableCollection(IEnumerable source)
{

ObservableCollection<dynamic> SourceCollection = new ObservableCollection<dynamic>();

IEnumerator enumItem = source.GetEnumerator();
var gType = source.GetType();
string collectionFullName = gType.FullName;
Type[] genericTypes = gType.GetGenericArguments();
string className = genericTypes[0].Name;
string classFullName = genericTypes[0].FullName;
string assName = (classFullName.Split('.'))[0];

// Get the type contained in the name string
Type type = Type.GetType(classFullName, true);

// create an instance of that type
object instance = Activator.CreateInstance(type);

/// List of Propery for the above created instance of a dynamic class
List<PropertyInfo> oProperty = instance.GetType().GetProperties().ToList();

while (enumItem.MoveNext())
{
Object instanceInner = Activator.CreateInstance(type);
var x = enumItem.Current;

foreach (var item in oProperty)
{
if (x.GetType().GetProperty(item.Name) != null)
{
var propertyValue = x.GetType().GetProperty(item.Name).GetValue(x, null);
if (propertyValue != null)
{
// Get a property on the type that is stored in the
// property string
PropertyInfo prop = type.GetProperty(item.Name);

// Set the value of the given property on the given instance
prop.SetValue(instanceInner, propertyValue, null);
}
}
}

SourceCollection.Add(instanceInner);
}

return SourceCollection;
}

}


The XAML Code:

<cust:BListBox ItemsSource="{Binding CustomerFilters}" BorderThickness="0" FilterDictionary="{Binding dictionary, Mode= TwoWay, UpdateSourceTrigger=PropertyChanged}" FilterKey="{Binding FilterKey}" InputSource="{Binding MobileListPrimary}" OutputSource="{Binding MobileList, Mode=TwoWay}">
<cust:BListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Item}" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.FilterDataGrid}">
<CheckBox.CommandParameter>
<MultiBinding Converter="{StaticResource DataGridConverterKey}">
<Binding RelativeSource="{ RelativeSource
Mode=FindAncestor,
AncestorType={x:Type ListBox}}" />
<Binding />
</MultiBinding>
</CheckBox.CommandParameter>
</CheckBox>
</DataTemplate>
</cust:BListBox.ItemTemplate>




How Can I set the Value to OutputSource within the Method

FilterResult(CheckedListItem<string> curFilter)
{
/////////////
// Refer the Above C# Code

OutputSource = SourceCollection;

// Refer the Above C# Code
////////////
}


Model :-

public class MobileModel : Notify
{
private string _brand = string.Empty;
private ObservableCollection<MobileModelInfo> _model = new ObservableCollection<MobileModelInfo>();
private string _os = string.Empty;

public string Brand
{
get { return _brand; }
set { _brand = value; OnPropertyChanged(); }
}
public ObservableCollection<MobileModelInfo> Model
{
get { return _model; }
set { _model = value; OnPropertyChanged(); }
}

public string OS
{
get { return _os; }
set { _os = value; OnPropertyChanged(); }
}
}

public class MobileModelInfo
{
public string Name { get; set; }
public string Catagory { get; set; }
public string Year { get; set; }
}


Loading Model in View Model : -

public void GetMobile()
{
List<MobileModel> mList = new List<MobileModel>();
List<MobileModelInfo> modList = new List<MobileModelInfo>();
MobileModel mob = new MobileModel();

modList.Clear();
mob.Brand = "Apple";
modList.Add(new MobileModelInfo { Name = "iPhone 4", Catagory = "Smart Phone", Year = "2011" });
modList.Add(new MobileModelInfo { Name = "iPhone 5", Catagory = "Smart Phone", Year = "2013" });
modList.Add(new MobileModelInfo { Name = "iPhone 6", Catagory = "Premium Smart Phone", Year = "2015" });
mob.Model = new ObservableCollection<MobileModelInfo>(modList);
mob.OS = "IOS";
mList.Add(mob);

mob = new MobileModel();
modList.Clear();
mob.Brand = "Samsung";
modList.Add(new MobileModelInfo { Name = "S4", Catagory = "Smart Phone", Year = "2011" });
modList.Add(new MobileModelInfo { Name = "S5", Catagory = "Smart Phone", Year = "2013" });
modList.Add(new MobileModelInfo { Name = "S6", Catagory = "Ultra Smart Phone", Year = "2015" });
mob.Model = new ObservableCollection<MobileModelInfo>(modList);
mob.OS = "Android";
mList.Add(mob);

mob = new MobileModel();
modList.Clear();
mob.Brand = "MicroSoft";
modList.Add(new MobileModelInfo { Name = "Lumina 9900", Catagory = "Phone", Year = "2011" });
modList.Add(new MobileModelInfo { Name = "Opera X220", Catagory = "Smart Phone", Year = "2013" });
mob.Model = new ObservableCollection<MobileModelInfo>(modList);
mob.OS = "Windows";
mList.Add(mob);

mob = new MobileModel();
modList.Clear();
mob.Brand = "Sony Ericssion";
modList.Add(new MobileModelInfo { Name = "S4", Catagory = "Smart Phone", Year = "2011" });
modList.Add(new MobileModelInfo { Name = "S5", Catagory = "Smart Phone", Year = "2013" });
modList.Add(new MobileModelInfo { Name = "S6", Catagory = "Ultra Smart Phone", Year = "2015" });
mob.Model = new ObservableCollection<MobileModelInfo>(modList);
mob.OS = "Android";
mList.Add(mob);

MobileListPrimary = new ObservableCollection<MobileModel>(mList);
MobileList = new ObservableCollection<MobileModel>(MobileListPrimary);
}

Answer

Instead of using ObservableCollection<T> use IEnumerable

The Dependency Property Declaration should be

public static readonly DependencyProperty OutputSourceCollectionProperty 
    = DependencyProperty.Register("OutputSourceCollection",
        typeof(IEnumerable), 
        typeof(BListBox), 
        new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

public IEnumerable OutputSourceCollection
{
    get { return (IEnumerable)GetValue(OutputSourceCollectionProperty); }
    set { SetValue(OutputSourceCollectionProperty, value); }
}

Use IList Interface to Add/Remove Items

(OutputSourceCollection as IList).Add(Item);

(OutputSourceCollection as IList).Remove(Item);