Navisworks COM API for Exporting geometry and calculating faces and vertices - autodesk

I am trying to export the vertices, faces and colors of a selected object in the Navis. After a bit of research I found that we can do it using the COM API provided by the Navisworks. I used getprimitives to find the triangles. which looks is something as below.
'using Autodesk.Navisworks.Api;
using Autodesk.Navisworks.Api.Plugins;
using ComBridge = Autodesk.Navisworks.Api.ComApi.ComApiBridge;
using COMApi = Autodesk.Navisworks.Api.Interop.ComApi;
#region InwSimplePrimitivesCB Class
class CallbackGeomListener : COMApi.InwSimplePrimitivesCB
{
public void Line(COMApi.InwSimpleVertex v1,
COMApi.InwSimpleVertex v2)
{
// do your work
}
public void Point(COMApi.InwSimpleVertex v1)
{
// do your work
}
public void SnapPoint(COMApi.InwSimpleVertex v1)
{
// do your work
}
public void Triangle(COMApi.InwSimpleVertex v1,
COMApi.InwSimpleVertex v2,
COMApi.InwSimpleVertex v3)
{
// do your work
}
}
#endregion
#region NW Plugin
[PluginAttribute("Test","ADSK",DisplayName= "Test")]
[AddInPluginAttribute(AddInLocation.AddIn)]
public class Class1:AddInPlugin
{
public override int Execute(params string[] parameters)
{
// get the current selection
ModelItemCollection oModelColl =
Autodesk.Navisworks.Api.Application.
ActiveDocument.CurrentSelection.SelectedItems;
//convert to COM selection
COMApi.InwOpState oState = ComBridge.State;
COMApi.InwOpSelection oSel =
ComBridge.ToInwOpSelection(oModelColl);
// create the callback object
CallbackGeomListener callbkListener =
new CallbackGeomListener();
foreach (COMApi.InwOaPath3 path in oSel.Paths())
{
foreach (COMApi.InwOaFragment3 frag in path.Fragments())
{
// generate the primitives
frag.GenerateSimplePrimitives(
COMApi.nwEVertexProperty.eNORMAL,
callbkListener);
}
}
return 0;
}
}
#endregion
'
The problem here is I am not able to find faces, I do get vertices by using triangle method.
Please let me know if anyone knows how to find faces and color of the object.

Related

Xamarin Forms - custom map marker not visible

