No Overload for method "GetValue" takes 1 arguments - wpf

I am trying to run a Devexpress Dxgrid sample program.
Which is here
The Vertical grid code is :
using DevExpress.Data;
using DevExpress.Xpf.Editors.Settings;
using DevExpress.Xpf.Grid;
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace dxExample.VGrid
{
public partial class VerticalGridControl : GridControl
{
INotifyCollectionChanged backItemsSourceEvents;
object InternalItemsSource
{
get { return base.ItemsSource; }
set { base.ItemsSource = value; }
}
GridColumnCollection InternalColumns
{
get { return base.Columns; }
}
public VerticalRowCollection Rows { get; set; }
public bool AutoPopulateRows
{
get { return (bool)GetValue(AutoPopulateRowsProperty); }
set { SetValue(AutoPopulateRowsProperty, value); }
}
public new object ItemsSource
{
get { return (object)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public VerticalGridControl()
{
InitializeComponent();
InitializeRowsCollection();
SubscribeItemsSourcePropertyChanged();
}
void InitializeRowsCollection()
{
Rows = new VerticalRowCollection();
Rows.CollectionChanged += OnRowsCollectionChanged;
}
void UpdateRowsCollection()
{
if (AutoPopulateRows)
{
PopulateRows();
}
}
void SubscribeItemsSourcePropertyChanged()
{
DependencyPropertyDescriptor itemsSourceDropertyDescriptor = DependencyPropertyDescriptor.FromProperty(VerticalGridControl.ItemsSourceProperty, typeof(VerticalGridControl));
itemsSourceDropertyDescriptor.AddValueChanged(this, new EventHandler(OnItemsSourcePropertyChanged));
}
void UpdateInternalColumns()
{
ICollection itemsSource = (ItemsSource as ICollection);
if (itemsSource == null)
{
Columns.Clear();
return;
}
Columns.BeginUpdate();
int columnsCount = itemsSource.Count;
if (InternalColumns.Count == columnsCount) return;
int delta = columnsCount - InternalColumns.Count;
if (columnsCount > InternalColumns.Count)
{
for (int i = InternalColumns.Count; i < columnsCount; i++)
{
InternalColumns.Add(new GridColumn() { FieldName = i.ToString(), UnboundType = UnboundColumnType.Object });
}
}
else
{
for (int i = InternalColumns.Count - 1; i >= columnsCount; i--)
{
InternalColumns.RemoveAt(i);
}
}
Columns.EndUpdate();
}
void UpdateItemsSourceEventsSubscription()
{
if (backItemsSourceEvents != null)
{
backItemsSourceEvents.CollectionChanged -= OnItemsSourceCollectionChanged;
}
if (!(ItemsSource is INotifyCollectionChanged)) return;
INotifyCollectionChanged itemsSourceEvents = (ItemsSource as INotifyCollectionChanged);
itemsSourceEvents.CollectionChanged += OnItemsSourceCollectionChanged;
backItemsSourceEvents = itemsSourceEvents;
}
void PopulateRows()
{
IEnumerable itemsSource = (ItemsSource as IEnumerable);
if (itemsSource == null) return;
IEnumerator itemsSourceEnumerator = itemsSource.GetEnumerator();
itemsSourceEnumerator.MoveNext();
object item = itemsSourceEnumerator.Current;
if (item == null) return;
PropertyInfo[] itemProps = item.GetType().GetProperties();
for (int i = 0; i < itemProps.Length; i++)
{
Rows.Add(VerticalRowData.FromPropertyInfo(itemProps[i]));
}
}
void OnRowsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
InternalItemsSource = Rows;
}
void OnItemsSourcePropertyChanged(object sender, EventArgs e)
{
UpdateInternalColumns();
UpdateRowsCollection();
UpdateItemsSourceEventsSubscription();
}
void OnItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add || e.Action == NotifyCollectionChangedAction.Remove)
{
UpdateInternalColumns();
}
}
void OnProcessUnboundColumnData(object sender, GridColumnDataEventArgs e)
{
IList itemsSource = (ItemsSource as IList);
if (itemsSource == null) return;
VerticalRowData row = Rows[e.ListSourceRowIndex];
object item = itemsSource[Convert.ToInt32(e.Column.FieldName)];
PropertyInfo itemProperty = item.GetType().GetProperty(row.RowName);
if (itemProperty == null) return;
if (e.IsGetData)
{
e.Value = itemProperty.GetValue(item);
}
if (e.IsSetData)
{
itemProperty.SetValue(item, e.Value);
}
}
public static readonly DependencyProperty AutoPopulateRowsProperty = DependencyProperty.Register("AutoPopulateRows", typeof(bool), typeof(VerticalGridControl), new PropertyMetadata(false));
public static new readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(object), typeof(VerticalGridControl), new PropertyMetadata(null));
}
public class BottomIndicatorRowVisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values.Count() < 2)
return Visibility.Collapsed;
if (!((values[0] is int) && (values[1] is int)))
return Visibility.Collapsed;
return ((int)values[0]) > ((int)values[1]) ? Visibility.Visible : Visibility.Collapsed;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class DefaultCellTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
VerticalRowData row = ((item as EditGridCellData).RowData.Row as VerticalRowData);
if (row.CellTemplate == null) return base.SelectTemplate(item, container);
return row.CellTemplate;
}
}
public class VerticalRowData : DependencyObject
{
public string RowName { get; set; }
public DataTemplate CellTemplate
{
get { return (DataTemplate)GetValue(CellTemplateProperty); }
set { SetValue(CellTemplateProperty, value); }
}
public static readonly DependencyProperty CellTemplateProperty = DependencyProperty.Register("CellTemplate", typeof(DataTemplate), typeof(VerticalRowData), new PropertyMetadata(null));
public static VerticalRowData FromPropertyInfo(PropertyInfo info)
{
return new VerticalRowData() { RowName = info.Name };
}
}
public class VerticalRowCollection : ObservableCollection<VerticalRowData>
{
protected override void InsertItem(int index, VerticalRowData item)
{
int existsIndex = IndexOf(item.RowName);
if (existsIndex > -1)
{
if (Items[existsIndex].CellTemplate != null) return;
Items[existsIndex].CellTemplate = item.CellTemplate;
return;
}
base.InsertItem(index, item);
}
int IndexOf(string rowName)
{
for (int i = 0; i < Items.Count; i++)
{
if (Items[i].RowName == rowName) return i;
}
return -1;
}
}
}
I am using Visual Studio 2010 and .NET 4.0,
And the only error i am getting in "GetValue" and "SetValue" method in OnProcessunboundData function,
telling no overload operator takes "1" and "2" operators respectively .
Is it cause of Platform mismatching.
Please try downloading the sample code mentioned above and tell me the answer.
Thanks,
Vivek

