Tuesday, March 25, 2014

Scrollable Expandable Control's problem

Scrollable-expandable-controls problem.
Scrollable-expandable-controls : are controls that can stretch as its content grows and will display scrollbars when their size is restricted.
Problem appears when they are located inside another scrollable control. Child scrollable-expandable-controls will keep expanding and will count on the outer scrollable control's scrollbars.
if you give it a maximum width or height problem will be resolved but you will need to know the size ahead and you don't have this privilege if you want a dynamic app that works well with all different screen sizes.
in order to achieve required behavior , we need a panel in between to allow its children (scrollable-expandable-control) to grow. Asking them to give the minimum required size and then give them the maximum size the parent provides without displaying scrollbars , currently there is no panel like this.

Here is a one that I developed to provide this functionality:
    class LimitChild : System.Windows.Controls.Panel
    {
        public LimitChild()
        {
        }

        protected override Size MeasureOverride(System.Windows.Size availableSize)
        {
            System.Diagnostics.Debug.Assert(InternalChildren.Count == 1);
            System.Windows.UIElement child = InternalChildren[0];

            Size panelDesiredSize = new Size();
            // panelDesiredSize.Width = availableSize.Width;
            panelDesiredSize.Width = (double)child.GetValue(FrameworkElement.MinWidthProperty);
            panelDesiredSize.Height = (double)child.GetValue(FrameworkElement.MinHeightProperty);

            child.Measure(panelDesiredSize);

            // IMPORTANT: do not allow PositiveInfinity to be returned, that will raise an exception in the caller! 
            // PositiveInfinity might be an availableSize input; this means that the parent does not care about sizing 
            return panelDesiredSize;
        }

        protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize)
        {
            System.Windows.UIElement child = InternalChildren[0];

            child.Arrange(new Rect(0, 0, finalSize.Width, finalSize.Height));
            if (finalSize.Width > child.RenderSize.Width)
                finalSize.Width = child.RenderSize.Width;
            if (finalSize.Height > child.RenderSize.Height)
                finalSize.Height = child.RenderSize.Height;

            return finalSize; // Returns the final Arranged size
        }
    }
and then inside your xaml surround your scrollable-expandable-control with a LimitChild panel.

Monday, March 24, 2014

SugarSync Review

I only tried to use it for one day, and I found all of these defects:

the client software that I install on my computer:
- I cannot log off and log in in a different user name. Once you log in you are stuck.
- some of the folders that are shared with me by other friends , their "sync to my computer" toggle button is completely disabled.
- The folder that I managed to turn its sync-to-my-computer toggle button on, SugarSync failed to sync it. It has a 3 GB file inside it. It says that sync is successful and complete, but actually the file is not in the folder. (P.S: I tried to increase the cache up to 8 GB but did not help.)
- Froze several times and became unresponsive. and I had to kill it every time.
- crashed once.


When I tried to access the Website directly , I faced the following Problems:
- it claims that download was successful and I end up with a broken file.
- if download is interrupted, there is no resume download feature.
- When I download a folder , I end up with 3 or 4 of the downloaded files with 0 KB (empty files). Knowing that they are at least few 3KBs in size but still I receive them with 0 KB and status is downloaded successfully.

Sunday, March 23, 2014

Unaligned Column Header with Data

I am very happy today that I solves a problem that I have been facing for a long time.
:->

When you have a custom control template, column headers will be shifted to the left unshowing the Select All button while the DataGrid cells manage to recognize the row header and shift correctly. Resulting in a column header that is not aligned with its corresponding cells.

CAUSE : some people would think it is the Visibility of the select all button but this is very untrue. The truth is that Width of this button is bound to an un-updated-properly property CellsPanelHorizontalOffset . Simply put , DataGrid fails to update this property accurately , ending up with value (most of the time) equals ZERO.

SOLUTION : bind the Select All button Width to RowHeaderActualWidth and enjoy the magic ;-)


Thursday, October 27, 2011

Don't derive from Selector

It is a base class that is used by ListBox ComboBox TabControl and others.. Why I cannot derive from it? because for some reason the designers decided to declare few critical functionality as internal . These methods were used in ListBox, ComboBox and TabControl in order to achieve their functionality but yet the designer determined to declare these methods as internal .. WHHHYYY?!!

I don't have the answer. I am deriving from ItemsControl instead.

Thursday, September 29, 2011

Double-click on a cell in a DataGrid does not start editing the cell, while F2 works, and begins editing the cell!!!