I am following article on MS page about Custom map renderer and I can not get it to work for android. Map shows but pins (Markers) are not there. I did not found what I did different from official documents (as in previous link). When I debug, there are 3 markers in customPins collection. And custom renderer works in UWP. So issue is only in Android code.
Here is my CustomRender code for Android which does not shows pins.
using System;
using System.Collections.Generic;
using Android.Content;
using Android.Gms.Maps;
using Android.Gms.Maps.Model;
using Android.Widget;
using iVanApp;
using iVanApp.Android.CustomMapRenderers;
using iVanApp.Droid;
using iVanApp.Model;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.Android;
[assembly: ExportRenderer(typeof(NightMap), typeof(MapRenderers))]
namespace iVanApp.Android.CustomMapRenderers
{
public class MapRenderers : MapRenderer, GoogleMap.IInfoWindowAdapter
{
List<NightPin> customPins;
public MapRenderers(Context context) : base(context)
{
}
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
NativeMap.InfoWindowClick -= OnInfoWindowClick;
}
if (e.NewElement != null)
{
var formsMap = (NightMap)e.NewElement;
customPins = formsMap.NightPins;
}
}
protected override void OnMapReady(GoogleMap map)
{
base.OnMapReady(map);
NativeMap.InfoWindowClick += OnInfoWindowClick;
NativeMap.SetInfoWindowAdapter(this);
}
protected override MarkerOptions CreateMarker(Pin pin)
{
var marker = new MarkerOptions();
marker.SetPosition(new LatLng(pin.Position.Latitude, pin.Position.Longitude));
marker.SetTitle(pin.Label);
marker.SetSnippet(pin.Address);
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.pin));
return marker;
}
void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
{
var customPin = GetCustomPin(e.Marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (!string.IsNullOrWhiteSpace(customPin.Name))
{
}
}
NightPin GetCustomPin(Marker annotation)
{
var position = new Position(annotation.Position.Latitude, annotation.Position.Longitude);
foreach (var pin in customPins)
{
if (pin.Position == position)
{
return pin;
}
}
return null;
}
public global::Android.Views.View GetInfoContents(Marker marker)
{
var inflater = global::Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as global::Android.Views.LayoutInflater;
if (inflater != null)
{
global::Android.Views.View view;
var customPin = GetCustomPin(marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
view = inflater.Inflate(Resource.Layout.mtrl_layout_snackbar_include, null);
if (customPin.Name.Equals("Xamarin"))
{
view = inflater.Inflate(Resource.Layout.XamarinMapInfoWindow, null);
}
else
{
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
}
var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);
if (infoTitle != null)
{
infoTitle.Text = marker.Title;
}
if (infoSubtitle != null)
{
infoSubtitle.Text = marker.Snippet;
}
return view;
}
return null;
}
public global::Android.Views.View GetInfoWindow(Marker marker)
{
return null;
}
}
}
DOes anyone have idea why this would not work?
Note: I had to modify official MS code because I got errors. Wherever is Android.Views.View I had to modify it to global::Android.Views.View otherwise I got following error
"'MapRenderers' does not implement interface member
'GoogleMap.IInfoWindowAdapter.GetInfoContents(Marker)'.
'MapRenderers.GetInfoContents(Marker)' cannot implement
'GoogleMap.IInfoWindowAdapter.GetInfoContents(Marker)' because it does
not have the matching return type of 'View'.".
and
The type or namespace name 'Views' does not exist in the namespace
'iVanApp.Android' (are you missing an assembly reference?)
Hope this did not break my code.
After investigating and reading about custom map issues (and mostly solutions) from others I got a workaround solution how to get pins on map but does not show info window when I click on pin(marker). Here I found workaround. If I modify OnMapReday and call&add method SetMapMarkers then pins are visible but as I said no info window is shown when I click on pin
protected override void OnMapReady(GoogleMap map)
{
base.OnMapReady(map);
NativeMap.InfoWindowClick += OnInfoWindowClick;
NativeMap.SetInfoWindowAdapter(this);
SetMapMarkers();
}
private void SetMapMarkers()
{
NativeMap.Clear();
foreach (var pin in customPins)
{
NativeMap.AddMarker(CreateMarker(pin));
}
}
Although this is solution, I would prefer if I could get it to work without this workaround. Hence I did not put much effort why info window is not shown when you click on pin. In case there would be no solution without this workaround then I will be interested in solution with workaround but as I said I do not prefer to go this way.
As FreakyAli said that adding a custom pin and positions for CustomMap.
<local:CustomMap x:Name="customMap" MapType="Street" />
Adding a custom pin and positions the map's view with the MoveToRegion method
public MainPage()
{
InitializeComponent();
var pin = new CustomPin
{
Type = PinType.Place,
Position = new Position(37.79752, -122.40183),
Label = "Xamarin San Francisco Office",
Address = "394 Pacific Ave, San Francisco CA",
Id = "Xamarin",
Url = "http://xamarin.com/about/"
};
customMap.CustomPins = new List<CustomPin> { pin };
customMap.Pins.Add(pin);
customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Distance.FromMiles(1.0)));
}
I can get InfoWindow by clicking map pin, having no problem.

GeoDataApi.getAutocompletePredictions not working