I was looking through a lot of forums
And then i tried
e.Value = itemProperty.GetValue(item,null);
and for SetValue :-
itemProperty.SetValue(item, e.Value,null);
And it worked :)
Thanks Anyways... :) :D

Related

Editable ComboBox behavior on arrow navigation in drop down

The default behavior for non-editable Combobox when you navigate through drop down list with Up and Down keys is, that the current item is highlighted but not selected. Only on Enter Key the Item gets selected.
If you set IsEditable="True" then the behavior is different. Currently selected item (and or Text input) changes by keyboard navigation in the drop down.
My problem with this is, that I'm filtering the items depending on text input. And when you select, you have one exact match and items count goes to one.
So it's not possible to select a correct item with a keyboard.
Inspired by blog post below (Thank you Diederik Krols) I'm finaly found a solution for my problem.
http://dotbay.blogspot.de/2009/04/building-filtered-combobox-for-wpf.html
It needed some extra work, but with a little bit Reflection and Binding suspendig, I have now combobox behavior like expected.
Here is my code
public enum FilterMode
{
Contains,
StartsWith
}
public class FilteredComboBoxBehavior : ManagedBehaviorBase<ComboBox>
{
private ICollectionView currentView;
private string currentFilter;
private Binding textBinding;
private TextBox textBox;
private PropertyInfo HighlightedInfoPropetyInfo { get; set; }
public static readonly DependencyProperty FilterModeProperty = DependencyProperty.Register("FilterMode", typeof(FilterMode), typeof(FilteredComboBoxBehavior), new PropertyMetadata(default(FilterMode)));
public FilterMode FilterMode
{
get
{
return (FilterMode)this.GetValue(FilterModeProperty);
}
set
{
this.SetValue(FilterModeProperty, value);
}
}
public static readonly DependencyProperty OpenDropDownOnFocusProperty = DependencyProperty.Register("OpenDropDownOnFocus", typeof(bool), typeof(FilteredComboBoxBehavior), new PropertyMetadata(true));
public bool OpenDropDownOnFocus
{
get
{
return (bool)this.GetValue(OpenDropDownOnFocusProperty);
}
set
{
this.SetValue(OpenDropDownOnFocusProperty, value);
}
}
protected override void OnSetup()
{
base.OnSetup();
this.AssociatedObject.KeyUp += this.AssociatedObjectOnKeyUp;
this.AssociatedObject.IsKeyboardFocusWithinChanged += this.OnIsKeyboardFocusWithinChanged;
this.textBox = this.AssociatedObject.FindChild<TextBox>();
this.textBinding = BindingOperations.GetBinding(this.AssociatedObject, ComboBox.TextProperty);
this.HighlightedInfoPropetyInfo = typeof(ComboBox).GetProperty(
"HighlightedInfo",
BindingFlags.Instance | BindingFlags.NonPublic);
var pd = DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, typeof(ComboBox));
pd.AddValueChanged(this.AssociatedObject, this.OnItemsSourceChanged);
}
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.KeyUp -= this.AssociatedObjectOnKeyUp;
if (this.currentView != null)
{
// ReSharper disable once DelegateSubtraction
this.currentView.Filter -= this.TextInputFilter;
}
BindingOperations.ClearAllBindings(this);
}
private void OnItemsSourceChanged(object sender, EventArgs eventArgs)
{
this.currentFilter = this.AssociatedObject.Text;
if (this.currentView != null)
{
// ReSharper disable once DelegateSubtraction
this.currentView.Filter -= this.TextInputFilter;
}
if (this.AssociatedObject.ItemsSource != null)
{
this.currentView = CollectionViewSource.GetDefaultView(this.AssociatedObject.ItemsSource);
this.currentView.Filter += this.TextInputFilter;
}
this.Refresh();
}
private void OnIsKeyboardFocusWithinChanged(object sender, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
if (this.AssociatedObject.IsKeyboardFocusWithin)
{
this.AssociatedObject.IsDropDownOpen = this.AssociatedObject.IsDropDownOpen || this.OpenDropDownOnFocus;
}
else
{
this.AssociatedObject.IsDropDownOpen = false;
this.currentFilter = this.AssociatedObject.Text;
this.Refresh();
}
}
private void AssociatedObjectOnKeyUp(object sender, KeyEventArgs keyEventArgs)
{
if (!this.IsTextManipulationKey(keyEventArgs)
|| (Keyboard.Modifiers.HasAnyFlag() && Keyboard.Modifiers != ModifierKeys.Shift)
)
{
return;
}
if (this.currentFilter != this.AssociatedObject.Text)
{
this.currentFilter = this.AssociatedObject.Text;
this.Refresh();
}
}
private bool TextInputFilter(object obj)
{
var stringValue = obj as string;
if (obj != null && !(obj is string))
{
var path = (string)this.GetValue(TextSearch.TextPathProperty);
if (path != null)
{
stringValue = obj.GetType().GetProperty(path).GetValue(obj) as string;
}
}
if (stringValue == null)
return false;
switch (this.FilterMode)
{
case FilterMode.Contains:
return stringValue.IndexOf(this.currentFilter, StringComparison.OrdinalIgnoreCase) >= 0;
case FilterMode.StartsWith:
return stringValue.StartsWith(this.currentFilter, StringComparison.OrdinalIgnoreCase);
default:
throw new ArgumentOutOfRangeException();
}
}
private bool IsTextManipulationKey(KeyEventArgs keyEventArgs)
{
return keyEventArgs.Key == Key.Back
|| keyEventArgs.Key == Key.Space
|| (keyEventArgs.Key >= Key.D0 && keyEventArgs.Key <= Key.Z)
|| (Keyboard.IsKeyToggled(Key.NumLock) && keyEventArgs.Key >= Key.NumPad0 && keyEventArgs.Key <= Key.NumPad9)
|| (keyEventArgs.Key >= Key.Multiply && keyEventArgs.Key <= Key.Divide)
|| (keyEventArgs.Key >= Key.Oem1 && keyEventArgs.Key <= Key.OemBackslash);
}
private void Refresh()
{
if (this.currentView != null)
{
var tempCurrentFilter = this.AssociatedObject.Text;
using (new SuspendBinding(this.textBinding, this.AssociatedObject, ComboBox.TextProperty))
{
this.currentView.Refresh();
//reset internal highlighted info
this.HighlightedInfoPropetyInfo.SetValue(this.AssociatedObject, null);
this.AssociatedObject.SelectedIndex = -1;
this.AssociatedObject.Text = tempCurrentFilter;
}
if (this.textBox != null && tempCurrentFilter != null)
{
this.textBox.SelectionStart = tempCurrentFilter.Length;
this.textBox.SelectionLength = 0;
}
}
}
}
/// <summary>
/// Temporarely suspend binding on dependency property
/// </summary>
public class SuspendBinding : IDisposable
{
private readonly Binding bindingToSuspend;
private readonly DependencyObject target;
private readonly DependencyProperty property;
public SuspendBinding(Binding bindingToSuspend, DependencyObject target, DependencyProperty property)
{
this.bindingToSuspend = bindingToSuspend;
this.target = target;
this.property = property;
BindingOperations.ClearBinding(target, property);
}
public void Dispose()
{
BindingOperations.SetBinding(this.target, this.property, this.bindingToSuspend);
}
}
public abstract class ManagedBehaviorBase<T> : Behavior<T> where T : FrameworkElement
{
private bool isSetup;
private bool isHookedUp;
private WeakReference weakTarget;
protected virtual void OnSetup() { }
protected virtual void OnCleanup() { }
protected override void OnChanged()
{
var target = this.AssociatedObject;
if (target != null)
{
this.HookupBehavior(target);
}
else
{
this.UnHookupBehavior();
}
}
private void OnTargetLoaded(object sender, RoutedEventArgs e) { this.SetupBehavior(); }
private void OnTargetUnloaded(object sender, RoutedEventArgs e) { this.CleanupBehavior(); }
private void HookupBehavior(T target)
{
if (this.isHookedUp) return;
this.weakTarget = new WeakReference(target);
this.isHookedUp = true;
target.Unloaded += this.OnTargetUnloaded;
target.Loaded += this.OnTargetLoaded;
if (target.IsLoaded)
{
this.SetupBehavior();
}
}
private void UnHookupBehavior()
{
if (!this.isHookedUp) return;
this.isHookedUp = false;
var target = this.AssociatedObject ?? (T)this.weakTarget.Target;
if (target != null)
{
target.Unloaded -= this.OnTargetUnloaded;
target.Loaded -= this.OnTargetLoaded;
}
this.CleanupBehavior();
}
private void SetupBehavior()
{
if (this.isSetup) return;
this.isSetup = true;
this.OnSetup();
}
private void CleanupBehavior()
{
if (!this.isSetup) return;
this.isSetup = false;
this.OnCleanup();
}
}
XAML
<ComboBox IsEditable="True"
Text="{Binding Path=ZipCode, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
ItemsSource="{Binding Path=PostalCodes}"
IsTextSearchEnabled="False"
behaviors:AttachedMaxLength.ChildTextBoxMaxLength="{Binding Path=ZipCodeMaxLength}">
<i:Interaction.Behaviors>
<behaviors:FilteredComboBoxBehavior FilterMode="StartsWith"/>
</i:Interaction.Behaviors>

