Auto expand Property when changed PropertyGrid.PropertyValueChanged not works. (ExpandableObjectConverter classes) - c#

I need to expand a PropertyGrid SelectedItem at design-time when I choose a property value. I try create CollectionEditor descendant which access the property grid. and do following in overridden CreateCollectionForm()
protected override CollectionForm CreateCollectionForm()
{
var collectionForm = base.CreateCollectionForm();
collectionForm.Shown += (s, e) =>
{
var propertyGrid = collectionForm.Controls[0].Controls.OfType<PropertyGrid>().First();
propertyGrid.PropertyValueChanged += (ss, ee) =>
{
if (ee.ChangedItem.Expandable)
ee.ChangedItem.Expanded = true; // NOT WORKING.
};
};
return collectionForm;
}
Another guys asking something similar but not answered yet from long time ago. In my case I need expand selectedItem in winForms designer propertygrid.
Automatically expand some properties in PropertyGrid
I see he try cast context as GridItem. Which in my side crash visual studio.
Anyhelp will be appreciated.

To do that a CollectionEditor descendant is must provided as follows:
public class AdvancedCollectionEditor : System.ComponentModel.Design.CollectionEditor
{
protected internal string formCaption;
protected internal List<Type> excludedTypes = new List<Type>();
protected internal bool allowMultiSelect;
public AdvancedCollectionEditor(Type type) : base(type)
{
allowMultiSelect = true;
}
protected override Type[] CreateNewItemTypes()
{
if (CollectionItemType.IsAbstract)
{
List<Type> validTypes = new List<Type>();
var types = Assembly.GetAssembly(CollectionItemType).GetTypes();
foreach (var type in types)
{
if (!type.IsAbstract && type.IsSubclassOf(CollectionItemType))
{
if (!excludedTypes.Contains(type))
validTypes.Add(type);
}
}
return validTypes.ToArray();
}
return base.CreateNewItemTypes();
}
protected override CollectionForm CreateCollectionForm()
{
var collectionForm = base.CreateCollectionForm();
if (!string.IsNullOrWhiteSpace(formCaption))
collectionForm.Text = formCaption;
collectionForm.Size = new Size(640, 500);
collectionForm.Shown += (s, e) =>
{
var propertyGrid = collectionForm.Controls[0].Controls.OfType<PropertyGrid>().First();
propertyGrid.HelpVisible = true;
propertyGrid.PropertyValueChanged += (ss, ee) =>
{
// Note that ee.ChangedItem will never works
void ExpandChildGridItems(GridItem parent)
{
if (parent.Expandable)
parent.Expanded = true;
if (parent.GridItems.Count > 0)
{
foreach (GridItem child in parent.GridItems)
ExpandChildGridItems(child);
}
}
if (propertyGrid.SelectedGridItem.Expandable)
propertyGrid.SelectedGridItem.Expanded = true;
ExpandChildGridItems(propertyGrid.SelectedGridItem);
};
};
return collectionForm;
}
protected override bool CanSelectMultipleInstances() => allowMultiSelect;
}

Related

Entry not vertically centered in Xamarin Forms MacOS