I am building an android application that shows autocomplete feature and fetches autocomplete predictions in google maps using - GeoDataApi.getAutocompletePredictions. I followed this tutorial - https://github.com/googlesamples/android-play-places/blob/master/PlaceComplete/Application/src/main/java/com/example/google/playservices/placecomplete/PlaceAutocompleteAdapter.java
But somehow this is not working fine for me.
My class is this -
public class GooglePlacesAutoCompleteAdapter extends ArrayAdapter implements Filterable {
private ArrayList<PlaceAutocomplete> mResultList;
GoogleApiClient mGoogleApiClient;
private LatLngBounds mBounds;
private AutocompleteFilter mPlaceFilter;
int radius = 500;
public GooglePlacesAutoCompleteAdapter(Context context, int textViewResourceId, GoogleApiClient googleApiClient,
Location lastLocation, AutocompleteFilter filter) {
super(context, textViewResourceId);
LatLng currentLatLng = new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude());
mBounds = Utility.boundsWithCenterAndLatLngDistance(currentLatLng, 500, 500);
mGoogleApiClient = googleApiClient;
mPlaceFilter = filter;
}
#Override
public int getCount() {
return mResultList.size();
}
#Override
public PlaceAutocomplete getItem(int index) {
return mResultList.get(index);
}
#Override
public android.widget.Filter getFilter() {
Filter filter = new Filter() {
#Override
public FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if (constraint != null && constraint.length() > 3 && constraint.length()%3 == 1) {
// Retrieve the autocomplete results.
mResultList = autocomplete(constraint.toString());
// Assign the data to the FilterResults
filterResults.values = mResultList;
filterResults.count = mResultList.size();
}
return filterResults;
}
#Override
public void publishResults(CharSequence constraint, FilterResults results) {
if (results != null && results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
};
return filter;
}
public ArrayList<PlaceAutocomplete> autocomplete(String input) {
if (mGoogleApiClient.isConnected()) {
// Submit the query to the autocomplete API and retrieve a PendingResult that will
// contain the results when the query completes.
PendingResult results = Places.GeoDataApi.getAutocompletePredictions(mGoogleApiClient, input.toString(),
mBounds, mPlaceFilter);
// This method should have been called off the main UI thread. Block and wait for at most 60s
// for a result from the API.
AutocompletePredictionBuffer autocompletePredictions = (AutocompletePredictionBuffer)results.await(60, TimeUnit.SECONDS);
// Confirm that the query completed successfully, otherwise return null
final Status status = autocompletePredictions.getStatus();
if (!status.isSuccess()) {
//Toast.makeText(getContext(), "Error contacting API: " + status.toString(),Toast.LENGTH_SHORT).show();
//Log.e(TAG, "Error getting autocomplete prediction API call: " + status.toString());
autocompletePredictions.release();
return null;
}
// Copy the results into our own data structure, because we can't hold onto the buffer.
// AutocompletePrediction objects encapsulate the API response (place ID and description).
Iterator<AutocompletePrediction> iterator = autocompletePredictions.iterator();
ArrayList resultList = new ArrayList<>(autocompletePredictions.getCount());
while (iterator.hasNext()) {
AutocompletePrediction prediction = iterator.next();
// Get the details of this prediction and copy it into a new PlaceAutocomplete object.
resultList.add(new PlaceAutocomplete(prediction.getPlaceId(), prediction.getDescription()));
}
// Release the buffer now that all data has been copied.
autocompletePredictions.release();
return resultList;
}
//Log.e(TAG, "Google API client is not connected for autocomplete query.");
return null;
}
class PlaceAutocomplete {
public CharSequence placeId;
public CharSequence description;
PlaceAutocomplete(CharSequence placeId, CharSequence description) {
this.placeId = placeId;
this.description = description;
}
#Override
public String toString() {
return description.toString();
}
}
}
The line on which GeoDataApi.getAutocompletePredictions is called, goes into an internal classes called - Filter.java, Log.java, handler.java and then Looper.java and loops there indefinetly on line 121 of Looper.java (I am sure studio sdk will show the code for Looper.java).
It is not even throwing an error, or going to the next line, it just does not work. Plus, I am not able to see the stack trace of an error.
This is the code snippet which is calling this -
if (mLastLocation != null) {
GooglePlacesAutoCompleteAdapter placesAdapter = new GooglePlacesAutoCompleteAdapter(this, R.layout.item_list, mGoogleApiClient, mLastLocation, null);
autoCompView.setAdapter(placesAdapter);
autoCompView.setOnItemClickListener(this);
}
Can someone please tell me what I am doing wrong here? Please any help will be greatly appreciated. I need to get this working as soon as I could.
PS - I am passing mPlaceFilter as null here.
Enable the Google Places API for Android in developers console

how to add google map in windows phone 8 app