WPF editable combobox slow typing

I have a WPF combobox like this :
<ComboBox x:Name="CustomerComboBox" IsEditable="True" ItemsSource="{Binding Relations.View}"
DisplayMemberPath="Model.sname" />
If I click in the editable combo while the binding is in place (MVVM) to give it focus, and I then press and hold any key, I assume the combo will be filled with that key rather quickly, but it isn't.
If I remove the displaymemberpath and then do the same, then I have the expected behavior. Of course I really need the binding.
The performance penalty only shows when the combo has a lot of elements mine has 6000.
I cannot understand where this performance penalty is coming from. Is there any way to bypass this problem ?
Below code solves the issues by creating a specialised combobox that basically caches all binding results. I created it by looking at the orginal source code of the combobox and itemscontrol using .NET reflector.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Reflection;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Windows.Controls.Primitives;
using System.Collections;
namespace ICeTechControlLibrary
{
public class FastEditComboBox : ComboBox
{
//PARTS
private TextBox _TextBoxPart = null;
//DEPENDENCY PROPERTIES
public static readonly DependencyProperty TextProperty
= DependencyProperty.Register("Text", typeof(string), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.Journal | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(FastEditComboBox.OnTextChanged)));
private List<string> _CompletionStrings = new List<string>();
private int _textBoxSelectionStart;
private bool _updatingText;
private bool _updatingSelectedItem;
private static Dictionary<TextBox, FastEditComboBox> _TextBoxDictionary = new Dictionary<TextBox,FastEditComboBox>();
static FastEditComboBox()
{
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.TextChangedEvent, new TextChangedEventHandler(FastEditComboBox.OnTextChanged));
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.SelectionChangedEvent, new RoutedEventHandler(FastEditComboBox.OnSelectionChanged));
}
public string Text
{
get
{
return (string)base.GetValue(TextProperty);
}
set
{
base.SetValue(TextProperty, value);
}
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_TextBoxPart = base.GetTemplateChild("PART_EditableTextBox") as TextBox;
if (!_TextBoxDictionary.ContainsKey(_TextBoxPart)) _TextBoxDictionary.Add(_TextBoxPart, this);
}
private void OnTextBoxSelectionChanged(object sender, RoutedEventArgs e)
{
this._textBoxSelectionStart = this._TextBoxPart.SelectionStart;
}
private void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)
{
if (IsEditable)
{
TextUpdated(_TextBoxPart.Text, true);
}
}
private void TextUpdated(string newText, bool textBoxUpdated)
{
if (!_updatingText && !_updatingSelectedItem)
{
try
{
_updatingText = true;
if (base.IsTextSearchEnabled)
{
int num = FindMatchingPrefix(newText);
if (num >= 0)
{
if (textBoxUpdated)
{
int selectionStart = this._TextBoxPart.SelectionStart;
if ((selectionStart == newText.Length) && (selectionStart > this._textBoxSelectionStart))
{
string primaryTextFromItem = _CompletionStrings[num];
this._TextBoxPart.Text = primaryTextFromItem;
this._TextBoxPart.SelectionStart = newText.Length;
this._TextBoxPart.SelectionLength = primaryTextFromItem.Length - newText.Length;
newText = primaryTextFromItem;
}
}
else
{
string b = _CompletionStrings[num];
if (!string.Equals(newText, b, StringComparison.CurrentCulture))
{
num = -1;
}
}
}
if (num != base.SelectedIndex)
{
SelectedIndex = num;
}
}
if (textBoxUpdated)
{
Text = newText;
}
else if (_TextBoxPart != null)
{
_TextBoxPart.Text = newText;
}
}
finally
{
_updatingText = false;
}
}
}
internal void SelectedItemUpdated()
{
try
{
this._updatingSelectedItem = true;
if (!this._updatingText)
{
string primaryTextFromItem = GetPrimaryTextFromItem(SelectedItem);
Text = primaryTextFromItem;
}
this.Update();
}
finally
{
this._updatingSelectedItem = false;
}
}
private void Update()
{
if (this.IsEditable)
{
this.UpdateEditableTextBox();
}
else
{
//this.UpdateSelectionBoxItem();
}
}
private void UpdateEditableTextBox()
{
if (!_updatingText)
{
try
{
this._updatingText = true;
string text = this.Text;
if ((this._TextBoxPart != null) && (this._TextBoxPart.Text != text))
{
this._TextBoxPart.Text = text;
this._TextBoxPart.SelectAll();
}
}
finally
{
this._updatingText = false;
}
}
}
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
base.RaiseEvent(e);
this.SelectedItemUpdated();
if (this.IsDropDownOpen)
{
object Item = SelectedItem;
if (Item != null)
{
base.OnSelectionChanged(e);
}
//object internalSelectedItem = base.InternalSelectedItem;
//if (internalSelectedItem != null)
//{
// base.NavigateToItem(internalSelectedItem, ItemsControl.ItemNavigateArgs.Empty);
//}
}
}
int FindMatchingPrefix(string s)
{
int index = _CompletionStrings.BinarySearch(s, StringComparer.OrdinalIgnoreCase);
if (index >= 0) return index;
index = ~index;
string p = _CompletionStrings[index];
if (p.StartsWith(s, StringComparison.CurrentCultureIgnoreCase)) return index;
return -1;
}
protected override void OnDisplayMemberPathChanged(string oldDisplayMemberPath, string newDisplayMemberPath)
{
FillCompletionStrings();
}
protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
switch (e.Action)
{
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
AddCompletionStrings(e.NewItems);
break;
case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
RemoveCompletionStrings(e.OldItems);
break;
case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
FillCompletionStrings();
break;
}
}
private void FillCompletionStrings()
{
_CompletionStrings.Clear();
AddCompletionStrings(Items);
}
private void RemoveCompletionStrings(IList items)
{
foreach (object o in items)
{
RemoveCompletionStringForItem(o);
}
}
private void AddCompletionStrings(IList items)
{
foreach (object o in items)
{
AddCompletionStringForItem(o);
}
}
private void AddCompletionStringForItem(object item)
{
Binding binding = new Binding(DisplayMemberPath);
TextBlock tb = new TextBlock();
tb.DataContext = item;
tb.SetBinding(TextBlock.TextProperty, binding);
string s = tb.Text;
int index = _CompletionStrings.BinarySearch(s, StringComparer.OrdinalIgnoreCase);
if (index < 0)
{
_CompletionStrings.Insert(~index, s);
}
else
{
_CompletionStrings.Insert(index, s);
}
}
private string GetPrimaryTextFromItem(object item)
{
Binding binding = new Binding(DisplayMemberPath);
TextBlock tb = new TextBlock();
tb.DataContext = item;
tb.SetBinding(TextBlock.TextProperty, binding);
string s = tb.Text;
return s;
}
private void RemoveCompletionStringForItem(object item)
{
Binding binding = new Binding(DisplayMemberPath);
TextBlock tb = new TextBlock();
tb.DataContext = item;
tb.SetBinding(TextBlock.TextProperty, binding);
string s = tb.Text;
int index = _CompletionStrings.BinarySearch(s, StringComparer.OrdinalIgnoreCase);
if (index >= 0) _CompletionStrings.RemoveAt(index);
}
private static void OnTextChanged(object sender, TextChangedEventArgs e)
{
TextBox tb = e.Source as TextBox;
if (tb.Name == "PART_EditableTextBox")
{
if (_TextBoxDictionary.ContainsKey(tb))
{
FastEditComboBox combo = _TextBoxDictionary[tb];
combo.OnTextBoxTextChanged(sender, e);
e.Handled = true;
}
}
}
private static void OnSelectionChanged(object sender, RoutedEventArgs e)
{
TextBox tb = e.Source as TextBox;
if (tb.Name == "PART_EditableTextBox")
{
if (_TextBoxDictionary.ContainsKey(tb))
{
FastEditComboBox combo = _TextBoxDictionary[tb];
combo.OnTextBoxSelectionChanged(sender, e);
e.Handled = true;
}
}
}
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FastEditComboBox actb = (FastEditComboBox)d;
actb.TextUpdated((string)e.NewValue, false);
}
}
}
selecting the very first element clears the selection with this implementation.
so still some bugs here

