How to make property editable in PropertyGrid? - windows-8

I'm developing a custom control for Windows Store App. This control has a property of type MyPoint:
public static readonly DependencyProperty CenterPointProperty = DependencyProperty.Register("CenterPoint",
typeof(MyPoint), typeof(MapControl), new PropertyMetadata(new GeoPoint(0, 0), CenterPointPropertyChanged));
public MyPoint CenterPoint {
get { return (MyPoint)GetValue(CenterPointProperty); }
set { SetValue(CenterPointProperty, value); }
}
MyPoint is a regular class, not DependecyObject descendant.
When user use my control in Visual Studio, user can't edit this property via PropertyGrid.
If MyPoint is DependencyObject there will be the "New..." button in the PropertyGrid. But I don't need DependencyObject descendant.
As I know, there is no TypeConverter or analogue is .Net for Windows Store Apps.
Is there some way to make this property editable?

Related

Looking for right way to implement multiple properties dependency for binding in Xamarin View

I'm new to Xamarin world, and its data binding rules. I have ViewModel with observable CurrentOrder property, and 3 properties which values depend on it. All 4 properties are used in View with bindings, so that each change in CurrentOrder should propagate changes to other 3 properties and that impact how view displays its controls and data. I'm confused with how I'm supposed to propagate the signal of CurrentOrder change to other 3 dependent properties. I came up with code that actually works, but to me it looks a bit awkward, and sets dependency inside independent property CurrentOrder, while I would prefer it to be other way around: dependent properties should better know what property they depend on.
Please note that SetProperty and OnPropertyChanged methods are in a base view model, and generated by standard VS Xamarin.Forms project pattern.
private int _currentOrder = 1;
public int CurrentOrder
{
get => _currentOrder;
set => SetProperty(ref _currentOrder, value, onChanged: () =>
{
OnPropertyChanged(nameof(CurrentItem));
OnPropertyChanged(nameof(IsTheLastItem));
OnPropertyChanged(nameof(IsTheFirstItem));
});
}
public string CurrentItem => Items[CurrentOrder - 1];
public bool IsTheLastItem => CurrentOrder == Items.Count;
public bool IsTheFirstItem => CurrentOrder == 1;
Any recommendations over best practices here are very appreciated
I would use Fody propertychanged for dependent properties like this.
Just add the nuget and dont forget to add FodyWeavers.xml, your class will be like below
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int CurrentOrder {get; set;}
public string CurrentItem => Items[CurrentOrder - 1];
public bool IsTheLastItem => CurrentOrder == Items.Count;
public bool IsTheFirstItem => CurrentOrder == 1;
}

Bind to an Item of a Dependency Collection