I am developing an app which uses Map service for Windows Phone 8.
I followed a link
http://themightyhedgehog.blogspot.de/2013/01/how-to-use-google-maps-in-your-own.html
and tries to develop an app containing Google Map.
But I got an error in Xaml on line
MapAppScope:BindingHelpers.TileSource="{Binding GoogleMap}"
and the error I got are:
BuildingHelpers is not supported in Silverlight.
The attachable property 'TileSource' was not found in type 'BuildingHelpers'.
The Namespace prefix "MapAppScope" is not defined.
In Xaml:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Microsoft_Phone_Controls_Maps:Map
Name="MyMap"
Grid.Column="1"
LogoVisibility="Collapsed"
d:LayoutOverrides="GridBox"
MapAppScope:BindingHelpers.TileSource="{Binding GoogleMap}"
Margin="0,0,0,2">
<Microsoft_Phone_Controls_Maps:Map.Mode>
<MSPCMCore:MercatorMode/>
</Microsoft_Phone_Controls_Maps:Map.Mode>
</Microsoft_Phone_Controls_Maps:Map>
</Grid>
In .CS:
namespace Google_Map_App
{
public enum GoogleType
{
Street = 'm',
Hybrid = 'y',
Satellite = 's',
Physical = 't',
PhysicalHybrid = 'p',
StreetOverlay = 'h',
WaterOverlay = 'r'
}
public class Google : TileSource
{
public Google()
{
MapType = GoogleType.Street;
UriFormat = #"http://mt{0}.google.com/vt/lyrs={1}&z={2}&x={3}&y={4}";
}
public GoogleType MapType { get; set; }
public override Uri GetUri(int x, int y, int zoomLevel)
{
return new Uri(
string.Format(UriFormat, (x % 2) + (2 * (y % 2)),
(char)MapType, zoomLevel, x, y));
}
}
public static class BindingHelpers
{
//Used for binding a single TileSource object to a Bing Maps control
#region TileSourceProperty
// Name, Property type, type of object that hosts the property, method to call when anything changes
public static readonly DependencyProperty TileSourceProperty =
DependencyProperty.RegisterAttached("TileSource", typeof(TileSource),
typeof(BindingHelpers), new PropertyMetadata(SetTileSourceCallback));
// Called when TileSource is retrieved
public static TileSource GetTileSource(DependencyObject obj)
{
return obj.GetValue(TileSourceProperty) as TileSource;
}
// Called when TileSource is set
public static void SetTileSource(DependencyObject obj, TileSource value)
{
obj.SetValue(TileSourceProperty, value);
}
//Called when TileSource is set
private static void SetTileSourceCallback(object sender, DependencyPropertyChangedEventArgs args)
{
var map = sender as Map;
var newSource = args.NewValue as TileSource;
if (newSource == null || map == null) return;
// Remove existing layer(s)
for (var i = map.Children.Count - 1; i >= 0; i--)
{
var tileLayer = map.Children[i] as MapTileLayer;
if (tileLayer != null)
{
map.Children.RemoveAt(i);
}
}
var newLayer = new MapTileLayer();
newLayer.TileSources.Add(newSource);
map.Children.Add(newLayer);
}
#endregion
}
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
// Sample code to localize the ApplicationBar
//BuildLocalizedApplicationBar();
}
}
}
Note that using Google Maps tiles in the Bing Maps WP8 or Windows 8 control is against the terms of use of both the Bing Maps and Google Maps API's. Any app found in the app store doing this will be removed.

Bind to action method