Markup extensions with state in WPF

I've just discovered that WPF Markup extension instances are reused in control templates. So each copy of the control template gets the same set of markup extensions.
This doesn't work if you want the extension to maintain some state per control it is attached to. Any idea how to solve this.
Don't store state in the Markup extension. Store it another way. For example.
public abstract class DynamicMarkupExtension : MarkupExtension
{
public class State
{
public object TargetObject { get; set; }
public object TargetProperty { get; set; }
public void UpdateValue(object value)
{
if (TargetObject != null)
{
if (TargetProperty is DependencyProperty)
{
DependencyObject obj = TargetObject as DependencyObject;
DependencyProperty prop = TargetProperty as DependencyProperty;
Action updateAction = () => obj.SetValue(prop, value);
// Check whether the target object can be accessed from the
// current thread, and use Dispatcher.Invoke if it can't
if (obj.CheckAccess())
updateAction();
else
obj.Dispatcher.Invoke(updateAction);
}
else // TargetProperty is PropertyInfo
{
PropertyInfo prop = TargetProperty as PropertyInfo;
prop.SetValue(TargetObject, value, null);
}
}
}
}
public sealed override object ProvideValue(IServiceProvider serviceProvider)
{
IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
State state = new State();
if (target != null)
{
state.TargetObject = target.TargetObject;
state.TargetProperty = target.TargetProperty;
return ProvideValueInternal(serviceProvider, state);
}
else
{
return null;
}
}
protected abstract object ProvideValueInternal(IServiceProvider serviceProvider, State state);
}
is a base class for handling the type of problem where you need to update the property the markup
extension is attached to at run time. For example a markup extension for binding to ISubject as
<TextBox Text="{Markup:Subscription Path=Excenter, ErrorsPath=Errors}"/>
using the SubscriptionExtension as below. I had had trouble with the code when I used it
within templates but I fixed it so the MarkupExtension did not store state in itself
using ReactiveUI.Ext;
using ReactiveUI.Subjects;
using ReactiveUI.Utils;
using System;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
namespace ReactiveUI.Markup
{
[MarkupExtensionReturnType(typeof(BindingExpression))]
public class SubscriptionExtension : DynamicMarkupExtension
{
[ConstructorArgument("path")]
public PropertyPath Path { get; set; }
[ConstructorArgument("errorsPath")]
public PropertyPath ErrorsPath { get; set; }
public SubscriptionExtension() { }
Maybe<Exception> currentErrorState = Maybe.None<Exception>();
public SubscriptionExtension(PropertyPath path, PropertyPath errorsPath)
{
Path = path;
ErrorsPath = errorsPath;
}
class Proxy : ReactiveObject, IDataErrorInfo, IDisposable
{
string _Value;
public string Value
{
get { return _Value; }
set { this.RaiseAndSetIfChanged(value); }
}
public string Error
{
get { return currentError.Select(e => e.Message).Else(""); }
}
public string this[string columnName]
{
get { return currentError.Select(e => e.Message).Else(""); }
}
public IObservable<Maybe<Exception>> Errors { get; set; }
public Maybe<Exception> currentError = Maybe.None<Exception>();
private CompositeDisposable Subscriptions = new CompositeDisposable();
public Proxy(IObservable<Maybe<Exception>> errors)
{
Errors = errors;
var subscription = errors.Subscribe(e => currentError = e);
Subscriptions.Add(subscription);
}
public void Dispose()
{
Subscriptions.Dispose();
}
}
protected override object ProvideValueInternal(IServiceProvider serviceProvider, DynamicMarkupExtension.State state )
{
var pvt = serviceProvider as IProvideValueTarget;
if (pvt == null)
{
return null;
}
var frameworkElement = pvt.TargetObject as FrameworkElement;
if (frameworkElement == null)
{
return this;
}
DependencyPropertyChangedEventHandler myd = delegate(object sender, DependencyPropertyChangedEventArgs e){
state.UpdateValue(MakeBinding(serviceProvider, frameworkElement));
};
frameworkElement.DataContextChanged += myd;
return MakeBinding(serviceProvider, frameworkElement);
}
private object MakeBinding(IServiceProvider serviceProvider, FrameworkElement frameworkElement)
{
var dataContext = frameworkElement.DataContext;
if (dataContext is String)
{
return dataContext;
}
ISubject<string> subject = Lens.Empty<string>().Subject;
IObservable<Maybe<Exception>> errors = Observable.Empty<Maybe<Exception>>();
Binding binding;
Proxy proxy = new Proxy(errors);
bool madeit = false;
if (dataContext != null)
{
subject = GetProperty<ISubject<string>>(dataContext, Path);
if (subject != null)
{
errors = GetProperty<IObservable<Maybe<Exception>>>
(dataContext
, ErrorsPath) ?? Observable.Empty<Maybe<Exception>>();
proxy = new Proxy(errors);
}
madeit = true;
}
if(!madeit)
{
subject = new BehaviorSubject<string>("Binding Error");
}
// Bind the subject to the property via a helper ( in private library )
var subscription = subject.TwoWayBindTo(proxy, x => x.Value);
// Make sure we don't leak subscriptions
frameworkElement.Unloaded += (e, v) => subscription.Dispose();
binding = new Binding()
{
Source = proxy,
Path = new System.Windows.PropertyPath("Value"),
ValidatesOnDataErrors = true
};
return binding.ProvideValue(serviceProvider);
}
private static T GetProperty<T>(object context, PropertyPath propPath)
where T : class
{
if (propPath==null)
{
return null;
}
try
{
object propValue = propPath.Path
.Split('.')
.Aggregate(context, (value, name)
=> value.GetType()
.GetProperty(name)
.GetValue(value, null));
return propValue as T;
}
catch (NullReferenceException e)
{
throw new MemberAccessException(propPath.Path + " is not available on " + context.GetType(),e);
}
}
}
}

