Hey I am using a WPF 3D scene and successfully loaded a few .stl models into it.
I am basicall using a method to select and deselect these objects, based on where my mouse in the windows is:
private void UIElement_OnMouseDown(object sender, MouseButtonEventArgs e)
{
var viewport = (HelixViewport3D)sender;
var firstHit = viewport.Viewport.FindHits(e.GetPosition(viewport)).FirstOrDefault();
if (firstHit != null)
{
this.viewModel.Select(firstHit.Visual);
}
else
{
this.viewModel.Select(null);
}
}
So I have the selected ModelVisual3D and could store it. However here is the main problem:
My models are generated based on certain data and an associated .stl model.
Basicall I import the .stl model and show it in my 3D scene, but the problem is I have no idea how connect my other data to the model.
For example when I select the visual, I want to show another windows with information like: material, dimensions, company.
But I can't figure out how to determine, which unique ModelVisual3D object is selected at the moment. There seem to be no properties I could use to my advantage doing something like:
ModelImporter tr = new ModelImporter();
var model = tr.Load("C:\\Users\\...\\Pictures\\a.stl");
ModelVisual3D test = new ModelVisual3D();
test.Content = model;
//Here I would like to save the id of my visual model to identify and
//associate it with my other data later
int myUniqueModelID=test.Properties.UNIQUEID
What about using a dictionary to keep the mapping between your data reference and ModelVisual3D reference.
Like
Dictionary<ModelVisual3D, StlDataObject> modelDataMap = new Dictionary<ModelVisual3D, StlDataObject>();
public void LoadModelWithData(string dataFilePath, string stlModelPath)
{
ModelImporter tr = new ModelImporter();
var model = tr.Load("C:\\Users\\...\\Pictures\\a.stl");
ModelVisual3D test = new ModelVisual3D();
test.Content = model;
//Load the datafile from file (or pass it this method)
StlDataObject IdForOurStlModel = GetStlDataFromFile(dataFilePath);
modelDataMap.Add(test, IdForOurStlModel);
}
Then when you need to find your data from the hit test in your viewport, you just check if this dictionary contains a key for the pressed ModelVisual3d and return the value related to that key if it does.
Related
I am building an app which displays a curve in 2D like for example the Math.Sin curve. The user is prompted to enter how many dots he wants to display on the plot. When he chooses the number of dots and enters the parameters for them - a new window is opened where the plot is displayed.
My question is, if there is a way, I can get back to the previous window and enter new parameters which will generate a new curve BUT display it together with the first one? My solution for now is for only one curve being displayed. Any time the Plot window is opened - a new instance of it is created, so I suppose I have to find a way to use the same instance since the window is not closed, only hidden, but I dont know how.
Checkout the following image:
As you have already assumed, you can begin by using the same instance of the Form which displays the PlotView. You could expose a method Update in the PlotDisplayWindow Form, which would then update the plot view with new points. For example, in your parent form.
PlotDisplayWindow plotDisplay;
private void RefreshPlot(object sender, EventArgs e)
{
var dataPoints = GetNewDataPoints();
if (plotDisplay == null)
{
plotDisplay = new PlotDisplayWindow();
plotDisplay.Show();
}
plotDisplay.Update(dataPoints);
}
In your PlotDisplayWindow Form, you could initialize your Model when loading the Window for the first time and then, use the Update method to add more points to the Plot View. For example:
private void PlotDisplayWindow_Load(object sender, EventArgs e)
{
this.plotView1.Model = new PlotModel { Title = "Example 1" };
}
public void Update(IEnumerable<DataPoint> points)
{
this.plotView1.Model.Series.Add(new LineSeries { ItemsSource = points });
this.plotView1.InvalidatePlot(true);
}
The PlotView.InvalidatePlot(true) would ensure the plot is refreshed and the newly added points are displayed.
this may be a very basic question but I'd like to ask if how can I output the variable from a .droid to a .shared project in VS Xamarin. Let's say I have a variable with value in a renderer from a .droid, then I'd like to call it from a .shared page. How can I do this?
ScannerPageRenderer.cs (From .droid)
try
{
var BarcodeText = result.text.ToString();
var BarcodeType = result.typeText.ToString();
}
If you have a ScannerPageRenderer then this means that you are using a custom Renderer for a Xamarin.Forms page.
To pass back the values you can either create public properties in the Page, for this example let's call it ScannerPage then pass the values in the Element object of the custom renderer as this is the Page you are attaching the custom renderer.
ex
private void Scan()
{
//or however you are getting the result...
var result = getScanResult();
var scanPage = Element as ScannerPage;
if (scanPage == null)
{
return;
}
scanPage.BarcodeText = result.text.ToString();
scanPage.BarcodeType = result.typeText.ToString();
}
Another way would be that instead of the two properties you create a public method where you pass in the result object the same way as above with the properties. In such method you will then assign your properties or fields with the values.
private void Scan()
{
var result = getScanResult();
var scanPage = Element as ScannerPage;
if (scanPage == null)
{
return;
}
scanPage.OnScanCompleted(result);
}
Hope this helps.-
I am working on an application that is generating a bunch of collections of ViewModel Instances representing wooden planks (has all needed attriuttes-x,y,z,posx,posy,posz). This works fine.
Now I would like to visualize these Planks inside of the app in a 3d environments:
I have found plenty of examples how to creates boxes with viewport3d Frameworkelement, but my problem is that all of them show how to statically define a single 3dobject.
I was trying and experimenting, but I did not manage to find a single example of how to databind a whole collection, transform single boxes, rotate, and resize them.
Does anyone know how to databind 3D viewmodel collections in WPF?
You can
Put to your Window a dependent property ViewModels and on changing it create your geometry models with bindings in code behind
or
Create a UserControl based ex. on Viewport3D and do 1. for it
The bindings you can create such way(pseudo code):
var geo = new MeshGeometry3D { Positions = new Point3DCollection(pointsLists), TriangleIndices = new Int32Collection(indexes) };
geo.Freeze();
var mat = new DiffuseMaterial(Brushes.Gray); mat.Freeze();
var bMat = new DiffuseMaterial(Brushes.Red); bMat.Freeze();
var geomod = new GeometryModel3D(geo, mat);
geomod.BackMaterial = bMat;
geomod.Transform = new ScaleTransform3D();
var bndng = new Binding("ScaleValue");
bndng.Source = SomeViewModel;//Here put the propriate viewmodel
BindingOperations.SetBinding(geomod.Transform, ScaleTransform3D.ScaleXProperty, bndng);
BindingOperations.SetBinding(geomod.Transform, ScaleTransform3D.ScaleYProperty, bndng);
BindingOperations.SetBinding(geomod.Transform, ScaleTransform3D.ScaleZProperty, bndng);
geomod.Geometry = geo;
Model3DGroup.Children.Add(geomod);//Here you have to find reference to you Model3DGroup
You can use an example that you can copy/paste from:
Same ScaleTransform3D for different geometries
I am making an application in C# WPF and need the location of an object that I added to a panel. While debugging I found the VisualOffset property of the object that gives me the relative position. I just can't get the value from the code.
What I would like to do is (though it is not possible):
var display = new Display(); // This is a class that inhereit UserControl
.
.
// At some point when display is added to a panel
var position = display.VisualOffset; // This property is not accessible
So how can I get the relative position of an object?
Use TranslatePoint method of the Display instance. Set the parent control as a target. The code below will give you coordinates of display on its parent. If the container is further down the visual tree then you have to find a parent of a parent.
In my sample I'm finding that on the parent. I'm doing that on button click and then return the results as a string to a text box - purely for simplicity sake. But the idea is the same wherever you use it:
private void Button_Click(object sender, RoutedEventArgs e)
{
var parent = display.Parent as UIElement;
var location = display.TranslatePoint(new Point(0, 0), parent);
this.myTextBox.Text = $"x: {location.X}, y: {location.Y}";
}
display is of course an instance of the Display user control.
Using MonoDevelop, I have been looking at an IOS implementation of a side slide out menu using FlyoutNavigationController, but have hit a couple of stumbling blocks.
Firstly, how can you access the font elements of the generated list?
I can easily modify row heights etc, but am unsure of how to proceed with modifying the list items, can this be down with a tablesource and item styling?
Secondly, how to open a view from this list?
Currently an empty view is used by default but new views are to be opened from the side menu list, I have tried using the push navigation controller but it fails to open.
Any ideas are more than welcome.
navigation = new FlyoutNavigationController();
navigation.View.Frame = UIScreen.MainScreen.Bounds;
View.AddSubview(navigation.View);
navigation.NavigationRoot = new RootElement ("Menu List")
{
new Section ("Menu List")
{
from page in SlideList
select new StringElement (page.title) as Element
}
};
navigation.NavigationTableView.BackgroundColor = UIColor.DarkGray;
navigation.NavigationTableView.RowHeight = 30;
navigation.NavigationTableView.SeparatorStyle = UITableViewCellSeparatorStyle.SingleLine;
navigation.NavigationTableView.SeparatorColor = UIColor.LightGray;
navigation.NavigationTableView.SectionHeaderHeight = 60;
//navigation.NavigationTableView.DataSource = SlideList;
//navigation.ViewControllers = Array.ConvertAll (MenuItems, title => new UINavigationController (new TaskPageController (navigation, title)));
navigation.ViewControllers = Array.ConvertAll (MenuItems, title => new TaskPageController (navigation, title));
this.NavigationItem.LeftBarButtonItem = new UIBarButtonItem (UIBarButtonSystemItem.Action, delegate {
navigation.ToggleMenu();
});
I haven't used the FlyOutNavigationController before, but I took a look at this example:
https://github.com/xamarin/FlyOutNavigation
It looks like you're supposed to have the same number of StringElements as Controllers. For the ViewControllers array, it looks like you can supply your own custom controllers instead of just plain ViewControllers. After that, clicking a list item should automatically navigate to the appropriate controller.
In regards to styling, looking at the source for this NavigationController, I don't see much in terms of being able to stylize the cells. I did a quick search for how to go about styling MonoTouch Dialog lists and it looks like there isn't an easy way without subclassing elements:
Monotouch Dialog: Styling Elements
However, I can share with you how I've accomplished the two questions you asked without the Dialog framework.
You can create a custom class that extends UITableViewSource:
http://docs.xamarin.com/guides/ios/user_interface/tables/part_2_-_populating_a_table_with_data
In the GetCell method override, you can grab an instance of the cell's label and set the font like so:
cell.TextLabel.Font = UIFont.FromName("TitlingGothicFB Cond", 20);
Another thing you can do with your custom UITableViewSource class is create a custom event:
public event EventHandler ListItemSelected;
Inside the RowSelected method you can dispatch this event:
public override void RowSelected (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
ListItemSelected(this, new MyCustomEventArgs(indexPath.Row));
}
In the controller class that was responsible for instantiating this TableSource, you can listen and handle this event like so:
var customTableSource = new CustomTableSource(myList);
MyTable.Source = customTableSource;
customTableSource.ListItemSelected += (object sender, EventArgs e) => {
if((e as MyCustomEventArgs).rowSelected == 1){
this.NavigationController.PushViewController(new MyNextViewController(), true));
}
}