I'm new to WPF. I'm facing the following issue. I have a User Control, Here is the Code of User Control
CustomControl Code
public partial class CustomCanvas : UserControl
{
public CustomCanvas()
{
InitializeComponent();
DrawCanvas();
}
private void DrawCanvas()
{
//TODO:
//Get the Dictionary Value from Parent Bound Property
}
public Dictionary<string, List<Shapes>> ShapesData
{
get { return (Dictionary<string, List<Shapes>>)GetValue(ShapesDataProperty); }
set { SetValue(ShapesDataProperty, value); }
}
public static readonly DependencyProperty ShapesDataProperty =
DependencyProperty.Register("ShapesData", typeof(Dictionary<string, List<Shapes>>), typeof(CustomCanvas), new PropertyMetadata(ShapesDataChanged));
private static void ShapesDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var value = e.NewValue;
}
}
Main Window Code
<Grid>
<uc:CustomCanvas ShapesData="{Binding ShData}" ></uc:CustomCanvas>
</Grid>
Value of ShapesData is bounded to following code.
ShData = new Dictionary<string, List<Shapes>>()
{
{"Week 1", new List<Shapes>() {Shapes.Circle, Shapes.Rectangle}},
{"Week 2", new List<Shapes>() {Shapes.Circle}},
{"Week 3", new List<Shapes>() {Shapes.Rectangle}}
};
Now My question is that in CustomControl DrawCanvas Method i want to fetch the bounded value in parent. Could any one guide me regarding that.
P.S: I know how to bound this value in child using relative RelativeSource and Mode as FindAncestor. Here i want to just fetch the value and process that Dictionary data. In ShapesDataChanged i can easily access the data but the issue is in fetching it in DrawCanvas Function.
Thanks in advance.
You can use DependencyObject's GetValue() method.
var theValueYouNeeded = CustomCanvas.GetValue(ShapesDataProperty);
Dictionary<string, List<Shapes>> value = (Dictionary<string, List<Shapes>>)theValueYouNeeded;
....
Related
I have a collection that gets populated with produce. Once the collection is populated, a BindableLayout/DataTemplate bound to a StackLayout will display the items and the user will be prompted with the option to change the Price property of a stock item by typing into an Entry.
A user can type into the provided Entry box to change Price property of each StockInfo object in the collection, and the change WILL SUCCESSFULLY be applied to the Observable Collection, BUT it WILL NOT fire the setter/property changed event of the Observable Collection.
I need the property changed event to fire so that I can effectively execute other parts of my code, but since it won't the fire setter or property changed of the collection, it never gets the chance to tell other parts of my code to do things.
namespace Test
{
public class Testing : BaseContentPage, INotifyPropertyChanged
{
public class StockInfo : BaseContentPage, INotifyPropertyChanged
{
private string description;
public string Description
{
get => description;
set
{
description = value;
OnPropertyChanged();
}
}
private int price;
public int Price
{
get => price;
set
{
price = value;
OnPropertyChanged();
}
}
}
private ObservableCollection<StockInfo> stockItems = new ObservableCollection<StockInfo>();
public ObservableCollection<StockInfo> StockItems
{
get => stockItems;
set
{
stockItems = value;
OnPropertyChanged();
OnPropertyChanged("SumPrices");
}
}
public double SumPrices
{
get
{
return StockItems.Sum(p => p.Price);
}
}
DataTemplate StockTemplate = new DataTemplate(() =>
{
return new StackLayout
{
Orientation = StackOrientation.Horizontal,
Children =
{
new Entry
{
}.Bind(Entry.TextProperty, path: "Description")
,
new Entry
{
Keyboard = Keyboard.Numeric
}.Bind(Entry.TextProperty, path: "Price")
}
};
});
public Testing()
{
BindingContext = this;
StockItems.Add(new StockInfo { Description = "Milk", Price = 20 });
StockItems.Add(new StockInfo { Description = "Cheese", Price = 15 });
Content = new StackLayout
{
Children =
{
new StackLayout
{
}.Invoke(layout => BindableLayout.SetItemTemplate(layout, StockTemplate))
.Bind(BindableLayout.ItemsSourceProperty, path: "StockItems")
,
new Label
{
}.Bind(Label.TextProperty, path: "SumPrices")
}
};
}
}
}
If I put a debugger stop line inside the get/set of the "Description" property in the StockInfo class and then type in the Entry, the debugger will pick it up and stop the program for debugging.
But if I put a debugger stop on a line some where in the set/get of the Observable Collection, the program will not stop inside of it.
*** Edits Below ***
I modified the code so that StockInfo now has a property that includes the price of a product. I also added a variable called SumPrices which will return the Sum of Price within StockItems using LINQ. The first time the page loads, the sum is calculated and the result is correct, but if I change the Entry box that the property is bound to for each object, it has no effect and the SumPrices variable never changes.
Ideally, I'd simply like for the Observable Collection to fire its setter/property change events whenever an Object's property within the collection is changed.
New Update Here
You cannot fire the setter of ObservableCollection when a property of an item in this collection has changed. I've searched so many info from the Internet and found a question similar to yours: ObservableCollection not noticing when Item in it changes (even with INotifyPropertyChanged). Bob Sammers abstract and define a new FullyObservableCollection class and put forward a pretty robust solution, including some of the techniques in other answers. This new class could get notified when a property of item has been changed. I have tested it and worked well.
Simply used it like the following code:
private FullyObservableCollection<StockInfo> stockItems = new FullyObservableCollection<StockInfo>();
public FullyObservableCollection<StockInfo> StockItems
{
get => stockItems;
set
{
stockItems = value;
OnPropertyChanged();
}
}
public Testing ()
{
...
StockItems.ItemPropertyChanged += StockItems_ItemPropertyChanged;
...
}
private void StockItems_ItemPropertyChanged(object sender, ItemPropertyChangedEventArgs e)
{
OnPropertyChanged(nameof(SumPrices));
}
Another workaround is what i've suggested in my previous answer, which is using TextChanged event handler.
In Datatemplate, add an EventHandler for entry:
new Entry
{
}.Bind(Entry.TextProperty, path: "Description",BindingMode.TwoWay)
.Invoke(entry=>entry.TextChanged+=Entry_TextChanged)
private void Entry_TextChanged(object sender, TextChangedEventArgs e)
{
OnPropertyChanged(nameof(SumPrices));
}
For more info, you could refer to Xamarin.Forms - CollectionView sample
Hope it works for you.
I am currently working with a Stacklayout that has list support. I load the data for this list on another thread, then add it to this view on the main thread. This works fine functionality wise, but I am having a slight delay / performance issue when the items are being loaded to the control. So after the call to the API has been made, and the assignment to the main thread is happening. I load around 5 items to ensure that i do not crowd it since it contains images (that are small in size + i use FFImageLoading).
What i have done now is to cache all of the views and then reuse it when possible. Works fine, but does not seem to improve the performance a lot. What im thinking of is to override LayoutChildren because it appears that the children that is added to this stacklayout, is recalculating it's size even though I reuse the View. What might i be doing wrong?
Below is my custom control:
public class CustomStackLayout : StackLayout
{
public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create(nameof(ItemTemplate), typeof(DataTemplate), typeof(CustomStackLayout),
default(DataTemplate), BindingMode.OneWay);
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set
{
SetValue(ItemTemplateProperty, value);
OnPropertyChanged(nameof(ItemTemplate));
}
}
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create("ItemsSource", typeof(IEnumerable), typeof(CustomStackLayout), default(IEnumerable<object>), BindingMode.TwoWay, propertyChanged: ItemsSourceChanged);
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set
{
SetValue(ItemsSourceProperty, value);
OnPropertyChanged(nameof(ItemsSource));
}
}
private static void ItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
{
var items = (CustomStackLayout)bindable;
items.Children.Clear();
if (items.ItemsSource != null)
{
foreach (var item in items.ItemsSource)
{
items.Children.Add(items.GetRowView(item));
}
}
}
protected virtual View GetRowView(object item)
{
// See if cached
var model = item as CustomModel;
if (AllViews.Any(x => x.Message.ObjectID.Equals(model.ObjectID)))
{
return AllViews.Where(x => x.Message.ObjectID.Equals(model.ObjectID)).FirstOrDefault().View;
}
object viewContent;
// Determine if this is a straight up template or using a AllViewselector
if (ItemTemplate is DataTemplateSelector dts)
{
var template = dts.SelectTemplate(item, this);
viewContent = template.CreateContent();
}
else
{
viewContent = ItemTemplate.CreateContent();
}
// Cache views
this.AllViews.Add(new CachedView() { Message = msg, View = viewContent is View ? viewContent as View : ((ViewCell)viewContent).View });
// Bind
var rowView = viewContent is View ? viewContent as View : ((ViewCell)viewContent).View;
rowView.BindingContext = item;
return rowView;
}
public List<CachedView> AllViews = new List<CachedView>();
}
public class CachedView
{
public Type Type { get; set; }
public View View { get; set; }
public Message Message { get; set; }
}
This is how i use it in xaml with a DataTemplateSelector that picks between different views depending on the data:
<controls:CustomStackLayout ItemsSource="{Binding Data}">
<controls:CustomStackLayout.ItemTemplate>
<selector:MyDataTemplateSelector />
</controls:CustomStackLayout.ItemTemplate>
</controls:CustomStackLayout>
I want create user control (user view) in xamarin.forms. My contol has one property. Control choose what the element would be add to the page (Entry or Label). For it I use BindableProperty, but it return only default value. I dont understand what wrong?
Here my user control code:
public partial class UserView : ContentView
{
public UserView()
{
InitializeComponent();
StackLayout stackLayout = new StackLayout();
if (TypeElement == "label") //TypeElement return only "default value"
stackLayout.Children.Add(new Label { Text = "LABEL" });
else
stackLayout.Children.Add(new Entry { Text = "ENTRY" });
Content = stackLayout;
}
public static readonly BindableProperty TypeProperty = BindableProperty.CreateAttached("TypeElement", typeof(string), typeof(UserView), "default value");
public string TypeElement
{
get
{
return (string)GetValue(TypeProperty);
}
set
{
SetValue(TypeProperty, value);
}
}
}
Here I use my control on page:
Your TypeElement property is getting set after the constructor completes, you should be watching for when this property changes and then do what you need to do, for example:
public static readonly BindableProperty TypeProperty = BindableProperty.CreateAttached("TypeElement", typeof(string), typeof(UserView), "default value", propertyChanged:OnTypeElementChanged);
private static void OnTypeElementChanged(BindableObject bindable, object oldValue, object newValue)
{
var userView = bindable as UserView;
StackLayout stackLayout = new StackLayout();
if (userView.TypeElement == "label") //TypeElement return only "default value"
stackLayout.Children.Add(new Label { Text = "LABEL" });
else
stackLayout.Children.Add(new Entry { Text = "ENTRY" });
userView.Content = stackLayout;
}
I have tested this and it works, there are a couple of things about your implementation that confuse me though, such as why you are using an attached property instead of a regular bindable property, and also why you seem to have a XAML file associated with UserView if you're just going to replace the content anyway.
I'm programming a WPF-window-designer application.
In the designer i can add customcontrols to the window and save the window by serializing the Canvas panel on which the added customcontrols are lying to XAML.
public string SerializeControlToXaml(FrameworkElement control)
{
StringBuilder outstr = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
XamlDesignerSerializationManager dsm =
new XamlDesignerSerializationManager(XmlWriter.Create(outstr, settings));
dsm.XamlWriterMode = XamlWriterMode.Expression;
System.Windows.Markup.XamlWriter.Save(control, dsm);
string xaml = outstr.ToString();
return xaml;
}
After that serialization i get the xaml as string and save it in a file which i can reload later.
Now my problem is that i added a new dependency property to one of my customcontrols which is of type ObservableCollection.
Each time i have set that property and try to serialize the canvas to XAML i get an error message:
"Invalid initials in 'ObservableCollection 1'. The sign '', hexadecimal value 0x60, may not be contained in a name."
I never give the collection a name.
What's going wrong?
This is the viewmodel-property to which i bind the control:
public ObservableCollection<string> SelectedFormulas
{
get
{
return selectedFormulas;
}
set
{
selectedFormulas = value;
RaisePropertyChanged("SelectedFormulas");
}
}
And this is my dependencyproperty:
public static readonly DependencyProperty SelectedFormulasProperty =
DependencyProperty.Register("SelectedFormulas", typeof(ObservableCollection<string>), typeof(CustomNumericField));
public ObservableCollection<string> SelectedFormulas
{
get { return GetValue(SelectedFormulasProperty) as ObservableCollection<string>; }
set { SetValue(SelectedFormulasProperty, value); }
}
The answer from dbc is the solution.
What i needed was a non-generic class instead of the ObservableCollection.
This is the new class:
public class SelectedFormulaCollection : ObservableCollection<string>
{
}
And here the DependencyProperty in the customcontrol (Type of the property in the viewmodel must be changed too!):
public static readonly DependencyProperty SelectedFormulasProperty =
DependencyProperty.Register("SelectedFormulas", typeof(SelectedFormulaCollection), typeof(CustomNumericField));
public SelectedFormulaCollection SelectedFormulas
{
get { return GetValue(SelectedFormulasProperty) as SelectedFormulaCollection; }
set { SetValue(SelectedFormulasProperty, value); }
}
I'm not quite sure how to deal with this problem. I'm using a bunch of comboboxes with dropdown lists of values we allow the user to set a property too. (i.e. Currencies = "USD, CAD, EUR").
Every now and then, when we load data, we'll find the currency is something not in our list, like "AUD". In this case, we still want the combobox to display the loaded value, and the current selected Currency should remain "AUD" unless the user chooses to change it, in which case their only options will still be "USD, CAD, EUR".
My problem is that as soon as the control becomes visible, the ComboBox is calling the setter on my SelectedCurrency property and setting it to null, presumably because the current value "AUD" isn't in it's list. How can I disable this behaviour without making it possible for the user to type whatever they want into the Currency field?
Set IsEditable="True", IsReadOnly="True", and your SelectedItem equal to whatever object you want to hold the selected item
<ComboBox ItemsSource="{Binding SomeCollection}"
Text="{Binding CurrentValue}"
SelectedItem="{Binding SelectedItem}"
IsEditable="True"
IsReadOnly="True">
IsEditable allows the Text property to show a value not in the list
IsReadOnly makes it so the Text property is not editable
And SelectedItem stores the selected item. It will be null until the user selects an item in the list, so in your SaveCommand, if SelectedItem == null then use CurrentValue instead of SelectedItem when saving to the database
This seems to be a reasonably common problem. Imagine you have a lookup list in the database, maybe a list of employees. The employee table has a 'works here' flag. Another table references the employee lookup list. When a person leaves the company, you want your views to show the name of the old employee, but not allow the old employee to be assigned in future.
Here's my solution to the similar currency problem:
Xaml
<Page.DataContext>
<Samples:ComboBoxWithObsoleteItemsViewModel/>
</Page.DataContext>
<Grid>
<ComboBox Height="23" ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem}"/>
</Grid>
C#
// ViewModelBase and Set() are from MVVM Light Toolkit
public class ComboBoxWithObsoleteItemsViewModel : ViewModelBase
{
private readonly string _originalCurrency;
private ObservableCollection<string> _items;
private readonly bool _removeOriginalWhenNotSelected;
private string _selectedItem;
public ComboBoxWithObsoleteItemsViewModel()
{
// This value might be passed in to the VM as a parameter
// or obtained from a data service
_originalCurrency = "AUD";
// This list is hard-coded or obtained from your data service
var collection = new ObservableCollection<string> {"USD", "CAD", "EUR"};
// If the value to display isn't in the list, then add it
if (!collection.Contains(_originalCurrency))
{
// Record the fact that we may need to remove this
// value from the list later.
_removeOriginalWhenNotSelected = true;
collection.Add(_originalCurrency);
}
Items = collection;
SelectedItem = _originalCurrency;
}
public string SelectedItem
{
get { return _selectedItem; }
set
{
// Remove the original value from the list if necessary
if(_removeOriginalWhenNotSelected && value != _originalCurrency)
{
Items.Remove(_originalCurrency);
}
Set(()=>SelectedItem, ref _selectedItem, value);
}
}
public ObservableCollection<string> Items
{
get { return _items; }
private set { Set(()=>Items, ref _items, value); }
}
}
You should set IsEditable of the ComboBox to true and bind the Text property instead of the SelectedValue property.
If IsEditable = false then ComboBox does not support a value not in the list.
If you want user action to add a value but not edit that value or any existing values then one approach might be to put the new value in TextBlock (not editable) and a Button to let them add that value. If they select any value from the combobox then hide the TextBlock and Button.
Another approach would be to add the value to the list with more complex logic behind that if any another value is selected then that tentative value is removed. And the tentative value does not get persisted until it is selected.
He doesn't want to be users to be able to type, so IsEditable seems to be off the table.
What I would do is just add the new value AUD to the Item list as
ComboBoxItem Content="AUD" Visibility="Collapsed"
Then Text="AUD" will work in code but not from the drop down.
To be fancy, one could make a converter for the ItemsSource that binds to the TEXT box and adds it collapsed automatically
Here was my solution to this problem:
XAML looks like this:
<DataTemplate>
<local:CCYDictionary Key="{TemplateBinding Content}">
<local:CCYDictionary.ContentTemplate>
<DataTemplate>
<ComboBox Style="{StaticResource ComboBoxCellStyle}"
SelectedValuePath="CCYName"
DisplayMemberPath="CCYName"
TextSearch.TextPath="CCYName"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:CCYDictionary}}, Path=ListItems}"
SelectedValue="{Binding}" />
</DataTemplate>
</local:CCYDictionary.ContentTemplate>
</local:CCYDictionary>
</DataTemplate>
<!-- For Completion's sake, here's the style and the datacolumn using it -->
<Style x:Key="ComboBoxCellStyle" TargetType="ComboBox">
<Setter Property="IsEditable" Value="False"/>
<Setter Property="IsTextSearchEnabled" Value="True"/>
<!-- ...other unrelated stuff (this combobox was was a cell template for a datagrid) -->
</Style>
<Column FieldName="CCYcode" Title="Currency" DataTemplate="{StaticResource CCYEditor}" />
There's probably a nicer way for the dictionary to expose the ItemsSource so that the Bindings aren't so ugly, but once I got it to work I was too tired of the problem to refine it further.
Individual dictionaries declared like so:
public class CCYDictionary : DataTableDictionary<CCYDictionary>
{
protected override DataTable table { get { return ((App)App.Current).ApplicationData.CCY; } }
protected override string indexKeyField { get { return "CCY"; } }
public CCYDictionary() { }
}
public class BCPerilDictionary : DataTableDictionary<BCPerilDictionary>
{
protected override DataTable table { get { return ((App)App.Current).ApplicationData.PerilCrossReference; } }
protected override string indexKeyField { get { return "BCEventGroupID"; } }
public BCPerilDictionary() { }
}
//etc...
Base class looks like:
public abstract class DataTableDictionary<T> : ContentPresenter where T : DataTableDictionary<T>
{
#region Dependency Properties
public static readonly DependencyProperty KeyProperty = DependencyProperty.Register("Key", typeof(object), typeof(DataTableDictionary<T>), new PropertyMetadata(null, new PropertyChangedCallback(OnKeyChanged)));
public static readonly DependencyProperty RowProperty = DependencyProperty.Register("Row", typeof(DataRowView), typeof(DataTableDictionary<T>), new PropertyMetadata(null, new PropertyChangedCallback(OnRowChanged)));
public static readonly DependencyProperty ListItemsProperty = DependencyProperty.Register("ListItems", typeof(DataView), typeof(DataTableDictionary<T>), new PropertyMetadata(null));
public static readonly DependencyProperty IndexedViewProperty = DependencyProperty.Register("IndexedView", typeof(DataView), typeof(DataTableDictionary<T>), new PropertyMetadata(null));
#endregion Dependency Properties
#region Private Members
private static DataTable _SourceList = null;
private static DataView _ListItems = null;
private static DataView _IndexedView = null;
private static readonly Binding BindingToRow;
private static bool cachedViews = false;
private bool m_isBeingChanged;
#endregion Private Members
#region Virtual Properties
protected abstract DataTable table { get; }
protected abstract string indexKeyField { get; }
#endregion Virtual Properties
#region Public Properties
public DataView ListItems
{
get { return this.GetValue(ListItemsProperty) as DataView; }
set { this.SetValue(ListItemsProperty, value); }
}
public DataView IndexedView
{
get { return this.GetValue(IndexedViewProperty) as DataView; }
set { this.SetValue(IndexedViewProperty, value); }
}
public DataRowView Row
{
get { return this.GetValue(RowProperty) as DataRowView; }
set { this.SetValue(RowProperty, value); }
}
public object Key
{
get { return this.GetValue(KeyProperty); }
set { this.SetValue(KeyProperty, value); }
}
#endregion Public Properties
#region Constructors
static DataTableDictionary()
{
DataTableDictionary<T>.BindingToRow = new Binding();
DataTableDictionary<T>.BindingToRow.Mode = BindingMode.OneWay;
DataTableDictionary<T>.BindingToRow.Path = new PropertyPath(DataTableDictionary<T>.RowProperty);
DataTableDictionary<T>.BindingToRow.RelativeSource = new RelativeSource(RelativeSourceMode.Self);
}
public DataTableDictionary()
{
ConstructDictionary();
this.SetBinding(DataTableDictionary<T>.ContentProperty, DataTableDictionary<T>.BindingToRow);
}
#endregion Constructors
#region Private Methods
private bool ConstructDictionary()
{
if( cachedViews == false )
{
_SourceList = table;
if( _SourceList == null )
{ //The application isn't loaded yet, we'll have to defer constructing this dictionary until it's used.
return false;
}
_SourceList = _SourceList.Copy(); //Copy the table so if the base table is modified externally we aren't affected.
_ListItems = _SourceList.DefaultView;
_IndexedView = CreateIndexedView(_SourceList, indexKeyField);
cachedViews = true;
}
ListItems = _ListItems;
IndexedView = _IndexedView;
return true;
}
private DataView CreateIndexedView(DataTable table, string indexKey)
{
// Create a data view sorted by ID ( keyField ) to quickly find a row.
DataView dataView = new DataView(table);
dataView.Sort = indexKey;
dataView.ApplyDefaultSort = true;
return dataView;
}
#endregion Private Methods
#region Static Event Handlers
private static void OnKeyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
// When the Key changes, try to find the data row that has the new key.
// If it is not found, return null.
DataTableDictionary<T> dataTableDictionary = sender as DataTableDictionary<T>;
if( dataTableDictionary.m_isBeingChanged ) return; //Avoid Reentry
dataTableDictionary.m_isBeingChanged = true;
try
{
if( dataTableDictionary.IndexedView == null ) //We had to defer loading.
if( !dataTableDictionary.ConstructDictionary() )
return; //throw new Exception("Dataview is null. Check to make sure that all Reference tables are loaded.");
DataRowView[] result = _IndexedView.FindRows(dataTableDictionary.Key);
DataRowView dataRow = result.Length > 0 ? result[0] : null;
//Sometimes a null key is valid - but sometimes it's just xceed being dumb - so we only skip the following step if it wasn't xceed.
if( dataRow == null && dataTableDictionary.Key != null )
{
//The entry was not in the DataView, so we will add it to the underlying table so that it is not nullified. Treaty validation will take care of notifying the user.
DataRow newRow = _SourceList.NewRow();
//DataRowView newRow = _IndexedView.AddNew();
int keyIndex = _SourceList.Columns.IndexOf(dataTableDictionary.indexKeyField);
for( int i = 0; i < _SourceList.Columns.Count; i++ )
{
if( i == keyIndex )
{
newRow[i] = dataTableDictionary.Key;
}
else if( _SourceList.Columns[i].DataType == typeof(String) )
{
newRow[i] = "(Unrecognized Code: '" + (dataTableDictionary.Key == null ? "NULL" : dataTableDictionary.Key) + "')";
}
}
newRow.EndEdit();
_SourceList.Rows.InsertAt(newRow, 0);
dataRow = _IndexedView.FindRows(dataTableDictionary.Key)[0];
}
dataTableDictionary.Row = dataRow;
}
catch (Exception ex)
{
throw new Exception("Unknow error in DataTableDictionary.OnKeyChanged.", ex);
}
finally
{
dataTableDictionary.m_isBeingChanged = false;
}
}
private static void OnRowChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
// When the Key changes, try to find the data row that has the new key.
// If it is not found, return null.
DataTableDictionary<T> dataTableDictionary = sender as DataTableDictionary<T>;
if( dataTableDictionary.m_isBeingChanged ) return; //Avoid Reentry
dataTableDictionary.m_isBeingChanged = true;
try
{
if( dataTableDictionary.Row == null )
{
dataTableDictionary.Key = null;
}
else
{
dataTableDictionary.Key = dataTableDictionary.Row[dataTableDictionary.indexKeyField];
}
}
catch (Exception ex)
{
throw new Exception("Unknow error in DataTableDictionary.OnRowChanged.", ex);
}
finally
{
dataTableDictionary.m_isBeingChanged = false;
}
}
#endregion Static Event Handlers
}