This project is read-only.

Dimming the items that are not selected

Sep 29, 2011 at 6:15 PM

Hi,

I need to apply some styling to the elements that are not selected. Ideally, I would like to be able to specify the opacity of the elements in the background and to blur them. Having a smooth transition from the "unselected" opacity to 1 would be great.

Would you have any advice on how to do that ?

I have added everything to specify the opacity to the Motion class, as well as a dependency property to specify opacity decay. However, I struggle to find how to apply the computed opacity to the element linked to the 3D model.

 

Sep 30, 2011 at 6:30 AM

I believe this is something that has to do with the items being stored in the ItemsControl, not ElementFlow itself.  You shouldn't need to modify ElementFlow in order to achieve this, as this functionality really has nothing to do with ElementFlow's logic at all.

The way ElementFlow displays your items into 3D is to paint a 3D rectangle with a visual brush, which uses your item's view (painted via its data template) as source.

Therefore, of course you can change the data template so that your items are rendered differently -- and they'll show up differently in the 3D model.  You're most likely using bindings and triggers to do this.

However, you need a way to tell whether the data template whether an item is the currently selected one.  Your item object probably won't have this property -- not every object has an IsSelected property for this use.  Therefore, there is no way for you to determine in your data template whether that particular item is the currently selected one.

One idea I have is to bind to the ElementFlow control's SelectedItem property -- which always returns the currently selected item.  In your data template, put in a trigger that activates when the SelectedItem is the same as the data context -- at that time, the item would be the selected one.

Sep 30, 2011 at 10:19 AM

I have added a dependency property called "OpacityDecay" to the element flow.

Then I added some code to the SelectItem function:

        private void SelectItemCore(int index)
        {
            // Apply opacity animation to the underlying items
            if (_modelContainer != null)
            {
                Visual3DCollection models = _modelContainer.Children;
                int i = 0;
                foreach (Visual3D m in models)
                {
                    ModelUIElement3D model = m as ModelUIElement3D;
                    if (model != null)
                    {
                        FrameworkElement elt = (FrameworkElement)model.GetValue(LinkedElementProperty);
                        elt.Opacity = Math.Pow(OpacityDecay, Math.Abs(i - index));
                    }
                    ++i;
                }
            }
//...
}

Oct 1, 2011 at 1:42 AM

Well, I don't think you need to modify ElementFlow code.  I just tried it within XAML, and it worked fine.

The Steps:

1. Create a MultiConverter called "Match converter" which takes two parameters from the input values and returns true if they are equal.  I am sure there must be a way in XAML to do this comparison without a converter, but I'm too lazy to find out and a converter is pretty simple to write.

2. Put in a trigger in your data template:

<!-- Fade non-selected items -->
<Style.Triggers>
	<DataTrigger Value="True">
		<DataTrigger.Binding>
			<!-- This multi-binding takes the SelectedItem of the ElementFlow control and compares it with the DataContext object using the MatchConverter, which returns true if both objects are the same -->
			<MultiBinding Converter="{x:Static myNamespace:Converters.MatchConverter}">
				<Binding Path="SelectedItem" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type fluidkit:ElementFlow}}" Mode="OneWay" />
				<Binding Path="." Mode="OneWay" />
			</MultiBinding>
		</DataTrigger.Binding>

		<!-- Fade current selected item in/out -->
		<DataTrigger.EnterActions>
			<BeginStoryboard>
				<Storyboard>
					<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.3" />
				</Storyboard>
			</BeginStoryboard>
		</DataTrigger.EnterActions>
		<DataTrigger.ExitActions>
			<BeginStoryboard>
				<Storyboard>
					<DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="0:0:0.8" />
				</Storyboard>
			</BeginStoryboard>
		</DataTrigger.ExitActions>
	</DataTrigger>
</Style.Triggers>

Oct 1, 2011 at 2:19 AM

Just realized that you'd like the opacity to change according to the absolute difference of the item from the current item.

I still think it is best to do this outside of the library (so you don't have to change the core library code).  You should be able to write a very simple converter that takes the current item and returns an opacity value, then bind the opacity of the data template in XAML.  Essentially, all the code you put inside ElementFlow should be in a custom converter instead.

Oct 4, 2011 at 11:47 AM

Thanks for the solutions. I have used what you suggested and it works nicely.

Regards,

Vincent