I'm trying to create a custom control that has a header and a footer and body. The idea is that the body of the report is a custom stack panel control that will allow the user to indicate page orientation and grouping. I created a dependency property on the custom UC to accept an IList of the custom stack panel. What I am trying to do is bind to one of the stack panels in the list. But for some reason the binding is not working.
The ReportPage:
public class ReportPage : StackPanel
{
//Nothing right now but will eventually include controls for page orientation and size (8.5x11, 11x17, etc.)
}
The UserControl code behind:
public partial class Report : UserControl, INotifyPropertyChanged
{
public Report()
{
ReportPages = new List<ReportPage>();
}
public static readonly DependencyProperty =
DependencyProperty.Register("ReportPages", typeof(IList), typeof(Report));
public IList ReportPages
{
get => (IList)GetValue(ReportPagesProperty);
set
{
SetValue(ReportPagesProperty, value);
ActivePage = value[0];
OnPropertyChanged(nameof(ActivePage));
}
}
private ReportPage _activePage;
public ReportPage ActivePage
{
get => _activePage;
set
{
_activePage = value;
OnPropertyChanged(nameof(ActivePage));
}
{
}
The UserControl xaml:
<Grid>
<!--Some xaml for the header and footer.-->
<ContentControl Content="{Binding ActivePage, RelativeSource={RelativeSource, FindAncestor, AncestorType=local:Report}}"/>
</Grid>
Here is how I am consuming the custom control. This should, in my mind at least, make three "pages" which I can toggle between using a button control that I didn't share.
<reportEngine:Report>
<reportEngine:Report.ReportPages>
<reportEngine:ReportPage>
<TextBlock>This is Page 1</TextBlock>
</reportEngine:ReportPage>
<reportEngine:ReportPage>
<TextBlock>This is Page 2</TextBlock>
</reportEngine:ReportPage>
<reportEngine:ReportPage>
<TextBlock>This is Page 3</TextBlock>
</reportEngine:ReportPage>
</reportEngine:Report.ReportPages>
</reportEngine:Report>
Any Ideas why the binding isn't working?
So I at least found a quick work around. I utilized the Collection Changed Event handler pattern from this answer and modified it for static dependency properties. Then, to get the values from the collection bound to the dependency property I create a static instance of the Report object in the constructor and use that to pass various values back to the object from the collection. Something like this:
public partial class Report : UserControl, INotifyPropertyChanged
{
private static Report _thisReport;
public Report()
{
InitializeComponent();
ReportPages = new ObservableCollection<ReportPage>();
_thisReport = this;
}
public static readonly DependencyProperty ReportPagesProperty =
DependencyProperty.Register("ReportPages", typeof(IList), typeof(Report), new FrameworkPropertyMetadata(ReportPagesChanged));
public IList ReportPages
{
get => (IList)GetValue(ReportPagesProperty);
set
{
SetValue(ReportPagesProperty, value);
//Update some other properties associated with the control (Total Page Numbers, etc.)
}
}
private static void ReportPagesChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
{
var newColl = (INotifyCollectionChanged)eventArgs.NewValue;
if (newColl != null)
newColl.CollectionChanged += ReportPages_CollectionChanged;
var oldColl = (INotifyCollectionChanged)eventArgs.OldValue;
if (oldColl != null)
oldColl.CollectionChanged -= ReportPages_CollectionChanged;
}
private static void ReportPages_CollectionChanged(object sender, NotifyCollectionChangedEventArgs eventArgs)
{
var newPages = (IList<ReportPage>) sender;
//Updates properties of the Report control.
_thisReport.ActivePage = newPages[0];
_thisReport.TotalPageNumber = newPages.Count;
}
}
Whether this is "correct" or not I couldn't say, but it works. If someone has a better answer I will change the answer.

Bing Map polyline using MVVM pattern XAML

I am working on widows phone 8.1 map based application.I want to know how can I draw a map polyline using MVVM pattern. I've already achieved this using the code behind for first creating the polyline and then adding it. My question is can I define a polyline in the XAML itself and give it a source binding to one of my observable collections of type BasicGeopositions in my viewmodel. If yes then how?
Data to be plotted using polyline:
is a list of BasicGeoposition that contains latitudes and longitudes of all the points I need to connect. I tried this way <Maps:MapPolyline Path="{Binding Trip.PTSPositions}"/> but it didn't work. PTSPositions is a list of BasicGeoposition.
What i want to perform:
I want to
MapPolyline polyLine = new MapPolyline() { StrokeColor = Colors.Blue, StrokeThickness = 5 };
polyLine.Path = new Geopath(Trip.PTSPositions);
MyMap.MapElements.Add(polyLine);
perform the above code behind code in XAML using MVVM where the Trip.PTSPositions would be fetched dynamically and the map polyline would be drawn using data binding.
I searched online a lot. I couldn't find anything that does not use code behind for polyline
Here is the implementation suggested up in the comments.
This is the attached bindable property implementation for MapControl and it stays in the Widows Phone 8.1 project:
public class Polyline
{
public static readonly DependencyProperty PathProperty =
DependencyProperty.RegisterAttached(
"Path",
typeof(IBasicGeoposition[]),
typeof(Polyline),
new PropertyMetadata(null, OnPathChanged));
public static void SetPath(UIElement element, IBasicGeoposition[] value)
{
element.SetValue(PathProperty, value);
}
public static IBasicGeoposition[] GetPath(UIElement element)
{
return (IBasicGeoposition[]) element.GetValue(PathProperty);
}
private static void OnPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var mapControl = d as MapControl;
if (mapControl == null)
{
throw new InvalidOperationException(
"Polyline.Track property can only be attached to a MapControl!");
}
mapControl.MapElements.Clear();
mapControl.MapElements.Add(CreateMapPolyline(GetPath(mapControl)));
}
private static MapPolyline CreateMapPolyline(IEnumerable<IBasicGeoposition> track)
{
return new MapPolyline
{
Path = new Geopath(track.Select(x =>
new BasicGeoposition
{
Altitude = x.Altitude,
Latitude = x.Latitude,
Longitude = x.Longitude,
})),
StrokeColor = Colors.Red,
StrokeThickness = 3,
StrokeDashed = false
};
}
}
This interface stays in the PCL, probably close to it's implementation (you'll have to add your custom class implementing the interface):
public interface IBasicGeoposition
{
double Altitude { get; set; }
double Latitude { get; set; }
double Longitude { get; set; }
}
Than in view model you have Trip.PTSPositions which is an array of IBasicGeoposition. And in the view (XAML), you'll have:
<maps:MapControl attached:Polyline.Path="{Binding Trip.PTSPositions}"/>

