WPF 3D - mapping gradient brush on complex geometry - wpf

I wanted to ask if anyone knows how to map gradient brush on complex objects in WPF 3D. The result should look similar to 3D images in matlab (3D function for example). Lets say you have some 3-dimensional data you wish to visualize and you want to diferentiate certain levels of values by color.

Given a GradientBrush defined something like this:
<LinearGradientBrush x:Name="RedYellowGradient">
<GradientStop Color="Blue" Offset="0.01" />
<GradientStop Color="Purple" Offset="0.25"/>
<GradientStop Color="Red" Offset="0.5"/>
<GradientStop Color="Orange" Offset="0.75"/>
<GradientStop Color="Yellow" Offset="1.0"/>
</LinearGradientBrush>
Fundamentally, you assign the GradientBrush to the DiffuseMaterial of your MeshGeometry3D. When defining the brush, set its ViewportUnits property to "Absolute".
Something like this would work directly in the code-behind of a XAML form (otherwise, create the brush in code (in your ViewModel) using the corresponding properties, or call it from your resource dictionary):
MyMaterial = New DiffuseMaterial(RedYellowGradient) With {.ViewportUnits = BrushMappingMode.Absolute}
Then, for each Point3D in your geometry, assign a value between 0.0 and 1.0 to the corresponding texture coordinate. Generically, for a pre-sized Point array it could look like this:
Parallel.For(0, positions.Count - 3, Sub(i)
Dim p = positions(i)
Dim plotValue = GetYourValue(p.X, p.Y, p.Z)
Dim t = (plotValue - minPlot) / (maxPlot - minPlot)
If t < 0 Then t = 0
If t > 1 Then t = 1
arr(i) = New Point(t, 0.5)
End Sub)
If your facets are very long or the values between vertices very far apart, your plotting will look odd. But given the strictures of WPF 3D it's probably the best you can do without a lot of UV Mapping.
(If you need C#, the Roslyn CTP has a VS Add-on which will convert VB code on the clipboard to C#...)

Related

How Do I convert LinearGradientBrush object to a Style?

What is the XAML Style equivalent of
LinearGradientBrush(Color.FromArgb(255, 154, 153, 153), Color.FromArgb(255, 51, 50, 50), 80)
Ideally, I would like to make an Application Resource that I could reuse. Thanks!
You can use this Xaml...
<LinearGradientBrush x:Key="MyDefaultBackground" StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="#ff9a9999"/>
<GradientStop Offset="1" Color="#ff333232"/>
</LinearGradientBrush>
This sets a resource called "MyDefaultBackground" for the colours you gave in your question. The start/stop values create a gradient where it's light grey at the top and dark grey at the bottom. You can adjust the start/stop values for a different effect.
The color stop values are in hex (i.e., 153 decimal is 9a hex), when you need to translate decimal values, you can use the built-in windows calculator in 'programmer mode'.
Anytime you want to use it where the Style calls for a Brush, you can compose...
Background={StaticResource MyDefaultBrush}
This will work when the brush is declared higher in the object graph than the style you are composing.
The MSDN docs for LinearGradientBrush are at http://msdn.microsoft.com/en-us/library/system.windows.media.lineargradientbrush(v=vs.110).aspx

Silverlight: change property of drawn object. -- should be easy & how to debug code

Say I have a rectangle in silverlight that I created in Blend. How can I change the background fill on the object.
XAML
<Rectangle x:Name="Background" Stroke="Black" StrokeThickness="0" Height="480" Width="640">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="White" Offset="1"/>
<GradientStop Color="#FED40707" Offset="0.164"/>
<GradientStop Color="#FED5EB0E" Offset="0.392"/>
<GradientStop Color="#FE849AF4" Offset="0.595"/>
<GradientStop Color="#FE2C9937" Offset="0.797"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
.cs file
Rectangle Background = new Rectangle();
string fileName = "Images/yello.png";
BitmapImage image = new BitmapImage(new Uri(fileName, UriKind.Relative));
ImageBrush brush = new ImageBrush();
brush.ImageSource = image;
Background.Fill = brush;
Background.UpdateLayout();
This runs but nothing happens. Also how can I debug this code. I loaded the project file into VS 2012 but when it runs it won't stop on breakpoints.
Also tried:
Background.Fill = new SolidColorBrush(Colors.Red);
Your .cs code fails as you are newing a rectangle called Background, that has nothing to do with the element named Background in your XAML file.
When you name an element in a XAML file, a C# member of that name is generated in the designer file and that property is connected to the XAML element (via a search by name of the loaded XAML element tree). That means that all named elements can simply be referenced as properties in the code behind. Take a look in your designer file to get a feel for what is going on behind the scenes.
Remove the Rectangle Background = new Rectangle(); line and try again. You also should not need to call Background.UpdateLayout();
You also probably want to choose another name, rather than Background, for your rectangle element as that may cause confusion with the Background property of all Panel elements
There may be other problems, but best you sort out these ones first :)

