I have a CheckBoxComboBox where I want to get fields of checked items so I do something like:
foreach (var currentChecked in cboDesignStatus.CheckBoxItems.Where(x => x.Checked))
{
var a = currentChecked.ComboBoxItem;
}
So var a result is :
My question is, how can I access this fields ? I want to get property Name so I try
var a = currentChecked.ComboBoxItem.Name;
But I can't it only let this:
How can I access this field
Note: variable on foreach "currentChecked" throws ComboBoxItem as ObjectSelectionWrapper
ObjectSelectionWrapper Class:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;
using System.Data;
namespace MyProject.Utility
{
/// <summary>
/// Used together with the ListSelectionWrapper in order to wrap data sources for a CheckBoxComboBox.
/// It helps to ensure you don't add an extra "Selected" property to a class that don't really need or want that information.
/// </summary>
public class ObjectSelectionWrapper<T> : INotifyPropertyChanged
{
public ObjectSelectionWrapper(T item, ListSelectionWrapper<T> container)
: base()
{
_Container = container;
_Item = item;
}
#region PRIVATE PROPERTIES
/// <summary>
/// Used as a count indicator for the item. Not necessarily displayed.
/// </summary>
private int _Count = 0;
/// <summary>
/// Is this item selected.
/// </summary>
private bool _Selected = false;
/// <summary>
/// A reference to the wrapped item.
/// </summary>
private T _Item;
/// <summary>
/// The containing list for these selections.
/// </summary>
private ListSelectionWrapper<T> _Container;
#endregion
#region PUBLIC PROPERTIES
/// <summary>
/// An indicator of how many items with the specified status is available for the current filter level.
/// Thaught this would make the app a bit more user-friendly and help not to miss items in Statusses
/// that are not often used.
/// </summary>
public int Count
{
get { return _Count; }
set { _Count = value; }
}
/// <summary>
/// A reference to the item wrapped.
/// </summary>
public T Item
{
get { return _Item; }
set { _Item = value; }
}
/// <summary>
/// The item display value. If ShowCount is true, it displays the "Name [Count]".
/// </summary>
public string Name
{
get
{
string Name = null;
if (string.IsNullOrEmpty(_Container.DisplayNameProperty))
Name = Item.ToString();
else if (Item is DataRow) // A specific implementation for DataRow
Name = ((DataRow)((Object)Item))[_Container.DisplayNameProperty].ToString();
else
{
PropertyDescriptorCollection PDs = TypeDescriptor.GetProperties(Item);
foreach (PropertyDescriptor PD in PDs)
if (PD.Name.CompareTo(_Container.DisplayNameProperty) == 0)
{
Name = (string)PD.GetValue(Item).ToString();
break;
}
if (string.IsNullOrEmpty(Name))
{
PropertyInfo PI = Item.GetType().GetProperty(_Container.DisplayNameProperty);
if (PI == null)
throw new Exception(String.Format(
"Property {0} cannot be found on {1}.",
_Container.DisplayNameProperty,
Item.GetType()));
Name = PI.GetValue(Item, null).ToString();
}
}
return _Container.ShowCounts ? String.Format("{0} [{1}]", Name, Count) : Name;
}
}
/// <summary>
/// The textbox display value. The names concatenated.
/// </summary>
public string NameConcatenated
{
get { return _Container.SelectedNames; }
}
/// <summary>
/// Indicates whether the item is selected.
/// </summary>
public bool Selected
{
get { return _Selected; }
set
{
if (_Selected != value)
{
_Selected = value;
OnPropertyChanged("Selected");
OnPropertyChanged("NameConcatenated");
}
}
}
#endregion
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
It looks like ComboBoxItem is an Object. As Nat said earlier, if you cast the object to your expected class, you can then reference the properties.
var itemName = ((Utility.ObjectSelectionWrapper<DataRow>)currentChecked.ComboBoxItem).Name;
Related
i have two observable Collections that my view is binded to, one is called Network.Nodes and one it Network.Connections - the Network object is a Property in my view model.
I'm getting data from BackgroundWorker and adding new Node\Connection via the BW.ProgressChanged.
When the BW finish it's work i see only nodes and no connection. i added a Debug.WriteLine("Network.Connection.Cout = " + Network.Connection.Cout);
On the BW finish work, and i see that there are 2 elements inside (which is the correct amount) but for some reason i don't see the elements.
The ProgressChanged:
if (e.ProgressPercentage == 2) //Add connection to UI
{
ConnectionViewModel tempCon = new ConnectionViewModel();
List<Object> ConnectionObj = new List<object>();
ConnectionObj = (List<Object>)e.UserState;
tempCon.SourceConnector = (ConnectorViewModel)ConnectionObj[0];
tempCon.DestConnector = (ConnectorViewModel)ConnectionObj[1];
Network.Connections.Add(tempCon);
This is how i call the ProgressChange:
List<Object> connectionObj = new List<Object>();
connectionObj.Add(connection.SourceConnector);
connectionObj.Add(connection.DestConnector);
connectionObj.Add(connection.Type);
connectionObj.Add(i++);
bw.ReportProgress(2, connectionObj);
The binding:
NodesSource="{Binding Network.Nodes}"
ConnectionsSource="{Binding Network.Connections}"
The Network in the View Model:
public NetworkViewModel Network
{
get
{
return network;
}
set
{
network = value;
OnPropertyChanged("Network");
}
}
The Network View Model has two observableCollections one is of type NodeView model and one is ConnectionViewModel.
the Connection View model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Utils;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Media;
using System.Windows;
namespace YogevAfekaRAPAT.YNIDS.ViewModels
{
/// <summary>
/// Defines a connection between two connectors (aka connection points) of two nodes.
/// </summary>
public sealed class ConnectionViewModel : AbstractModelBase
{
#region Internal Data Members
/// <summary>
/// The source connector the connection is attached to.
/// </summary>
private ConnectorViewModel sourceConnector = null;
/// <summary>
/// The destination connector the connection is attached to.
/// </summary>
private ConnectorViewModel destConnector = null;
/// <summary>
/// The source and dest hotspots used for generating connection points.
/// </summary>
private Point sourceConnectorHotspot;
private Point destConnectorHotspot;
/// <summary>
/// Points that make up the connection.
/// </summary>
private PointCollection points = null;
#endregion Internal Data Members
public enum ConnectorType
{
REGULAR = 0,
FLOW = 1
}
/// <summary>
/// The source connector the connection is attached to.
/// </summary>
public ConnectorViewModel SourceConnector
{
get
{
return sourceConnector;
}
set
{
if (sourceConnector == value)
{
return;
}
if (sourceConnector != null)
{
sourceConnector.AttachedConnections.Remove(this);
sourceConnector.HotspotUpdated -= new EventHandler<EventArgs>(sourceConnector_HotspotUpdated);
}
sourceConnector = value;
if (sourceConnector != null)
{
sourceConnector.AttachedConnections.Add(this);
sourceConnector.HotspotUpdated += new EventHandler<EventArgs>(sourceConnector_HotspotUpdated);
this.SourceConnectorHotspot = sourceConnector.Hotspot;
}
OnPropertyChanged("SourceConnector");
OnConnectionChanged();
}
}
/// <summary>
/// The destination connector the connection is attached to.
/// </summary>
public ConnectorViewModel DestConnector
{
get
{
return destConnector;
}
set
{
if (destConnector == value)
{
return;
}
if (destConnector != null)
{
destConnector.AttachedConnections.Remove(this);
destConnector.HotspotUpdated -= new EventHandler<EventArgs>(destConnector_HotspotUpdated);
}
destConnector = value;
if (destConnector != null)
{
destConnector.AttachedConnections.Add(this);
destConnector.HotspotUpdated += new EventHandler<EventArgs>(destConnector_HotspotUpdated);
this.DestConnectorHotspot = destConnector.Hotspot;
}
OnPropertyChanged("DestConnector");
OnConnectionChanged();
}
}
/// <summary>
/// The source and dest hotspots used for generating connection points.
/// </summary>
public Point SourceConnectorHotspot
{
get
{
return sourceConnectorHotspot;
}
set
{
sourceConnectorHotspot = value;
ComputeConnectionPoints();
OnPropertyChanged("SourceConnectorHotspot");
}
}
public Point DestConnectorHotspot
{
get
{
return destConnectorHotspot;
}
set
{
destConnectorHotspot = value;
ComputeConnectionPoints();
OnPropertyChanged("DestConnectorHotspot");
}
}
/// <summary>
/// Points that make up the connection.
/// </summary>
public PointCollection Points
{
get
{
return points;
}
set
{
points = value;
OnPropertyChanged("Points");
}
}
private ConnectorType type;
public ConnectorType Type
{
get
{
return type;
}
set
{
type = value;
OnPropertyChanged("Type");
}
}
/// <summary>
/// Event fired when the connection has changed.
/// </summary>
public event EventHandler<EventArgs> ConnectionChanged;
#region Private Methods
/// <summary>
/// Raises the 'ConnectionChanged' event.
/// </summary>
private void OnConnectionChanged()
{
if (ConnectionChanged != null)
{
ConnectionChanged(this, EventArgs.Empty);
}
}
#endregion Private Methods
}
}
I am not sure, but it might be that you're trying to update the collections from the background worker, which can result in problems. You need to marshal that to the UI-Thread using a Dispatcher like:
view.Dispatcher.BeginInvoke(new Action(() =>
{
Network.Connections.Add(tempCon);
}), DispatcherPriority.Normal);
A Dispatcher can be found on all UI-Elements. Not sure how your code is structured so can't tell where to get one from without seeing more code or getting more information.
I have the following classes gist with the classes.
I want to bind Item.Visible to Items.ItemsVisible - is it possible?, if so - how?
Item.cs:
using System;
using System.ComponentModel;
namespace WpfApplication85
{
/// <summary>
/// Item Object.
/// </summary>
public class Item : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged; //Event to notify when Property changed.
/// <summary>
/// Notify that Property has Changed.
/// </summary>
/// <param name="propertyName">The name of the Property</param>
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region Private Variables
private bool _Visible; //Bool to determine if the Item is visible or not
#endregion
#region Public Properties
//Return the value of Visible / Set the value of Visible and Notify.
public bool Visible
{
get { return _Visible; }
set
{
_Visible = value;
NotifyPropertyChanged("Visible");
}
}
#endregion
#region Constructor
/// <summary>
/// Item Constructor
/// </summary>
public Item()
{
_Visible = true;
}
#endregion
}
}
Items.cs:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace WpfApplication85
{
/// <summary>
/// Items Object.
/// </summary>
public class Items : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged; //Event to notify when Property changed.
/// <summary>
/// Notify that Property has Changed.
/// </summary>
/// <param name="propertyName">The name of the Property</param>
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region Private Variables
private bool _itemsVisible; //Bool to determine if the Items are visible or not
private ObservableCollection<Item> _itemsCollection; //Collection of Items.
#endregion
#region Public Properties
//Return the value of ItemsVisible / Set the value of ItemsVisible and Notify.
public bool ItemsVisible
{
get { return _itemsVisible; }
set
{
_itemsVisible = value;
NotifyPropertyChanged("ItemsVisible");
}
}
//Return the Items Collection / Set the Items Collection and Notify.
public ObservableCollection<Item> ItemsCollection
{
get
{
return _itemsCollection;
}
set
{
_itemsCollection = value;
NotifyPropertyChanged("ItemsCollection");
}
}
#endregion
#region Constructor
/// <summary>
/// Items Constructor
/// </summary>
public Items()
{
_itemsVisible = true;
_itemsCollection = new ObservableCollection<Item>();
}
#endregion
#region Methods
/// <summary>
/// Add Item to the ItemsCollection.
/// </summary>
/// <param name="item">Item Object</param>
public void AddItem(Item item)
{
//Bind item.Visible to this.ItemsVisible
_itemsCollection.Add(item);
}
#endregion
}
}
Setting data binding within Items and Item properties is nothing but listening PropertyChanged or CollectionChanged event from proper interfaces.
You can use either += clause for the subscription, or WeakEventListener pattern, using the PropertyChangedEventManager and CollectionChangedEventManager
I prefer the last one, because:
Listening for events can lead to memory leaks.
So, your Items class should implement IWeakEventListener interface:
public class Items : INotifyPropertyChanged, IWeakEventListener
{
#region IWeakEventListener
public bool ReceiveWeakEvent(Type managerType, Object sender, EventArgs e)
{
if (sender == this._itemsCollection && managerType == typeof(CollectionChangedEventManager))
{
// Your collection has changed, you should add/remove
// subscription for PropertyChanged event
UpdateSubscriptions((NotifyCollectionChangedEventArgs)e);
return true;
}
if (sender is Item && managerType == typeof(PropertyChangedEventManager))
{
// The Visible property of an Item object has changed
// You should handle it properly here, for example, like this:
this.ItemsVisible = this._itemsCollection.All(i => i.Visible);
return true;
}
return false;
}
private void UpdateSubscriptions(NotifyCollectionChangedEventArgs e)
{
switch(e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (Item item in e.NewItems)
{
PropertyChangedEventManager.AddListener(item, this, "Visible");
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (Item item in e.OldItems)
{
PropertyChangedEventManager.RemoveListener(item, this, "Visible");
}
break;
case NotifyCollectionChangedAction.Reset:
foreach (Item item in this._itemsCollection)
{
PropertyChangedEventManager.RemoveListener(item, this, "Visible");
PropertyChangedEventManager.AddListener(item, this, "Visible");
}
break;
default:
break;
}
}
...
public Items()
{
_itemsVisible = true;
_itemsCollection = new ObservableCollection<Item>();
CollectionChangedEventManager.AddListener(_itemsCollection, this);
}
}
Binding in the WPF sense only works on DependencyProperties, and does not apply between two standard properties (even when using INotifyPropertyChanged).
That said, if you are using these classes as View Models and are binding them to controls you could use a MultiConverter to set the visibility of the Control to collapsed when both the ItemsVisible and Visible property are true (for example).
Alternatively, you could add a Parent property to the Item class and set it to the parent Items class which would allow you to have the Item.Visible property return the parent's ItemsVisible property (or again whatever logic makes sense in your application).
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I Pass an object OptionSelector to a different ViewModel. When passing it is not null. But on the receiving end it shows as null. Any ideas
My View is wrapped in this class.
public class CoreView : XboxApplicationPage, IRefAppNavigationItem
{
/// <summary>
/// Gets or sets navigation data for nested views.
/// </summary>
public object Data
{
get { return GetValue(DataProperty) as object; }
set { SetValue(DataProperty, value); }
}
/// <summary>
/// Identifies the Data dependency property.
/// </summary>
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data",typeof(object),typeof(CoreView),new PropertyMetadata(null));
/// <summary>
/// Gets or sets the viewModel used in this page.
/// </summary>
public CoreViewModel ViewModel
{
get
{
return (CoreViewModel)GetValue(ViewModelProperty);
}
set { SetValue(ViewModelProperty, value); }
}
/// <summary>
/// Sets the View.DataContext to the View.ViewModel.
/// </summary>
private void SetViewModel()
{
if (ViewModel != null)
{
try
{
if (this.Data != null)
{
ViewModel.Data = this.Data;
}
else
{
ViewModel.Data = this.Tag;
}
SetDataContext();
}
catch(Exception e)
{
Logger.Log("SetViewModel() error :" + e.StackTrace);
}
}
}
/// <summary>
/// Sets the DataContext to the ViewModel.
/// Override when additional actions might be required after setting the DataContext.
/// </summary>
protected virtual void SetDataContext()
{
this.DataContext = ViewModel;
}
/// <summary>
/// Handles on NavigateTo events.
/// </summary>
/// <param name="e">Event args.</param>
/// <remarks>This method is used to get the post navigation data and integrate into CoreView.</remarks>
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
if (DesignerProperties.IsInDesignTool)
{
return;
}
try
{
if (this.currentPageCulture != AmebaTV_XBOXApplication.Common.Resources.Localization.CurrentCulture)
{
UpdateLocalizedStrings(this);
}
Microsoft.Xbox.Controls.Localization.CultureChanged += Localization_CultureChanged;
var postNavigationState = IoC.Get<INavigationService>().GetPostNavigationData(NavigationContext);
if (postNavigationState != null)
{
this.Data = postNavigationState;
}
this.ViewModel.OnNavigatedTo();
if (legendService != null)
{
legendService.IsNavigateBackEnabled = true;
}
base.OnNavigatedTo(e);
}
catch (Exception ex)
{
Logger.Log("OnNavigatedTo : "+ex.Message);
}
}
}
/// <summary>
/// Base class for all ViewModels.
/// </summary>
public class CoreViewModel : ViewModelBase
{
/// <summary>
/// Field for Data.
/// </summary>
private object data;
/// <summary>
/// To be used with navigation to populate view models with initial content.
/// </summary>
public virtual void OnDataSet()
{
}
/// <summary>
/// Gets or sets ViewModel data.
/// </summary>
public object Data
{
get { return this.data; }
set
{
this.data = value;
RaisePropertyChanged("Data");
OnDataSet();
}
}
}
OptionSelectorData object
/// <summary>
/// Contains data for the options selector view.
/// </summary>
public class OptionSelectorData
{
/// <summary>
/// Gets or sets the list of options.
/// </summary>
public IList<string> Options { get; set; }
/// <summary>
/// Gets or sets the option title.
/// </summary>
public string Title { get; set; }
/// <summary>
/// Gets or sets the callback that will be invoked when an option is selected
/// </summary>
public Action<string> NotificationCallback { get; set; }
}
}
Command to trigger navigation
public class MoreOverflowViewModel : CoreViewModel
{
/// <summary>
/// Navigate to Property filter page
/// </summary>
public ICommand gotoViewPagebyCriteria
{
get
{
return new RelayCommand(() =>
{
OptionSelectorData option = new OptionSelectorData
{
Options = filterOptions, Title =
Localization.GetByLocalizationKey("OptionTitleFilter"),
NotificationCallback = OnFilterOptionsCallback
};
Messenger.Default.Send(new NavigateToMessage(new
Uri(PageListings.ViewPageByCriteria, UriKind.Relative), option));
});
}
}
}
Viewmodel to receive data, OnDataSet checks object and sets properties
public class ViewByCriteriaViewModel : CoreViewModel
{
/// <summary>
/// ondataset
/// </summary>
public override void OnDataSet()
{
option = this.Data as OptionSelectorData;
if (option != null)
{
OptionTitle = option.Title;
itemsSource = option.Options;
}
else
{
Logger.Log("NULL Option Data");
}
}
}
Try this. I'm thinking that this.Data isn't getting the object you think it is. If it's some other type, then as will return null.
public override void OnDataSet()
{
Logger.Log("this.Data = " + (this.Data == null ? "null" : this.Data.GetType().Name));
option = this.Data as OptionSelectorData;
if (option != null)
{
OptionTitle = option.Title;
itemsSource = option.Options;
}
else
{
Logger.Log("NULL Option Data");
}
}
Its seems I had a default OnNavigatedTo() that was overriding the method in the base class. Issue resolved.
I am trying to create a settings page for my windows phone 7 application and i am using this article as the basis http://msdn.microsoft.com/en-us/library/ff769510(v=vs.92).aspx so my application class is :
public class AppSettings
{
// Our isolated storage settings
IsolatedStorageSettings isolatedStore;
// The isolated storage key names of our settings
const string CheckBoxSettingKeyName = "CheckBoxSetting";
const string ListBoxSettingKeyName = "ListBoxSetting";
const string RadioButton1SettingKeyName = "RadioButton1Setting";
const string RadioButton2SettingKeyName = "RadioButton2Setting";
const string RadioButton3SettingKeyName = "RadioButton3Setting";
const string UsernameSettingKeyName = "UsernameSetting";
const string PasswordSettingKeyName = "PasswordSetting";
// The default value of our settings
const bool CheckBoxSettingDefault = true;
const int ListBoxSettingDefault = 0;
const bool RadioButton1SettingDefault = true;
const bool RadioButton2SettingDefault = false;
const bool RadioButton3SettingDefault = false;
const string UsernameSettingDefault = "";
const string PasswordSettingDefault = "";
/// <summary>
/// Constructor that gets the application settings.
/// </summary>
public AppSettings()
{
try
{
// Get the settings for this application.
isolatedStore = IsolatedStorageSettings.ApplicationSettings;
}
catch (Exception e)
{
Debug.WriteLine("Exception while using IsolatedStorageSettings: " + e.ToString());
}
}
/// <summary>
/// Update a setting value for our application. If the setting does not
/// exist, then add the setting.
/// </summary>
/// <param name="Key"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool AddOrUpdateValue(string Key, Object value)
{
bool valueChanged = false;
// If the key exists
if (isolatedStore.Contains(Key))
{
// If the value has changed
if (isolatedStore[Key] != value)
{
// Store the new value
isolatedStore[Key] = value;
valueChanged = true;
}
}
// Otherwise create the key.
else
{
isolatedStore.Add(Key, value);
valueChanged = true;
}
return valueChanged;
}
/// <summary>
/// Get the current value of the setting, or if it is not found, set the
/// setting to the default setting.
/// </summary>
/// <typeparam name="valueType"></typeparam>
/// <param name="Key"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
public valueType GetValueOrDefault<valueType>(string Key, valueType defaultValue)
{
valueType value;
// If the key exists, retrieve the value.
if (isolatedStore.Contains(Key))
{
value = (valueType)isolatedStore[Key];
}
// Otherwise, use the default value.
else
{
value = defaultValue;
}
return value;
}
/// <summary>
/// Save the settings.
/// </summary>
public void Save()
{
isolatedStore.Save();
}
/// <summary>
/// Property to get and set a CheckBox Setting Key.
/// </summary>
public bool CheckBoxSetting
{
get
{
return GetValueOrDefault<bool>(CheckBoxSettingKeyName, CheckBoxSettingDefault);
}
set
{
AddOrUpdateValue(CheckBoxSettingKeyName, value);
Save();
}
}
/// <summary>
/// Property to get and set a ListBox Setting Key.
/// </summary>
public int ListBoxSetting
{
get
{
return GetValueOrDefault<int>(ListBoxSettingKeyName, ListBoxSettingDefault);
}
set
{
AddOrUpdateValue(ListBoxSettingKeyName, value);
Save();
}
}
/// <summary>
/// Property to get and set a RadioButton Setting Key.
/// </summary>
public bool RadioButton1Setting
{
get
{
return GetValueOrDefault<bool>(RadioButton1SettingKeyName, RadioButton1SettingDefault);
}
set
{
AddOrUpdateValue(RadioButton1SettingKeyName, value);
Save();
}
}
/// <summary>
/// Property to get and set a RadioButton Setting Key.
/// </summary>
public bool RadioButton2Setting
{
get
{
return GetValueOrDefault<bool>(RadioButton2SettingKeyName, RadioButton2SettingDefault);
}
set
{
AddOrUpdateValue(RadioButton2SettingKeyName, value);
Save();
}
}
/// <summary>
/// Property to get and set a RadioButton Setting Key.
/// </summary>
public bool RadioButton3Setting
{
get
{
return GetValueOrDefault<bool>(RadioButton3SettingKeyName, RadioButton3SettingDefault);
}
set
{
AddOrUpdateValue(RadioButton3SettingKeyName, value);
Save();
}
}
/// <summary>
/// Property to get and set a Username Setting Key.
/// </summary>
public string UsernameSetting
{
get
{
return GetValueOrDefault<string>(UsernameSettingKeyName, UsernameSettingDefault);
}
set
{
AddOrUpdateValue(UsernameSettingKeyName, value);
Save();
}
}
/// <summary>
/// Property to get and set a Password Setting Key.
/// </summary>
public string PasswordSetting
{
get
{
return GetValueOrDefault<string>(PasswordSettingKeyName, PasswordSettingDefault);
}
set
{
AddOrUpdateValue(PasswordSettingKeyName, value);
Save();
}
}
}
Everything is working fine and i am able to update the settings value from a xaml settings page and i can access the setting values in my main application using
IsolatedStorageSettings Settings;
Settings = IsolatedStorageSettings.ApplicationSettings;
string checkboxvalue = (string)Settings["CheckBoxSetting"];
Now what i want is to be able to know when a value in the application settings is changed/updated , so that i can perform a action when settings are updated .
Similar to the other answer but more concrate. If you already use properties to work with, implement INotifyPropertyChanged interface, write your own RaisePropertyChanged/NotifyPropertyChanged and in the destination class subscribe to PropertyChanged event.
IsolatedStorageSettings.ApplicationSettings is a Dictionary. It is not observable by default.
There are lots of ways you could do this but the easiest way to get startred is if you just query the settings when you need to know them.
The other simple alternative woudl be for your AppSettings object to raise events when something was changed and have the relevant other classes subscribe to them.
My combobox returns a set of values from s stored procedure as this
private void BindCombo()
{
DataCombo.FillCombo(ComboDS(2313001), cmbClass, 0);
DataCombo.FillCombo(DDCombo(5007), cmbGroup, 0);
}
I managed to give a rudimentary auto complete suggestion as IsTextSearchenabled but cannot get a auto suggestion box that i would like.
I have seen loads of examples of autocomplete/suggestive textboxes but none of them seem to suit me.
this code apparently suits me.
but how would i use the auto suggest here
using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace DotNetZen.AutoFilteredComboBox
{
public class AutoFilteredComboBox : ComboBox
{
private int silenceEvents = 0;
/// <summary>
/// Creates a new instance of <see cref="AutoFilteredComboBox" />.
/// </summary>
public AutoFilteredComboBox()
{
DependencyPropertyDescriptor textProperty = DependencyPropertyDescriptor.FromProperty(
ComboBox.TextProperty, typeof(AutoFilteredComboBox));
textProperty.AddValueChanged(this, this.OnTextChanged);
this.RegisterIsCaseSensitiveChangeNotification();
}
#region IsCaseSensitive Dependency Property
/// <summary>
/// The <see cref="DependencyProperty"/> object of the <see cref="IsCaseSensitive" /> dependency property.
/// </summary>
public static readonly DependencyProperty IsCaseSensitiveProperty =
DependencyProperty.Register("IsCaseSensitive", typeof(bool), typeof(AutoFilteredComboBox), new UIPropertyMetadata(false));
/// <summary>
/// Gets or sets the way the combo box treats the case sensitivity of typed text.
/// </summary>
/// <value>The way the combo box treats the case sensitivity of typed text.</value>
[System.ComponentModel.Description("The way the combo box treats the case sensitivity of typed text.")]
[System.ComponentModel.Category("AutoFiltered ComboBox")]
[System.ComponentModel.DefaultValue(true)]
public bool IsCaseSensitive
{
[System.Diagnostics.DebuggerStepThrough]
get
{
return (bool)this.GetValue(IsCaseSensitiveProperty);
}
[System.Diagnostics.DebuggerStepThrough]
set
{
this.SetValue(IsCaseSensitiveProperty, value);
}
}
protected virtual void OnIsCaseSensitiveChanged(object sender, EventArgs e)
{
if (this.IsCaseSensitive)
this.IsTextSearchEnabled = false;
this.RefreshFilter();
}
private void RegisterIsCaseSensitiveChangeNotification()
{
System.ComponentModel.DependencyPropertyDescriptor.FromProperty(IsCaseSensitiveProperty, typeof(AutoFilteredComboBox)).AddValueChanged(
this, this.OnIsCaseSensitiveChanged);
}
#endregion
#region DropDownOnFocus Dependency Property
/// <summary>
/// The <see cref="DependencyProperty"/> object of the <see cref="DropDownOnFocus" /> dependency property.
/// </summary>
public static readonly DependencyProperty DropDownOnFocusProperty =
DependencyProperty.Register("DropDownOnFocus", typeof(bool), typeof(AutoFilteredComboBox), new UIPropertyMetadata(true));
/// <summary>
/// Gets or sets the way the combo box behaves when it receives focus.
/// </summary>
/// <value>The way the combo box behaves when it receives focus.</value>
[System.ComponentModel.Description("The way the combo box behaves when it receives focus.")]
[System.ComponentModel.Category("AutoFiltered ComboBox")]
[System.ComponentModel.DefaultValue(true)]
public bool DropDownOnFocus
{
[System.Diagnostics.DebuggerStepThrough]
get
{
return (bool)this.GetValue(DropDownOnFocusProperty);
}
[System.Diagnostics.DebuggerStepThrough]
set
{
this.SetValue(DropDownOnFocusProperty, value);
}
}
#endregion
#region | Handle selection |
/// <summary>
/// Called when <see cref="ComboBox.ApplyTemplate()"/> is called.
/// </summary>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.EditableTextBox.SelectionChanged += this.EditableTextBox_SelectionChanged;
}
/// <summary>
/// Gets the text box in charge of the editable portion of the combo box.
/// </summary>
protected TextBox EditableTextBox
{
get
{
return ((TextBox)base.GetTemplateChild("PART_EditableTextBox"));
}
}
private int start = 0, length = 0;
private void EditableTextBox_SelectionChanged(object sender, RoutedEventArgs e)
{
if (this.silenceEvents == 0)
{
this.start = ((TextBox)(e.OriginalSource)).SelectionStart;
this.length = ((TextBox)(e.OriginalSource)).SelectionLength;
this.RefreshFilter();
}
}
#endregion
#region | Handle focus |
/// <summary>
/// Invoked whenever an unhandled <see cref="UIElement.GotFocus" /> event
/// reaches this element in its route.
/// </summary>
/// <param name="e">The <see cref="RoutedEventArgs" /> that contains the event data.</param>
protected override void OnGotFocus(RoutedEventArgs e)
{
base.OnGotFocus(e);
if (this.ItemsSource != null && this.DropDownOnFocus)
{
this.IsDropDownOpen = true;
}
}
#endregion
#region | Handle filtering |
private void RefreshFilter()
{
if (this.ItemsSource != null)
{
ICollectionView view = CollectionViewSource.GetDefaultView(this.ItemsSource);
view.Refresh();
this.IsDropDownOpen = true;
}
}
private bool FilterPredicate(object value)
{
// We don't like nulls.
if (value == null)
return false;
// If there is no text, there's no reason to filter.
if (this.Text.Length == 0)
return true;
string prefix = this.Text;
// If the end of the text is selected, do not mind it.
if (this.length > 0 && this.start + this.length == this.Text.Length)
{
prefix = prefix.Substring(0, this.start);
}
return value.ToString()
.StartsWith(prefix, !this.IsCaseSensitive, CultureInfo.CurrentCulture);
}
#endregion
/// <summary>
/// Called when the source of an item in a selector changes.
/// </summary>
/// <param name="oldValue">Old value of the source.</param>
/// <param name="newValue">New value of the source.</param>
protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue)
{
if (newValue != null)
{
ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
view.Filter += this.FilterPredicate;
}
if (oldValue != null)
{
ICollectionView view = CollectionViewSource.GetDefaultView(oldValue);
view.Filter -= this.FilterPredicate;
}
base.OnItemsSourceChanged(oldValue, newValue);
}
private void OnTextChanged(object sender, EventArgs e)
{
if (!this.IsTextSearchEnabled && this.silenceEvents == 0)
{
this.RefreshFilter();
// Manually simulate the automatic selection that would have been
// available if the IsTextSearchEnabled dependency property was set.
if (this.Text.Length > 0)
{
foreach (object item in CollectionViewSource.GetDefaultView(this.ItemsSource))
{
int text = item.ToString().Length, prefix = this.Text.Length;
this.SelectedItem = item;
this.silenceEvents++;
this.EditableTextBox.Text = item.ToString();
this.EditableTextBox.Select(prefix, text - prefix);
this.silenceEvents--;
break;
}
}
}
}
}
}
Also found the AutoFilteredComboBox to be very simple to work with. Though I have made some changes:
Removed use of DependencyPropertyDescriptor to avoid memory leak of combobox-objects
Introduced FilterItem-event and FilterList-event to allow one to customize the filtering
Changed default filtering from starts-with-string to contains-string
Removed support of having IsTextSearchEnabled enabled
Shows dropdown as soon one changes the search string, so search result is displayed
Example of how it is used:
<Controls:AutoFilteredComboBox ItemsSource="{Binding ViewModel.AvailableItems}"
SelectedValue="{Binding ViewModel.SelectedItem, Mode=TwoWay}"
IsEditable="True" IsTextSearchEnabled="False"/>
Improved version of AutoFilteredComboBox:
public class AutoFilteredComboBox : ComboBox
{
bool _ignoreTextChanged;
string _currentText;
/// <summary>
/// Creates a new instance of <see cref="AutoFilteredComboBox" />.
/// </summary>
public AutoFilteredComboBox()
{
if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) return;
}
public event Func<object, string, bool> FilterItem;
public event Action<string> FilterList;
#region IsCaseSensitive Dependency Property
/// <summary>
/// The <see cref="DependencyProperty"/> object of the <see cref="IsCaseSensitive" /> dependency property.
/// </summary>
public static readonly DependencyProperty IsCaseSensitiveProperty =
DependencyProperty.Register("IsCaseSensitive", typeof(bool), typeof(AutoFilteredComboBox), new UIPropertyMetadata(false));
/// <summary>
/// Gets or sets the way the combo box treats the case sensitivity of typed text.
/// </summary>
/// <value>The way the combo box treats the case sensitivity of typed text.</value>
[Description("The way the combo box treats the case sensitivity of typed text.")]
[Category("AutoFiltered ComboBox")]
[DefaultValue(true)]
public bool IsCaseSensitive
{
[System.Diagnostics.DebuggerStepThrough]
get
{
return (bool)this.GetValue(IsCaseSensitiveProperty);
}
[System.Diagnostics.DebuggerStepThrough]
set
{
this.SetValue(IsCaseSensitiveProperty, value);
}
}
#endregion
#region DropDownOnFocus Dependency Property
/// <summary>
/// The <see cref="DependencyProperty"/> object of the <see cref="DropDownOnFocus" /> dependency property.
/// </summary>
public static readonly DependencyProperty DropDownOnFocusProperty =
DependencyProperty.Register("DropDownOnFocus", typeof(bool), typeof(AutoFilteredComboBox), new UIPropertyMetadata(false));
/// <summary>
/// Gets or sets the way the combo box behaves when it receives focus.
/// </summary>
/// <value>The way the combo box behaves when it receives focus.</value>
[Description("The way the combo box behaves when it receives focus.")]
[Category("AutoFiltered ComboBox")]
[DefaultValue(false)]
public bool DropDownOnFocus
{
[System.Diagnostics.DebuggerStepThrough]
get
{
return (bool)this.GetValue(DropDownOnFocusProperty);
}
[System.Diagnostics.DebuggerStepThrough]
set
{
this.SetValue(DropDownOnFocusProperty, value);
}
}
#endregion
#region | Handle focus |
/// <summary>
/// Invoked whenever an unhandled <see cref="UIElement.GotFocus" /> event
/// reaches this element in its route.
/// </summary>
/// <param name="e">The <see cref="RoutedEventArgs" /> that contains the event data.</param>
protected override void OnGotFocus(RoutedEventArgs e)
{
base.OnGotFocus(e);
if (this.ItemsSource != null && this.DropDownOnFocus)
{
this.IsDropDownOpen = true;
}
}
#endregion
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
AddHandler(TextBox.TextChangedEvent, new TextChangedEventHandler(OnTextChanged));
KeyUp += AutoFilteredComboBox_KeyUp;
this.IsTextSearchEnabled = false;
}
void AutoFilteredComboBox_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Down)
{
if (this.IsDropDownOpen == true)
{
// Ensure that focus is given to the dropdown list
if (Keyboard.FocusedElement is TextBox)
{
Keyboard.Focus(this);
if (this.Items.Count > 0)
{
if (this.SelectedIndex == -1 || this.SelectedIndex==0)
this.SelectedIndex = 0;
}
}
}
}
if (Keyboard.FocusedElement is TextBox)
{
if (e.OriginalSource is TextBox)
{
// Avoid the automatic selection of the first letter (As next letter will cause overwrite)
TextBox textBox = e.OriginalSource as TextBox;
if (textBox.Text.Length == 1 && textBox.SelectionLength == 1)
{
textBox.SelectionLength = 0;
textBox.SelectionStart = 1;
}
}
}
}
#region | Handle filtering |
private void RefreshFilter()
{
if (this.ItemsSource != null)
{
Action<string> filterList = FilterList;
if (filterList != null)
{
filterList(_currentText);
}
else
{
ICollectionView view = CollectionViewSource.GetDefaultView(this.ItemsSource);
view.Refresh();
}
this.SelectedIndex = -1; // Prepare so arrow down selects first
this.IsDropDownOpen = true;
}
}
private bool FilterPredicate(object value)
{
// We don't like nulls.
if (value == null)
return false;
// If there is no text, there's no reason to filter.
if (string.IsNullOrEmpty(_currentText))
return true;
Func<object, string, bool> filterItem = FilterItem;
if (filterItem != null)
return filterItem(value, _currentText);
if (IsCaseSensitive)
return value.ToString().Contains(_currentText);
else
return value.ToString().ToUpper().Contains(_currentText.ToUpper());
}
#endregion
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
try
{
_ignoreTextChanged = true; // Ignore the following TextChanged
base.OnSelectionChanged(e);
}
finally
{
_ignoreTextChanged = false;
}
}
/// <summary>
/// Called when the source of an item in a selector changes.
/// </summary>
/// <param name="oldValue">Old value of the source.</param>
/// <param name="newValue">New value of the source.</param>
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
if (newValue != null)
{
ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
if (FilterList == null)
view.Filter += this.FilterPredicate;
}
if (oldValue != null)
{
ICollectionView view = CollectionViewSource.GetDefaultView(oldValue);
view.Filter -= this.FilterPredicate;
}
base.OnItemsSourceChanged(oldValue, newValue);
}
private void OnTextChanged(object sender, TextChangedEventArgs e)
{
if (_ignoreTextChanged)
return;
_currentText = Text;
if (!this.IsTextSearchEnabled)
{
this.RefreshFilter();
}
}
I have found a super simple workaround to my problem.
i created a preview text input event of the combobox.
then i just wrote
Combobox.IsDropDownOpen = true
may not the most elegant but works in my case