Stumbled upon this bug https://github.com/xamarin/Xamarin.Forms/issues/10789 when trying to work with a centered entry.
Tried to solve it locally by doing a custom renderer but having some troubles along the way. This is what i currently have:
[assembly: Xamarin.Forms.ExportRenderer(typeof(Entry), typeof(CustomEntryRenderer))]
namespace Project.MacOS.Renderers
{
public class CustomEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
var element = e.NewElement as Entry;
if (Control != null && element != null)
{
Control.BackgroundColor = NSColor.Clear;
Control.Bordered = false;
var stringHeight = Control.AttributedStringValue.Size.Height;
var titleRect = Bounds;
var oldOriginY = this.Bounds.Y;
var res = titleRect.Y + (Bounds.Size.Height - stringHeight) / 2.0;
titleRect.Y = (System.nfloat)res;
var res2 = titleRect.Size.Height - (titleRect.Y - oldOriginY);
titleRect.Size.Height = res2;
}
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
}
}
}
So I followed this question:
Set text vertical center in NSTextField
But having a few issues. First issue is that I am unable to set the titleRect.Size.Height = res2;as it is complaining about "Cannot modify the return value of ´CGRECT.Size´ because it is not a variable. Second issue is how I assign these newly added values to the control itself so that i can test it and see if it worked.
First issue is that I am unable to set the titleRect.Size.Height = res2;as it is complaining about "Cannot modify the return value of ´CGRECT.Size´ because it is not a variable.
About this, that means you can not assign Height directly.
We need to set the total paramater of Size as follows:
titleRect = new CoreGraphics.CGRect(titleRect.X, titleRect.Y, titleRect.Width, res2 );
Second issue is how I assign these newly added values to the control itself so that i can test it and see if it worked.
From shared discussion, we also can custom a NSTextFieldCell and then set for NSTextField.
public class CustomEntryRenderer :EntryRenderer
{
public CustomEntryRenderer()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
var element = e.NewElement as Entry;
if (Control != null & element != null)
{
Control.BackgroundColor = NSColor.Clear;
VerticallyCenteredTextfieldCell verticallyCenteredTextfieldCell = new VerticallyCenteredTextfieldCell(Control);
Control.Cell = verticallyCenteredTextfieldCell;
Control.StringValue = element.Text;
Control.Bordered = true;
}
}
}
public class VerticallyCenteredTextfieldCell : NSTextFieldCell
{
private NSTextField control;
public VerticallyCenteredTextfieldCell(NSTextField control)
{
this.control = control;
}
public override CoreGraphics.CGRect TitleRectForBounds(CoreGraphics.CGRect theRect)
{
var stringheight = control.AttributedStringValue.Size.Height;
CoreGraphics.CGRect titleRect = base.TitleRectForBounds(theRect);
var oldOriginY = control.Frame.Y;
titleRect.Y = control.Frame.Y + (control.Frame.Size.Height - stringheight) / 2;
var height = titleRect.Size.Height - (titleRect.Y - oldOriginY);
titleRect = new CoreGraphics.CGRect(titleRect.X, titleRect.Y, titleRect.Width, height);
return titleRect;
}
public override void DrawInteriorWithFrame(CoreGraphics.CGRect cellFrame, NSView inView)
{
base.DrawInteriorWithFrame(TitleRectForBounds(cellFrame), inView);
}
}
The effect:

UWP drag and drop custom type/class

Hy there,
I'm trying to enable drag & drop between 2 GridViews, I managed to do it with the custom types of the "DataPackage" class (SetText, SetBitmap, etc..) but I can't figure out how to do this with a custom class/type.
Both GridViews are data-bound to the same custom class (only a couple of properties, int, string, bitmapimage), I simply would like to drag directly this data items from one GridView to the other.
Thank you very much for your help!
So to summarize for the benefit of others, I added these to event handlers to DataTemplate content, as I only wanted items of a certain (ViewModel) type to be draggable.
private void Grid_Drop(object sender, DragEventArgs e)
{
if (sender is FrameworkElement)
{
var fe = sender as FrameworkElement;
var targetIvm = fe.DataContext as ItemViewModel;
object obj = null;
if(e.DataView.Properties.TryGetValue("ItemViewModel", out obj))
{
var sourceIvm = obj as ItemViewModel;
vm.MoveItem(sourceIvm, targetIvm);
}
}
}
private void Grid_DragStarting(Windows.UI.Xaml.UIElement sender, DragStartingEventArgs args)
{
if (sender is FrameworkElement)
{
var fe = sender as FrameworkElement;
var item = new KeyValuePair<string, object>("ItemViewModel", fe.DataContext);
args.Data.RequestedOperation = DataPackageOperation.Move;
args.Data.Properties.Add("ItemViewModel", fe.DataContext);
}
}
I had the same issue please check this example I used Behaviors because I used MVVM pattern but I did this for ListView but is the same for GridView with small changes.
Change the Behaviors <ListView> to <GridView>
This behavior is attached in the ListView where you want drag the item
public class StartingDragBehavior:Behavior<ListView>
{
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.CanDragItems = true;
this.AssociatedObject.DragItemsStarting += AssociatedObject_DragItemsStarting;
}
private void AssociatedObject_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
{
e.Data.RequestedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Copy;
if(e.Items!=null && e.Items.Any())
{
e.Data.Properties.Add("item", e.Items.FirstOrDefault());
}
}
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.DragItemsStarting -= AssociatedObject_DragItemsStarting;
}
}
This behavior is attached in the ListView where you want to drop the item
Here another Behavior to catch the drop event.
public class EndDropBehavior : Behavior<ListView>
{
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.AllowDrop = true;
this.AssociatedObject.Drop += AssociatedObject_Drop;
this.AssociatedObject.DragOver += AssociatedObject_DragOver;
}
private void AssociatedObject_Drop(object sender, Windows.UI.Xaml.DragEventArgs e)
{
if (e.DataView != null &&
e.DataView.Properties != null &&
e.DataView.Properties.Any(x => x.Key == "item" && x.Value.GetType() == typeof(MyObject)))
{
try
{
var def = e.GetDeferral();
var item = e.Data.Properties.FirstOrDefault(x => x.Key == "item");
var card = item.Value as MyObject;
var list = sender as ListView;
var vm = list.DataContext as Infrastructure.ViewModels.CreditCardsViewModel;
vm.MyCollection.Add(card);
def.Complete();
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
else
{
e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.None;
}
}
private void AssociatedObject_DragOver(object sender, Windows.UI.Xaml.DragEventArgs e)
{
if (e.DataView != null &&
e.DataView.Properties != null &&
e.DataView.Properties.Any(x => x.Key == "item" && x.Value.GetType() == typeof(MyObject)))
{
e.AcceptedOperation = e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Copy;
}
else
{
e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.None;
}
}
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.Drop -= AssociatedObject_Drop;
this.AssociatedObject.DragOver -= AssociatedObject_DragOver;
}
}
If you are not using MVVM pattern just check the events of the to Behaviors.