Is it possible to use a simple action method - just like with Caliburn.Micro - instead of a command with MvvmCross bindings?
Example:
public void Action()
{
Tip = 11;
}
<Button
android:text="Button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/button1"
local:MvxBind="Click Action" />
It doesn't work out of the box, I tested that.
While I found a lot of samples about adding new target bindings, I didn't find a single one about adding a new source binding.
UPDATE:
This works now out of the box with the Rio binding. To use it, add the MvvmCross MethodBinding NuGet package to the Android project.
Up until now, much of the emphasis for MvvmCross has been on allowing multi-platform target binding with the source remaining mainly 'vanilla' INotifyPropertyChanged.
There have been some deviation in terms of ViewModel structure - e.g.:
the MvxCommandCollection - http://slodge.blogspot.co.uk/2013/03/fixing-mvvm-commands-making-hot-tuna.html
some users using Fody - http://twincoders.com/blog/codigo-limpio-con-fody/
Recently, several new feature requests have also been logged in this area:
AutoCommands - I think this is what you are asking about here - https://github.com/slodge/MvvmCross/issues/301
Rio binding sources - https://github.com/slodge/MvvmCross/issues/299
Tibet binding - https://github.com/slodge/MvvmCross/issues/298
Because of these, I do expect more functionality to be exposed in this area in the future...
With that said, if you wanted to get this working today, then MvvmCross Binding is overrideable so you could fairly easily do it:
1. Implement an ICommand that invokes a MethodInfo using reflection (for completeness this should probably also use a parameter if available) - some kind of InvokeMethodCommand (code for this left to the reader!)
.
2. Implement an MyMethodSourceBinding class which wraps the InvokeMethodCommand - something like:
public class MyMethodSourceBinding : MvxSourceBinding
{
private readonly MethodInfo _methodInfo;
protected MyMethodSourceBinding(object source, MethodInfo methodInfo)
: base(source)
{
_methodInfo = _methodInfo;
}
public override void SetValue(object value)
{
// do nothing - not allowed
}
public override Type SourceType
{
get { return typeof(ICommand); }
}
public override bool TryGetValue(out object value)
{
value = new InvokeMethodCommand(source, _methodInfo);
return true;
}
}
3. Override MvvmCross's registered IMvxSourceBindingFactory with your own implementation that can detect when a method is present - sadly most of this is cut and paste coding today - it would be something like
public class MySourceBindingFactory
: IMvxSourceBindingFactory
{
private IMvxSourcePropertyPathParser _propertyPathParser;
private IMvxSourcePropertyPathParser SourcePropertyPathParser
{
get
{
if (_propertyPathParser == null)
{
_propertyPathParser = Mvx.Resolve<IMvxSourcePropertyPathParser>();
}
return _propertyPathParser;
}
}
public IMvxSourceBinding CreateBinding(object source, string combinedPropertyName)
{
var tokens = SourcePropertyPathParser.Parse(combinedPropertyName);
return CreateBinding(source, tokens);
}
public IMvxSourceBinding CreateBinding(object source, IList<MvxPropertyToken> tokens)
{
if (tokens == null || tokens.Count == 0)
{
throw new MvxException("empty token list passed to CreateBinding");
}
var currentToken = tokens[0];
if (tokens.Count == 1)
{
return CreateLeafBinding(source, currentToken);
}
else
{
var remainingTokens = tokens.Skip(1).ToList();
return CreateChainedBinding(source, currentToken, remainingTokens);
}
}
private static MvxChainedSourceBinding CreateChainedBinding(object source, MvxPropertyToken propertyToken,
List<MvxPropertyToken> remainingTokens)
{
if (propertyToken is MvxIndexerPropertyToken)
{
return new MvxIndexerChainedSourceBinding(source, (MvxIndexerPropertyToken) propertyToken,
remainingTokens);
}
else if (propertyToken is MvxPropertyNamePropertyToken)
{
return new MvxSimpleChainedSourceBinding(source, (MvxPropertyNamePropertyToken) propertyToken,
remainingTokens);
}
throw new MvxException("Unexpected property chaining - seen token type {0}",
propertyToken.GetType().FullName);
}
private static IMvxSourceBinding CreateLeafBinding(object source, MvxPropertyToken propertyToken)
{
if (propertyToken is MvxIndexerPropertyToken)
{
return new MvxIndexerLeafPropertyInfoSourceBinding(source, (MvxIndexerPropertyToken) propertyToken);
}
else if (propertyToken is MvxPropertyNamePropertyToken)
{
//**************************
// Special code is here
var propertyToken = (MvxPropertyNamePropertyToken) propertyToken;
if (source != null)
{
var method = source.GetType().GetMethod(propertyToken.PropertyName, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
if (method != null)
{
return new MyMethodSourceBinding(source, method);
}
}
return new MvxSimpleLeafPropertyInfoSourceBinding(source,
(MvxPropertyNamePropertyToken) propertyToken);
// Special code ends here
//**************************
}
else if (propertyToken is MvxEmptyPropertyToken)
{
return new MvxDirectToSourceBinding(source);
}
throw new MvxException("Unexpected property source - seen token type {0}", propertyToken.GetType().FullName);
}
}
4. Supply this source binding factory in your own custom binding builder - e.g.:
public class MyAndroidBindingBuilder
: MvxAndroidBindingBuilder
{
protected override IMvxSourceBindingFactory CreateSourceBindingFactory()
{
return new MvxSourceBindingFactory();
}
}
5. Supply this binding builder during your setup
public class Setup : MvxAndroidSetup
{
// ....
protected override MvxAndroidBindingBuilder CreateBindingBuilder()
{
return new MyAndroidBindingBuilder();
}
}
Note: This approach is only for advanced users right now... As suggested in the first part of this question, I do expect the code in this area to change quite a lot so you might also encounter some issues maintaining a fork in this area. (Indeed the code in this area has already changed quite significantly on the Tibet Binding branch within the GitHub repo!)

app certification requirements when returning from tombstoning

I have a page where user can enter his name and attach an image.
When returning from tombstoning state, is it mandatory for my app to restore the image too?
Is it app certification requirement, something without which my app will not pass certification? Or is it a recommended pattern?
same question in the case when I have a pivot for example, is it mandatory to save the index of selected pivot item and restore the selection when activating from tombstoning?
Not necessary:
Is there a popular library \ framework to help me with tombstoning and serializing objects, images, etc?
According to the Technical certification requirements for Windows Phone , the only requirements are :
A Windows Phone app is deactivated when the user presses the Start button or if the device timeout causes the lock screen to engage. A Windows Phone app is also deactivated with it invokes a Launcher or Chooser API.
A Windows Phone OS 7.0 app is tombstoned (terminated) when it is deactivated. A Windows Phone OS 7.1 or higher app becomes Dormant when it is deactivated but can be terminated by the system when resource use policy causes it to tombstone.
When activated after termination, the app must meet the requirements in Section 5.2.1 – Launch time.
As the section 5.2.1 - "Launch time" only concerns startup performance and responsiveness, you don't have a certification requirement for your issue.
However, if the user enters data (attaches images, etc.) and let's say it answer a call, does some other stuff and get's back to the application and then the data he entered was lost... it surely won't appreciate it. That will look more like a defect/bug.
Concerning the serialization of your state, I recommend you to use binary serialization as the performance is at least 10x better than using Json, Xml or any other format.
Personally, I implement a custom interface, IBinarySerializable to my "state" related classes and use this BinaryWriter extensions class to help writing the serialization code:
using System.IO;
namespace MyCompany.Utilities
{
public interface IBinarySerializable
{
void Write(BinaryWriter writer);
void Read(BinaryReader reader);
}
}
using System;
using System.Collections.Generic;
using System.IO;
namespace MyCompany.Utilities
{
public static class BinaryWriterExtensions
{
public static void Write<T>(this BinaryWriter writer, T value) where T : IBinarySerializable
{
if (value == null)
{
writer.Write(false);
return;
}
writer.Write(true);
value.Write(writer);
}
public static T Read<T>(this BinaryReader reader) where T : IBinarySerializable, new()
{
if (reader.ReadBoolean())
{
T result = new T();
result.Read(reader);
return result;
}
return default(T);
}
public static void WriteList<T>(this BinaryWriter writer, IList<T> list) where T : IBinarySerializable
{
if (list == null)
{
writer.Write(false);
return;
}
writer.Write(true);
writer.Write(list.Count);
foreach (T item in list)
{
item.Write(writer);
}
}
public static List<T> ReadList<T>(this BinaryReader reader) where T : IBinarySerializable, new()
{
bool hasValue = reader.ReadBoolean();
if (hasValue)
{
int count = reader.ReadInt32();
List<T> list = new List<T>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
T item = new T();
item.Read(reader);
list.Add(item);
}
return list;
}
}
return null;
}
public static void WriteListOfString(this BinaryWriter writer, IList<string> list)
{
if (list == null)
{
writer.Write(false);
return;
}
writer.Write(true);
writer.Write(list.Count);
foreach (string item in list)
{
writer.WriteSafeString(item);
}
}
public static List<string> ReadListOfString(this BinaryReader reader)
{
bool hasValue = reader.ReadBoolean();
if (hasValue)
{
int count = reader.ReadInt32();
List<string> list = new List<string>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
list.Add(reader.ReadSafeString());
}
return list;
}
}
return null;
}
public static void WriteSafeString(this BinaryWriter writer, string value)
{
if (value == null)
{
writer.Write(false);
return;
}
writer.Write(true);
writer.Write(value);
}
public static string ReadSafeString(this BinaryReader reader)
{
bool hasValue = reader.ReadBoolean();
if (hasValue)
return reader.ReadString();
return null;
}
public static void WriteDateTime(this BinaryWriter writer, DateTime value)
{
writer.Write(value.Ticks);
}
public static DateTime ReadDateTime(this BinaryReader reader)
{
var int64 = reader.ReadInt64();
return new DateTime(int64);
}
}
}