如何在双向绑定WPF自定义控件C#中通过依赖属性返回值
本文关键字:依赖 返回值 属性 自定义控件 WPF 绑定 | 更新日期: 2023-09-27 18:22:08
我有一个自定义控件,它继承了ListBox控件,因为我添加了两个DependencyProperty,一个用于获取输入,另一个用于通过绑定发送处理后的输出。
下面是ListBox继承的自定义控件BListBox:-C#编码
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;
}
}
XAML代码:
<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>
如何在方法中将值设置为OutputSource
FilterResult(CheckedListItem<string> curFilter)
{
/////////////
// Refer the Above C# Code
OutputSource = SourceCollection;
// Refer the Above C# Code
////////////
}
型号:-
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; }
}
视图中的加载模型模型:-
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);
}
不使用ObservableCollection<T>
,而是使用IEnumerable
依赖属性声明应为
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); }
}
使用IList
接口添加/删除项目
(OutputSourceCollection as IList).Add(Item);
(OutputSourceCollection as IList).Remove(Item);
问题是XAML绑定不是查看实际的数据类型,而是查看依赖属性的数据类型IEnumerable
。该类型的变量不能分配给ObservableCollection<T>
,因此,模型上的值不会更新。
您可以通过添加转换器并在绑定中使用它来修复此问题:
public class EnumerableConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return null;
if (targetType.IsInstanceOfType(value))
return value;
if (value.GetType().GetInterfaces().Contains(typeof(IEnumerable)) && targetType.IsGenericType
&& !targetType.IsGenericTypeDefinition && targetType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
return ((IEnumerable)value).Cast(targetType.GetGenericArguments().Single());
throw new InvalidOperationException(
string.Format("Can't convert from {0} to {1}", value.GetType(), targetType));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Convert(value, targetType, parameter, culture);
}
}
此代码使用Cast
的非通用版本,因此您也需要此类:
public static class EnumerableExtensions
{
private static readonly MethodInfo CastMethod;
static EnumerableExtensions()
{
CastMethod = typeof(Enumerable).GetMethod("Cast", BindingFlags.Public | BindingFlags.Static);
}
public static object Cast(this IEnumerable input, Type targetType)
{
return CastMethod.MakeGenericMethod(targetType).Invoke(null, new object[] { input });
}
}