ICollection filter error convert type

I have filter my collection
It is my code
public ICollectionView LogEntriesStoreView { get; set; }
var collection = new ObservableCollection<Service>(this._model.GetService());
this.LogEntriesStoreView = CollectionViewSource.GetDefaultView(collection);
this.LogEntriesStoreView.Filter += new FilterEventHandler(ShowOnlyBargainsFilter);
private void ShowOnlyBargainsFilter(object sender, FilterEventArgs e)
{
AuctionItem product = e.Item as AuctionItem;
if (product != null)
{
// Filter out products with price 25 or above
if (product.CurrentPrice < 25)
{
e.Accepted = true;
}
else
{
e.Accepted = false;
}
}
}
Now I get this error
Implicit type conversion "System.Windows.Data.Filter EventHandler" in "System.Predicate " can not be
this._view = new TViewType();
this._model = new ServiceModel();
this.Service = new ObservableCollection<Service>(this._model.GetService());
this.OkCommand = new RelayCommand(o => this.OKRun());
this.LostFocusCommand = new RelayCommand(o => this.LostFocusOKRun());
// в переменную получаем нашу коллекцию
var collection = new ObservableCollection<Service>(this._model.GetService());
// инициализируем поле типа ICollectionView нашей коллецией
this.LogEntriesStoreView = CollectionViewSource.GetDefaultView(collection);
this.LogEntriesStoreView.Filter = new Predicate<object>(Contains);
this.LogEntriesStoreView.Filter += new FilterEventHandler(ShowOnlyBargainsFilter);
this._view.SetDataContext(this);
this._view.ShowIView();
}
private void OKRun()
{
MessageBox.Show("One Click");
}
private void LostFocusOKRun()
{
MessageBox.Show("LostFocus");
}
private void TextChanged()
{
}
private void ShowOnlyBargainsFilter(object sender, FilterEventArgs e)
{
}
public bool Contains(object de)
{
return true;
}
full code, i added a predicate in me code. All made for example on msdn
EventHandler should work for CollectionViewSource LogEntriesStoreView.
There is a difference between implementation of Filter for CollectionView and CollectionViewSource.
https://msdn.microsoft.com/en-us/library/system.windows.data.collectionview.filter(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.windows.data.collectionviewsource.filter(v=vs.110).aspx

How to create user control for displaying collection of other user controls in WinForms?