Setter of BindableProperty of Integer never called from xaml (Xamarin.forms)

I'm making app with using Xamarin.forms.
I set BindableProperty of integer.
But it's setter never called and not even set from xaml.
<... SelectedIndex="{Binding myValue}">
Is there anything I did wrong?
Thanks.
public class CircleSegmentControl : StackLayout
{
public static readonly BindableProperty SegmentInitialIndexProperty = BindableProperty.Create("SelectedIndex", typeof(int), typeof(CircleSegmentControl), 0);
public int SelectedIndex {
set{
Debug.WriteLine("setter");
SetValue(SegmentInitialIndexProperty, value);
SelectIndex(value);
}
get{
Debug.WriteLine("getter");
return (int)GetValue(SegmentInitialIndexProperty);
}
}
...
}
Apparently the same applies as for WPF dependency properties. You must not call anything else than GetValue and SetValue in the get and set methods of the property wrapper:
public int SelectedIndex
{
get { return (int)GetValue(SelectedIndexProperty); }
set { SetValue(SelectedIndexProperty, value); }
}
To get notified about property value changes (to call your SelectIndex method), you should register a propertyChanged delegate with another overload of BindableProperty.Create.

GridView does not refresh changes to items when using LayoutAwarePage.DefaultViewModel

In a "Blank App" (Visual C#, Windows Store), I create a new "Grouped Items Page", then declare a MyItemViewModel class deriving from DependencyObject with a Dependency Property for a String Title.
This is the page's LoadState method:
protected async override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
this.DefaultViewModel["Groups"] = this.items;
this.items.Add(new MyItemViewModel { Title = "My Title" });
for (int i = 0; i < 5; i++)
{
await Task.Delay(1000);
this.items.First().Title += ".";
}
}
The expectation is that dots appear after the item's title every second. The actual output is simply "My Title" and nothing else happens.
By adding the following unreferenced dependency property the dots will then appear:
public MyItemViewModel blah
{
get { return (MyItemViewModel)GetValue(blahProperty); }
set { SetValue(blahProperty, value); }
}
public static readonly DependencyProperty blahProperty =
DependencyProperty.Register("blah", typeof(MyItemViewModel), typeof(GroupedItemsPage1), new PropertyMetadata(0));
Why does the GridView only refresh the Title property of the item view model when there is an unused dependency property with the same type?
Do view model classes always have to be explicitly declared as a dependency property somewhere in an app at least once?
DependencyObject is usually inherited by UIElement (e.g., Grid, TextBlock, etc.), and their properties are DependencyProperty which allows, for example, Binding.
A ViewModel should implement INotifyPropertyChanged instead of inherit from DependencyObject. If you look at sample templates like GridApp, you will see that BindableBase implements INotifyPropertyChanged.