Double-click on a cell in a DataGrid does not start editing the cell, while F2 works, and begins editing the cell!!!

I worked a lot to solve this problem.. In my case, the problem was that my implementation of IList was not working properly. Specifically, the index operator (this[]) , the IndexOf method and Contains method.. Fix them and then double-click will work again without problems.

Update: just more clarification. In my case, I tried to make a trick to deceive the DataGrid by passing different objects everytime the DataGrid calls the this[] operator on the collection (I return a new object having properties with equal values). But it turned out that DataGrid internally keeps a list of these objects and compare them by reference, ending up with unequal results.

Wednesday, September 28, 2011

A custom IEnumerable implementation does not work properly with DataGrid

I am developing a DataGrid that looks at a data store that does not have a public collection. I implemented an IEnumerable interface for this data-store BUT
the problem is: I am not able to edit cells; every time I try to edit a cell I get this exception saying, "'EditItem' is not allowed for this view.".

You may ask, why not to create a list for your data-store and pass it to the DataGrid. The answer is: Because my data-store might get very large.

Analysis: I did some digging and I found that DataGrid casts Items property (property of its grand base class: ItemsControl) it casts it to IEditableCollectionView. And here where it fails (we will talk about it later). But what is the type of Items Property ?
Items is a property of type ItemCollection (which is a CollectionView) that is created for the Enumerable class that you assigned to ItemsSource. The collection-view is created by calling CollectionViewSource.GetDefaultCollectionView on your Enumerable class.

The analysis' results: DataGrid fails to create an editable CollectionView for your Enumerable class. Why? because you did not implement the correct interface for your Enumerable class.

So, the question is what interfaces your collection (your Enumerable class) should implement, so that the DataGrid can create an editable collection-view for it?

OK , now , it started to make sense.. I dag deeper and deeper and I found this piece of comments inside ViewManager class in .Net framework that clarifies the problem: (ViewManager is the creator of the collection-view for your Enumerable class that eventually will be passed to and used by Items)
The comments say:
// Order of precendence in acquiring the View:
// 0) If collection is already a CollectionView, return it.
// 1) If the CollectionView for this collection has been cached, then
// return the cached instance.
// 2) If a CollectionView derived type has been passed in collectionViewType
// create an instance of that Type
// 3) If the collection is an ICollectionViewFactory use ICVF.CreateView()
// from the collection
// 4) If the collection is an IListSource call GetList() and perform 5),
// etc. on the returned list
// 5) If the collection is an IBindingList return a new BindingListCollectionView
// 6) If the collection is an IList return a new ListCollectionView
// 7) If the collection is an IEnumerable, return a new CollectionView
// (it uses the ListEnumerable wrapper)
// 8) return null
// An IListSource must share the view with its underlying list.

// if the view already exists, just return it
// Also, return null if it doesn't exist and we're called in "lazy" mode

So , all what we need to do now is to implement one of the following interfaces that would generate automatically one of the Collection Views that implements IEditableCollectionView. so that your grid will work correctly.

Finally, I implemented IList in my Enumerable class and it worked without problems :) great ..!!
Helpful Notes:
- The generic version of IList interface is not the one you should implement. You have to implement the non-gernic version of IList.
- You can try, implementing ICollectionViewFactory , but you have to know it is a little bit more complicated. Because you're going to end up implementing few more interfaces in the process.
- You can implement the IEditableObject interface for that items in your list to have more control over editing and validating each item in the list (each row in the DataGrid).

Problem solved.

Update: another complication I created .. read here about it

Friday, September 23, 2011

How to trace inside WPF source code !! FOUND IT..

How to trace inside WPF? Thank God I found the solution posted by Shawn Burke - MSFT
Thank you Shawn :)

And these links too:
http://referencesource.microsoft.com/serversetup.aspx
http://weblogs.asp.net/rajbk/archive/2010/04/21/setting-up-visual-studio-2010-to-step-into-microsoft-net-source-code.aspx

If non of the above worked (... just like what happened with me..), try this one. You can download .Net Framework source code :) .. isn't this neat. Here:
http://www.codeproject.com/Articles/93423/Step-Into-NET-Framework-4-0-Source-Code
Thanks Arik Poznanski :)

But no.. not even this worked .. I guess I still have DLLs that do not have source code of the same version.. But hey, look at the bright side.. I have the source code now.. And I can use the features and tricks provided by links the above. Especially Tracing into properties and filling the Call Stack frame with external assemblies' calls.. providing me with objects' names and methods' names. So I can look them up from the Source Code and figure out the problem that I am having.