I need to create a user control MyTypeListControl to display collection of objects of type MyType using a user controls MyTypeDisplayControl instance for each of those objects.
So that I could
add instance of MyTypeListControl to my WinForm, then
load collection of MyType and
assign it to MyTypeListControl's DataSource.
In the result it should generate and show appropriate count of MyTypeDisplayControl instances in MyTypeListControl's instance.
In case if I needed to show list of properties - equivalent would be DataGrid with specific fields from MyType assigned to specific DataGrid's columns, but I want to view each MyType item as a user control - with more power for visual representation and functionality than DataGrid provides for it's rows.
Is that even possible?
I found this SO resource how to create My collection type, but this is only small part of the problem solution...
It is quite easy (if you know how) and doesn't take so much effort as you might think in the first place (at least for a simple implementation that handles collection of less then 100 items).
So at first lets create a MyType:
public class MyType
{
public static MyType Empty = new MyType(String.Empty, DateTime.MinValue);
public MyType(string myName, DateTime myBirthday)
{
MyName = myName;
MyBirthday = myBirthday;
}
public DateTime MyBirthday { get; private set; }
public string MyName { get; private set; }
}
At next we need a MyTypeControl:
public partial class MyTypeControl : UserControl
{
private MyType _MyType;
private Label labelBirthday;
private Label labelName;
private Label labelSeparator;
public MyTypeControl()
{
InitializeComponent();
}
public event EventHandler MyTypeChanged;
public MyType MyType
{
get { return _MyType; }
set
{
if (_MyType == value)
return;
_MyType = value ?? MyType.Empty;
OnMyTypeChanged(EventArgs.Empty);
}
}
protected virtual void OnMyTypeChanged(EventArgs eventArgs)
{
UpdateVisualization();
RaiseEvent(MyTypeChanged, eventArgs);
}
protected void UpdateVisualization()
{
SuspendLayout();
labelName.Text = _MyType.MyName;
labelBirthday.Text = _MyType.MyBirthday.ToString("F");
labelBirthday.Visible = _MyType.MyBirthday != DateTime.MinValue;
ResumeLayout();
}
private void InitializeComponent()
{
labelName = new Label();
labelBirthday = new Label();
labelSeparator = new Label();
SuspendLayout();
labelName.Dock = DockStyle.Top;
labelName.Location = new Point(0, 0);
labelName.TextAlign = ContentAlignment.MiddleCenter;
labelBirthday.Dock = DockStyle.Top;
labelBirthday.TextAlign = ContentAlignment.MiddleCenter;
labelSeparator.BorderStyle = BorderStyle.Fixed3D;
labelSeparator.Dock = DockStyle.Top;
labelSeparator.Size = new Size(150, 2);
Controls.Add(labelSeparator);
Controls.Add(labelBirthday);
Controls.Add(labelName);
MinimumSize = new Size(0, 48);
Name = "MyTypeControl";
Size = new Size(150, 48);
ResumeLayout(false);
}
private void RaiseEvent(EventHandler eventHandler, EventArgs eventArgs)
{
var temp = eventHandler;
if (temp != null)
temp(this, eventArgs);
}
}
Then comes our magically list control:
public class MyTypeListControl : UserControl
{
private ObservableCollection<MyType> _Items;
public MyTypeListControl()
{
AutoScroll = true;
_Items = new ObservableCollection<MyType>();
_Items.CollectionChanged += OnItemsCollectionChanged;
}
public Collection<MyType> Items
{
get { return _Items; }
}
private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UpdateVisualization();
}
private void UpdateVisualization()
{
SuspendLayout();
Controls.Clear();
foreach (var item in _Items)
{
var control = new MyTypeControl { MyType = item, Dock = DockStyle.Top };
Controls.Add(control);
Controls.SetChildIndex(control, 0);
}
ResumeLayout();
}
}
And now simply create the list control in your form or parent control and fill it with some meaningful values:
myTypeListControl.Items.Add(new MyType("Adam", DateTime.UtcNow.Add(-TimeSpan.FromDays(365 * 40))));
myTypeListControl.Items.Add(new MyType("Eva", DateTime.UtcNow.Add(-TimeSpan.FromDays(365 * 38))));

Getting dynamically added child controls to display in the UI

I am trying to create a RadioButtonListWithOther class that extends the RadoButtonList but I can't get the "Other" textbox to render on the page. When I step through while debugging I can see the control in the parent control's Controls collectio but it still doesn't render. Any ideas what I am doing wrong here?
public class RadioButtonListWithOther : RadioButtonList
{
private TextBox _otherReason;
public RadioButtonListWithOther()
{
_otherReason = new TextBox();
_otherReason.TextMode = TextBoxMode.MultiLine;
_otherReason.Rows = 6;
_otherReason.Width = Unit.Pixel(300);
_otherReason.Visible = true;
}
protected override void CreateChildControls()
{
this.Controls.Add(_otherReason);
this.EnsureChildControls();
base.CreateChildControls();
}
protected override void OnSelectedIndexChanged(EventArgs e)
{
_otherReason.Enabled = false;
if (OtherSelected())
{
_otherReason.Enabled = true;
}
base.OnSelectedIndexChanged(e);
}
public override string Text
{
get
{
if (OtherSelected())
{
return _otherReason.Text;
}
return base.Text;
}
set
{
base.Text = value;
}
}
public override bool Visible
{
get
{
return base.Visible;
}
set
{
//Push visibility changes down to the children controls
foreach (Control control in this.Controls)
{
control.Visible = value;
}
base.Visible = value;
}
}
private bool OtherSelected()
{
if (this.SelectedItem.Text == "Other")
{
return true;
}
return false;
}
}
Here is my code to add an instance of this control to the WebForm:
protected override void CreateChildControls()
{
var whyMentorOptions = new Dictionary<string, string>();
whyMentorOptions.Add("Option 1", "1");
whyMentorOptions.Add("Option 2", "2");
whyMentorOptions.Add("Option 3", "3");
whyMentorOptions.Add("Other", "Other");
mentorWhy = new RadioButtonListWithOther
{
DataSource = whyMentorOptions
};
this.mentorWhy.DataTextField = "Key";
this.mentorWhy.DataValueField = "Value";
this.mentorWhy.DataBind();
Form.Controls.Add(mentorWhy);
base.CreateChildControls();
}
The RadioButtonList class completely ignores its child controls when rendering (it's only interested in the contents of its Items collection).
You'll have to render the text box yourself:
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
_otherReason.RenderControl(writer);
}

Categories