Styling Ribbon from the RibbonControlsLibrary

Ribbon is nice. I want to make it nicer... (IMHO)
With the Ribbon (from RibbonControlsLibrary on .NET 3.5 sp1), it is ok to change some backgrounds and foregrounds. But the thing I want to re-style is the white "mask" (linear gradient brush with alpha) that seats in the "background" of the RibbonTabGroup. I saw it with Snoop. I found it in the style.
<LinearGradientBrush x:Key="[49] Í" StartPoint="0.5,0.0" EndPoint="0.5,1.0">
<GradientStop Color="#EEFFFFFF" Offset="0.0" />
<GradientStop Color="#BBFFFFFF" Offset="0.1" />
<GradientStop Color="#05FFFFFF" Offset="0.5" />
<GradientStop Color="#20FFFFFF" Offset="1.0" />
</LinearGradientBrush>
But still I have no idea how to override it. I don't know either where it is set...
Cheers, Patrick
I got it!
With help of the following post Serialize a UserControl to xaml, but not its children? [Many thanks to you Will]. I could extract the "default" style. So I obtain the complete style. What I did before, open RibbonControlsLibrary with .NET Reflector and read the XAML with BAML Viewer. Not ideal in my case.
Just in case someone has the same wish, obtaining the default style of component (when it isn't published #MSDN):
System.Windows.Style style = Application.Current.FindResource(typeof(Microsoft.Windows.Controls.Ribbon.Ribbon)) as System.Windows.Style;
var sb = new System.Text.StringBuilder();
var writer = System.Xml.XmlWriter.Create(sb, new System.Xml.XmlWriterSettings
{
Indent = true,
ConformanceLevel = System.Xml.ConformanceLevel.Fragment,
OmitXmlDeclaration = true
});
var mgr = new System.Windows.Markup.XamlDesignerSerializationManager(writer);
mgr.XamlWriterMode = System.Windows.Markup.XamlWriterMode.Expression;
System.Windows.Markup.XamlWriter.Save(style, mgr);
string styleString = sb.ToString();
Cheers, Patrick

How to create a repeating background with xaml elements in silverlight?

I want to create an area in my application that looks draggable. Usually, you see this done with a background of small dots or squares, or sometimes lines. I'm using Silverlight and I want to simply create a background that is a set of repeating small rectangles. I honestly cannot figure out how to generate a background with xaml. I'd rather not have to create every little rectangle -- this will also cause the control not to scale. Is there some way to repeat xaml elements to form a pattern? This would be similar to CSS repeating backgrounds, but I would like to use xaml instead of images.
You can use a brush, like this:
<Rectangle>
<Rectangle.Fill>
<LinearGradientBrush EndPoint="6,6" StartPoint="2,2" SpreadMethod="Repeat" MappingMode="Absolute">
<GradientStop Color="#FFAFAFAF" Offset="0"/>
<GradientStop Color="#00FFFFFF" Offset="1"/>
<GradientStop Color="#00FFFFFF" Offset="0.339"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
I've nicked this particular example from the excellent blacklight project, you'll need to play around with all the different settings to see what does what. I'm guessing a radial brush will allow you to get dots, etc. I think they created it in blend as all the numbers were crazy decimals until I sanitised them a bit.

WPF: Changing Resources (colors) from the App.xaml during runtime

I am trying to make my application more customizable by allowing users to pick a color from a Color Picker dialog, and then changing the style of the application in real time (with DynamicResource)
How do I go about in changing specific resources that reside in the app.xaml ?
I have tried something like this but no luck (just a test):
var colorDialog = new CustomControls.ColorPickerDialog();
var dResult = colorDialog.ShowDialog();
var x = Application.Current.Resources.Values.OfType<LinearGradientBrush>().First();
x = new LinearGradientBrush();
x.GradientStops.Add(new GradientStop(colorDialog.SelectedColor,1));
This an excerpt of the app.xaml file:
<Application.Resources>
<LinearGradientBrush x:Key="HeaderBackground" StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="#82cb02" Offset="1"/>
<GradientStop Color="#82cb01" Offset="0.2"/>
<GradientStop Color="#629a01" Offset="0.5"/>
</LinearGradientBrush>
</Application.Resources>
What is the best way to allow this form of customizability (basically just changing some colors) to an application?
[Update]
I just found this answer from a previous question that was asked, and tried it but I am getting the same InvalidOperationException exception Petoj mentioned in the comments for the given answer. Here is the sample code from the answer:
Xaml:
<LinearGradientBrush x:Key="MainBrush" StartPoint="0,0.5" EndPoint="1,0.5" >
<GradientBrush.GradientStops>
<GradientStop Color="Blue" Offset="0" />
<GradientStop Color="Black" Offset="1" />
</GradientBrush.GradientStops>
</LinearGradientBrush>
C#:
LinearGradientBrush myBrush = FindResource("MainBrush") as LinearGradientBrush;
myBrush.GradientStops[0].Color = Colors.Red;
It looks like you're trying to do some sort of skinning?
I'd recommend defining the resources in a Resource Dictionary contained in a separate file. Then in code (App.cs to load a default, then elsewhere to change) you can load the resources as so:
//using System.Windows
ResourceDictionary dict = new ResourceDictionary();
dict.Source = new Uri("MyResourceDictionary.xaml", UriKind.Relative);
Application.Current.Resources.MergedDictionaries.Add(dict);
You could also define the default resource dictionary in App.xaml and unload it in code just fine.
Use the MergedDictionaries object to change the dictionary you're using at runtime. Works like a charm for changing an entire interface quickly.
Changing application wide resources in runtime is like:
Application.Current.Resources("MainBackgroundBrush") = Brsh
About the InvalidOperationException, i guess WallStreet Programmer is right.
Maybe you should not try to modify an existing brush, but instead create a new brush in code with all the gradientstops you need, and then assign this new brush in application resources.
Another Approach on changing the color of some GradientStops is to define those colors as DynamicResource references to Application Wide SolidColorBrushes like:
<LinearGradientBrush x:Key="MainBrush" StartPoint="0, 0.5" EndPoint="1, 0.5" >
<GradientBrush.GradientStops>
<GradientStop Color="{DynamicResource FirstColor}" Offset="0" />
<GradientStop Color="{DynamicResource SecondColor}" Offset="1" />
</GradientBrush.GradientStops>
and then use
Application.Current.Resources["FirstColor"] = NewFirstColorBrsh
Application.Current.Resources["SecondColor"] = NewSecondColorBrsh
HTH
Use the Clone() method to make a deep copy of the brush (or any other freezable object like Storyboard) and then use it:
LinearGradientBrush myBrush = FindResource("MainBrush") as LinearGradientBrush;
myBrush = myBrush.Clone();
myBrush.GradientStops[0].Color = Colors.Red;
#WallstreetProgrammer is right - all application level resources are frozen by default.
Thats why you need to clone the object first.
You get an exception because you are trying to modify a frozen object. All application level resources are automatically frozen if they are freezable and LinearGradientBrush is. If you add it on a lower level like window level it will work.

Resources