Calculated Properties using Partial Classes(WPF)

I am trying to use the calculated columns to display in my grid.
I have a partial class automatically generated by EF code generator with three properties:
Here is my code generated by EF entity generator
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.Serialization;
using System.ComponentModel.DataAnnotations;
namespace Employees.Contract
{
[DataContract(IsReference = true)]
[KnownType(typeof(Department))]
[KnownType(typeof(PropertyType))]
public partial class Employee: IObjectWithChangeTracker, INotifyPropertyChanged,IDataErrorInfo
{
[NonSerialized]
private CLOS.Contract.Validation.DataErrorInfoSupport dataErrorInfoSupport;
public Employee()
{
dataErrorInfoSupport = new CLOS.Contract.Validation.DataErrorInfoSupport(this);
Init();
}
partial void Init();
string IDataErrorInfo.Error { get { return dataErrorInfoSupport.Error; } }
string IDataErrorInfo.this[string memberName] { get { return dataErrorInfoSupport[memberName]; } }
#region Primitive Properties
[DataMember]
public Nullable<decimal> Salary
{
get { return _salary; }
set
{
if (_salary != value)
{
_salary = value;
OnPropertyChanged("Salary");
}
}
}
private Nullable<decimal> _salary;
[DataMember]
public Nullable<decimal> WageRate
{
get { return _wageRate; }
set
{
if (_wageRate != value)
{
_wageRate = value;
OnPropertyChanged("WageRate");
}
}
}
private Nullable<decimal> _wageRate;
[DataMember]
public Nullable<decimal> Bonus
{
get { return _bonus; }
set
{
if (_bonus != value)
{
_bonus = value;
OnPropertyChanged("Bonus");
}
}
}
private Nullable<decimal> _bonus;
#endregion
#region Navigation Properties
[DataMember]
public Department Department
{
get { return _department; }
set
{
if (!ReferenceEquals(_department, value))
{
var previousValue = _department;
_department = value;
OnNavigationPropertyChanged("Department");
}
}
}
private Borrower _department;
[DataMember]
public PropertyType PropertyType
{
get { return _propertyType; }
set
{
if (!ReferenceEquals(_propertyType, value))
{
var previousValue = _propertyType;
_propertyType = value;
OnNavigationPropertyChanged("PropertyType");
}
}
}
private PropertyType _propertyType;
#endregion
#region ChangeTracking
protected virtual void OnPropertyChanged(String propertyName)
{
if (ChangeTracker.State != ObjectState.Added && ChangeTracker.State != ObjectState.Deleted)
{
ChangeTracker.State = ObjectState.Modified;
}
if (_propertyChanged != null)
{
_propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
protected virtual void OnNavigationPropertyChanged(String propertyName)
{
if (_propertyChanged != null)
{
_propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged{ add { _propertyChanged += value; } remove { _propertyChanged -= value; } }
private event PropertyChangedEventHandler _propertyChanged;
private ObjectChangeTracker _changeTracker;
[DataMember]
public ObjectChangeTracker ChangeTracker
{
get
{
if (_changeTracker == null)
{
_changeTracker = new ObjectChangeTracker();
_changeTracker.ObjectStateChanging += HandleObjectStateChanging;
}
return _changeTracker;
}
set
{
if(_changeTracker != null)
{
_changeTracker.ObjectStateChanging -= HandleObjectStateChanging;
}
_changeTracker = value;
if(_changeTracker != null)
{
_changeTracker.ObjectStateChanging += HandleObjectStateChanging;
}
}
}
private void HandleObjectStateChanging(object sender, ObjectStateChangingEventArgs e)
{
if (e.NewState == ObjectState.Deleted)
{
ClearNavigationProperties();
}
}
protected bool IsDeserializing { get; private set; }
[OnDeserializing]
public void OnDeserializingMethod(StreamingContext context)
{
IsDeserializing = true;
}
[OnDeserialized]
public void OnDeserializedMethod(StreamingContext context)
{
dataErrorInfoSupport = new CLOS.Contract.Validation.DataErrorInfoSupport(this);
IsDeserializing = false;
ChangeTracker.ChangeTrackingEnabled = true;
}
protected virtual void ClearNavigationProperties()
{
Department = null;
PropertyType = null;
}
#endregion
}
}
It also works if i put OnPropertyChanged("Salary") in Hours,Wage,Overtime Property in EF Generated class (which is not a good idea) because if the class gets regenerated , my code will be wiped out
Any help is appreciated. (Sorry for the formatting , this is my first question)
Thanks
Final Draft
(I removed old edits due to irrelevance)
In your partial class add, in addition to your definition of Salary:
partial void Init()
{
_propertyChanged += NotifySalary;
}
private void NotifySalary(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Wages" || e.PropertyName == "Hours" || e.PropertyName == "Overtime")
{
OnPropertyChanged("Salary");
}
}
I was able to fix this issue. What was happening is that service was marshaling the data back to the UI but it was not marshaling the events with the properties, so what i had to do was to call the init method from the UI and it started working.

MVVM Invoke Method in View (from ControlTemplate via ViewModel)

I would like to know how the following problem can be solved WITHOUT using Event Aggregation. This is for WPF 3.5 SP1, so the CallMethodBehavior is not available.
Simple Scenario: A click on a button inside a ControlTemplate needs to be triggered to the VM. I used CaliburnMicro's ActionMessage which worked fine. Inside the ViewModel I want to trigger a method inside the View, which only starts a custom transition (no real logic). I tried many things, but I did not work out.
I created a Property in my view, which could call the method but I am not able to use Triggers to set a new value for the property, because I can't tell the setter to target a property outside the controltemplate.
So in essence I want to update a Property in the viewmodel and trigger a set-property in the view class. Or if you have any idea how to get around this at all: I am open to new ideas! :D
Regards
Gope
i think the most simple way is to expose an event from your vm and subscribe to it in your view?
i used this for dialogs to send DialogResult from vm
I found a solution I can live with: I ported the CallMethodAction to 3.5 and wrote my own PropertyChangedTrigger. It's pretty simple to call a method inside the view via a PropertyChange in the viewmodel - Kids: don't try this at home. It's only for special scenarios! :D
Find my code below:
usage:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<i:Interaction.Triggers >
<Framework:PropertyChangedTrigger Binding="{Binding StartTransition}" Value="True">
<Framework:CallMethodAction MethodName="ApplyTransition" />
</Framework:PropertyChangedTrigger>
</i:Interaction.Triggers>
PropertyChangedTrigger:
public class PropertyChangedTrigger : TriggerBase<DependencyObject>
{
public static readonly DependencyProperty BindingProperty = DependencyProperty.Register("Binding", typeof(object), typeof(PropertyChangedTrigger), new PropertyMetadata(new PropertyChangedCallback(OnBindingChanged)));
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(PropertyChangedTrigger), new PropertyMetadata(null));
public object Binding
{
get
{
return base.GetValue(BindingProperty);
}
set
{
base.SetValue(BindingProperty, value);
}
}
public object Value
{
get
{
return base.GetValue(ValueProperty);
}
set
{
base.SetValue(ValueProperty, value);
}
}
protected virtual void EvaluateBindingChange(object args)
{
var propertyChangedArgs = (DependencyPropertyChangedEventArgs)args;
string newValue = propertyChangedArgs.NewValue.ToString();
bool equal = string.Equals(newValue, Value.ToString(),StringComparison.InvariantCultureIgnoreCase);
if(equal)
{
InvokeActions(args);
}
}
private static void OnBindingChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
((PropertyChangedTrigger)sender).EvaluateBindingChange(args);
}
}
CallMethodAction:
public class CallMethodAction : TargetedTriggerAction<FrameworkElement>
{
private List<MethodDescriptor> methodDescriptors = new List<MethodDescriptor>();
public static readonly DependencyProperty MethodNameProperty = DependencyProperty.Register("MethodName", typeof(string), typeof(CallMethodAction), new PropertyMetadata(new PropertyChangedCallback(OnMethodNameChanged)));
public static readonly DependencyProperty TargetObjectProperty = DependencyProperty.Register("TargetObject", typeof(object), typeof(CallMethodAction), new PropertyMetadata(new PropertyChangedCallback(OnTargetObjectChanged)));
protected override void OnAttached()
{
base.OnAttached();
this.UpdateMethodInfo();
}
protected override void OnDetaching()
{
this.methodDescriptors.Clear();
base.OnDetaching();
}
private static void OnMethodNameChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
((CallMethodAction)sender).UpdateMethodInfo();
}
private static void OnTargetObjectChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
((CallMethodAction)sender).UpdateMethodInfo();
}
private static bool AreMethodParamsValid(ParameterInfo[] methodParams)
{
if (methodParams.Length == 2)
{
if (methodParams[0].ParameterType != typeof(object))
{
return false;
}
if (!typeof(EventArgs).IsAssignableFrom(methodParams[1].ParameterType))
{
return false;
}
}
else if (methodParams.Length != 0)
{
return false;
}
return true;
}
protected override void Invoke(object parameter)
{
if (base.AssociatedObject != null)
{
MethodDescriptor descriptor = this.FindBestMethod(parameter);
if (descriptor != null)
{
ParameterInfo[] parameters = descriptor.Parameters;
if (parameters.Length == 0)
{
descriptor.MethodInfo.Invoke(this.Target, null);
}
else if ((((parameters.Length == 2) && (base.AssociatedObject != null)) && ((parameter != null) && parameters[0].ParameterType.IsAssignableFrom(base.AssociatedObject.GetType()))) && parameters[1].ParameterType.IsAssignableFrom(parameter.GetType()))
{
descriptor.MethodInfo.Invoke(this.Target, new object[] { base.AssociatedObject, parameter });
}
}
else if (this.TargetObject != null)
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "No valid method found.", new object[] { this.MethodName, this.TargetObject.GetType().Name }));
}
}
}
private MethodDescriptor FindBestMethod(object parameter)
{
if (parameter != null)
{
parameter.GetType();
}
return this.methodDescriptors.FirstOrDefault(methodDescriptor => (!methodDescriptor.HasParameters || ((parameter != null) && methodDescriptor.SecondParameterType.IsAssignableFrom(parameter.GetType()))));
}
private void UpdateMethodInfo()
{
this.methodDescriptors.Clear();
if ((this.Target != null) && !string.IsNullOrEmpty(this.MethodName))
{
foreach (MethodInfo info in this.Target.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance))
{
if (this.IsMethodValid(info))
{
ParameterInfo[] parameters = info.GetParameters();
if (AreMethodParamsValid(parameters))
{
this.methodDescriptors.Add(new MethodDescriptor(info, parameters));
}
}
}
this.methodDescriptors = this.methodDescriptors.OrderByDescending<MethodDescriptor, int>(delegate(MethodDescriptor methodDescriptor)
{
int num = 0;
if (methodDescriptor.HasParameters)
{
for (Type type = methodDescriptor.SecondParameterType; type != typeof(EventArgs); type = type.BaseType)
{
num++;
}
}
return (methodDescriptor.ParameterCount + num);
}).ToList<MethodDescriptor>();
}
}
private bool IsMethodValid(MethodInfo method)
{
if (!string.Equals(method.Name, this.MethodName, StringComparison.Ordinal))
{
return false;
}
if (method.ReturnType != typeof(void))
{
return false;
}
return true;
}
public void InvokeInternal()
{
if (AssociatedObject != null)
{
foreach (
MethodInfo info in AssociatedObject.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance))
{
if (IsMethodValid(info))
{
info.Invoke(AssociatedObject, new object[0]);
}
}
}
}
public string MethodName
{
get
{
return (string)base.GetValue(MethodNameProperty);
}
set
{
base.SetValue(MethodNameProperty, value);
}
}
private object Target
{
get
{
return (TargetObject ?? base.AssociatedObject);
}
}
public object TargetObject
{
get
{
return base.GetValue(TargetObjectProperty);
}
set
{
base.SetValue(TargetObjectProperty, value);
}
}
private class MethodDescriptor
{
public MethodDescriptor(MethodInfo methodInfo, ParameterInfo[] methodParams)
{
MethodInfo = methodInfo;
Parameters = methodParams;
}
public bool HasParameters
{
get
{
return (Parameters.Length > 0);
}
}
public MethodInfo MethodInfo { get; private set; }
public int ParameterCount
{
get
{
return Parameters.Length;
}
}
public ParameterInfo[] Parameters { get; private set; }
public Type SecondParameterType
{
get
{
if (Parameters.Length >= 2)
{
return Parameters[1].ParameterType;
}
return null;
}
}
}
}
Hope this helps anybode. All questions are welcome! Remeber: all this can be found in the Expression Blend SDK 4. This code is only for people who are forced to work with older versions like 3.5
Regards
Gope
Gope

Resources