Should my custom popup window be a singleton? - c#

I have popup custom windows in my DLL used by 3-4 other DLLs. These windows popup in a modal manner.
Should my custom window be a singleton?
Should it be called as follows:
NeXusCustomWindowDlg.Instance.CustomWndDlg.Show("Recipe properties", ctl, 600, 600);
...
NeXusCustomWindowDlg.Instance.Close()
Relevant code:
public void Show(string title, object content, double width, double height)
{
Window newWindow = new Window
{
BorderBrush = Brushes.Blue,
BorderThickness = new Thickness(3),
Title = title,
Content = content,
WindowStyle = System.Windows.WindowStyle.ToolWindow,
WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen,
ResizeMode = System.Windows.ResizeMode.NoResize,
Width = width,
Height = height,
VerticalContentAlignment = VerticalAlignment.Stretch
};
//WindowStyle = System.Windows.WindowStyle.None,
OpenedWindow = newWindow;
newWindow.ShowDialog();
newWindow.Content = null;
}
public void Close()
{
if (OpenedWindow != null)
{
OpenedWindow.Close();
}
}
private Window OpenedWindow
{
get
{
lock (_syncObj)
{
return _openedWindow;
}
}
set
{
lock (_syncObj)
{
_openedWindow = value;
}
}
}

Related

Make a CustomListBox to add BorderColor then can't use ListBox normal properties/methods

I'm trying to change the border color of a ListBox.
I made this custom control where i have a function that makes the border by drawing.
After had it working, noticed that can't use ListBox.Items anymore, methods such as .Add() or .Clear().
Code of the Custom ListBox:
class CustomListBox : UserControl
{
//Fields
private Color borderColor = Color.MediumSlateBlue;
private int borderSize = 1;
//Items
private ListBox Listb;
//Properties
[Category("Custom")]
public Color BorderColor
{
get { return borderColor; }
set
{
borderColor = value;
}
}
[Category("Custom")]
public int BorderSize
{
get { return borderSize; }
set
{
borderSize = value;
this.Padding = new Padding(borderSize);//Border Size
AdjustListBoxDimensions();
}
}
public CustomListBox()
{
Listb = new ListBox();
this.SuspendLayout();
// ListBox
Listb.BorderStyle = BorderStyle.None;
Listb.DrawMode = DrawMode.OwnerDrawFixed;
Listb.ForeColor = Color.FromArgb(((int)(((byte)(249)))), ((int)(((byte)(249)))), ((int)(((byte)(249)))));
Listb.FormattingEnabled = true;
Listb.ItemHeight = 24;
Listb.Location = new Point(567, 64);
Listb.Name = "CustomListBox";
Listb.Size = new Size(235, 936);
Listb.DrawItem += new DrawItemEventHandler(Listb_DrawItem);
this.MinimumSize = new Size(200, 30);
this.Size = new Size(200, 30);
this.Padding = new Padding(borderSize);//Border Size
this.Font = new Font(this.Font.Name, 12F);
this.ResumeLayout();
AdjustListBoxDimensions();
}
// Highlight event
private void Listb_DrawItem(object sender, DrawItemEventArgs e)
{
Color backgroundColor = Color.FromArgb(50, 50, 50);
Color horizontalColor = Color.FromArgb(100, 100, 100);
if (e.Index >= 0)
{
SolidBrush sb = new SolidBrush(((e.State & DrawItemState.Selected) == DrawItemState.Selected) ? horizontalColor : backgroundColor);
e.Graphics.FillRectangle(sb, e.Bounds);
string text = Listb.Items[e.Index].ToString();
SolidBrush tb = new SolidBrush(e.ForeColor);
e.Graphics.DrawString(text, e.Font, tb, Listb.GetItemRectangle(e.Index).Location);
}
}
//Adjust Dimension (Still in test)
private void AdjustListBoxDimensions()
{
Listb.Location = new Point()
{
X = this.Width - this.Padding.Right - Listb.Width,
Y = Listb.Height
};
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics graph = e.Graphics;
//Draw border
using (Pen penBorder = new Pen(borderColor, borderSize))
{
penBorder.Alignment = PenAlignment.Inset;
graph.DrawRectangle(penBorder, 0, 0, this.Width - 0.5F, this.Height - 0.5F);
}
}
}
My problem is that i can't use the ListBox properties/methods, is there a way to inherit them?
Since you've made your own control, you have to make your own properties and methods, calling Listbox's methods and getters/setters
something like this:
public void Add(object item)
{
this.Listb.Items.Add(item);
}
public ObjectCollection ListItems
{
get
{
return this.Listb.Items;
}
set
{
this.Listb.Items.AddRange(value);
}
}
//etc...
public void Add(object item)
{
this.Listb.BeginUpdate();
this.Listb.Items.Add(item);
this.Listb.EndUpdate();
}
public void Clear()
{
this.Listb.BeginUpdate();
this.Listb.Items.Clear();
this.Listb.EndUpdate();
}
public int SelectedIndex()
{
return this.Listb.SelectedIndex;
}
public object Item(int index)
{
return this.Listb.Items[index];
}
Add to code:
Dock=Fill
This.control.add(listb)

Detect URL change with Xamarin.Forms Webview and Compare current URL to original URL

So I'm creating an app that uses Xamarin.Forms Webview. I'm trying to detect when the URL changes and if it does then compare the Original URL with the Current URL and then show or hide a button depending. The buttons purpose is to go back to the previous page and keep going until it reaches it's original destination. I only want this "go back" button to show when the user is not on the homescreen. Otherwise, always show.
I've tried everything with if(webview.cangoback...) but that doesn't detect the url change. I've tried setting a string that is equal to the original URL and using .Equals to compare the webview.source (which is where I'm currently at)
I just started looking into webviewNavigating but still nothing.
namespace Webview_Test
{
public partial class MainPage : ContentPage
{
public static string CurrentUrl { get; set; }
public MainPage()
{
InitializeComponent();
string CurrentUrl = "https://www.google.com/";
var _webView = new WebView()
{
Source = "https://www.google.com/",
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
};
Button BackButton = new Button
{
Text = "Go Back",
BackgroundColor = Color.FromHex("990000"),
TextColor = Color.White
};
BackButton.Clicked += OnBackButtonClicked;
void OnBackButtonClicked(object sender, EventArgs e)
{
_webView.GoBack();
}
Grid grid = new Grid
{
VerticalOptions = LayoutOptions.FillAndExpand,
RowDefinitions =
{
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = new GridLength(1, GridUnitType.Star) },
new RowDefinition { Height = new GridLength(50, GridUnitType.Absolute) },
new RowDefinition { Height = new GridLength(15, GridUnitType.Absolute) },
new RowDefinition { Height = new GridLength(15, GridUnitType.Absolute) },
new RowDefinition { Height = new GridLength(36, GridUnitType.Absolute) }
},
ColumnDefinitions =
{
new ColumnDefinition { Width = GridLength.Auto },
new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) },
new ColumnDefinition { Width = new GridLength(50, GridUnitType.Absolute) },
new ColumnDefinition { Width = new GridLength(50, GridUnitType.Absolute) },
new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) },
new ColumnDefinition { Width = GridLength.Auto }
}
};
grid.Children.Add(_webView, 0, 6, 0, 7);
if (_webView.Source.Equals(CurrentUrl))
{
grid.Children.Remove(BackButton);
}
else
{
grid.Children.Add(BackButton, 2, 4, 4, 6);
}
Content = grid;
}
}
}
My expected result is that on the homepage the button that says "go back" doesn't show. But on any page other than the homepage it should show the "go back" button. In logical terms it's if OriginalURL = CurrentURL don't show button. if OriginalURL != CurrentURL show button.
Have you tried Navigating event? i'll put some examples below.
public string OriginalURL = "https://www.stackoverflow.com"
private async void Webview_Navigating(object sender, WebNavigatingEventArgs e)
{
if(e.Url != OriginalURL)
{
//Write code, show the button or use if(webview.CanGoBack){//your code}
}
}
It might be late, but this helps, easy, quick, without any problem.
var url = await webView.EvaluateJavaScriptAsync("window.location.href");
I create custom renderer of webView on each platform to get the current url of webView, it's a little complex but it works finally.
In iOS part, override the LoadingFinished method to get the current url:
[assembly: ExportRenderer(typeof(MyWebView), typeof(MyWebViewRenderer))]
namespace App374.iOS
{
public class MyWebViewRenderer : WebViewRenderer,IUIWebViewDelegate
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{ // perform initial setup
UIWebView myWebView = (UIWebView)this.NativeView;
Delegate = new CustomWebViewDelegate(e.NewElement as WebView);
}
}
}
public class CustomWebViewDelegate : UIWebViewDelegate
{
Xamarin.Forms.WebView formsWebView;
public CustomWebViewDelegate(WebView webView)
{
formsWebView = webView;
}
public override void LoadingFinished(UIWebView webView)
{
var url = webView.Request.Url.AbsoluteUrl.ToString();
MainPage.CurrentUrl = webView.Request.Url.AbsoluteString;
MainPage.checkToShowButton();
}
}
}
In Android part, override the OnPageFinished method to get the current url:
[assembly: ExportRenderer (typeof (MyWebView), typeof (MyWebViewRenderer))]
namespace App374.Droid
{
public class MyWebViewRenderer : WebViewRenderer
{
public MyWebViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
// lets get a reference to the native control
var webView = (global::Android.Webkit.WebView)Control;
webView.SetWebViewClient(new MyWebViewClient());
webView.SetInitialScale(0);
webView.Settings.JavaScriptEnabled = true;
}
}
}
public class MyWebViewClient : WebViewClient
{
public override void OnPageFinished(Android.Webkit.WebView view, string url)
{
base.OnPageFinished(view, url);
MainPage.CurrentUrl = url;
MainPage.checkToShowButton();
}
}
}
And code behiend, check whether to show the go back button after every navigation:
public partial class MainPage : ContentPage
{
public static string CurrentUrl { get; set; }
public static MyWebView _webView;
public static Grid grid;
public static Button BackButton;
public MainPage()
{
InitializeComponent();
string CurrentUrl = "https://www.baidu.com/";
_webView = new MyWebView()
{
Source = CurrentUrl,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
};
BackButton = new Button
{
Text = "Go Back",
BackgroundColor = Color.FromHex("990000"),
TextColor = Color.White
};
grid = new Grid
{
//...
};
grid.Children.Add(_webView, 0, 6, 0, 7);
Content = grid;
checkToShowButton();
//Button click
BackButton.Clicked += OnBackButtonClicked;
void OnBackButtonClicked(object sender, EventArgs e)
{
_webView.GoBack();
checkToShowButton();
if (_webView.CanGoBack == false)
{
grid.Children.Remove(BackButton);
}
}
}
//Check whther to show goBack button
public static void checkToShowButton()
{
if ("https://www.baidu.com/".Equals(MainPage.CurrentUrl) || CurrentUrl == null || CurrentUrl == "")
{
grid.Children.Remove(BackButton);
}
else
{
if (grid != null)
{
grid.Children.Add(BackButton, 2, 4, 4, 6);
}
}
}
}
public class MyWebView : WebView { }
I uploaded my whole sample here and you can check it. Let me know if it works.
Note: I tested the _webView.Navigated and I found it only fires at the first time when loading the webView.
_webView.Navigated += (sender, e) => {
};
Refer : webview-check-when-website-address-changed

How to superimpose text on an image in a Xamarin Forms Button?

I was not able to find an easy way to create a Xamarin Forms button as an image with superimposed text on top. Curiously the Image property of Button only allows text next to the image.
So I'll share my code implementation here. It includes a facility to hide the keyboard when the button is tapped and supports text properties, image sizing and enablement. Grateful to #F. Badili, #Sharada Gururaj and others for assistance.
My implementation:
public class ImageButton : Grid
// A clickable visual element overlaying a label on an image, serving as a button
{
public event EventHandler Clicked;
public Image TheImage { get; set; }
public Label TheLabel { get; set; }
public bool HideKeyboard { get; set; }
public string Text
{
get
{
if ( TheLabel == null )
return null;
return TheLabel.Text;
}
set
{
if ( TheLabel == null )
return;
TheLabel.Text = value;
}
}
public Color TextColor
{
set
{
if ( TheLabel != null )
TheLabel.TextColor = value;
}
}
public string FontFamily
{
set
{
if ( TheLabel != null )
TheLabel.FontFamily = value;
}
}
public FontAttributes FontAttributes
{
set
{
if ( TheLabel != null )
TheLabel.FontAttributes = value;
}
}
public double FontSize
{
set
{
if ( TheLabel != null )
TheLabel.FontSize = value;
}
}
public double ImageHeightRequest
{
set
{
if ( TheImage != null )
TheImage.HeightRequest = value;
}
}
public double ImageWidthRequest
{
set
{
if ( TheImage != null )
TheImage.WidthRequest = value;
}
}
public ImageButton ( Image image, Label label, bool hideKeyboard = true )
{
TheImage = image;
TheLabel = label;
HideKeyboard = hideKeyboard;
Text = label.Text;
// Construct the control
ConstructControl ();
}
// Invoke the Clicked event; called when ImageButton is tapped
protected virtual void OnClicked ( EventArgs e )
{
if ( Clicked != null )
Clicked ( this, e );
}
private void ConstructControl ()
// Construct the control using a grid with a single cell
{
// Add action performed upon tap
this.AddTap ( () =>
{
// Hide keyboard
if ( HideKeyboard )
DependencyService.Get<IKeyboard> ().HideKeyboard ();
// Fire the event
OnClicked ( EventArgs.Empty );
});
// Bind opacity of image and label to IsEnabled via a converter
TheLabel.SetBinding ( OpacityProperty, new Binding ( "IsEnabled", converter: new BooleanToOpacityConverter (), source: this ) );
TheImage.SetBinding ( OpacityProperty, new Binding ( "IsEnabled", converter: new BooleanToOpacityConverter (), source: this ) );
// Stack image and label on top of each other in a grid with a single cell
this.RowDefinitions.Add ( new RowDefinition { Height = new GridLength ( 1, GridUnitType.Auto ) } );
this.ColumnDefinitions.Add ( new ColumnDefinition { Width = new GridLength ( 1, GridUnitType.Auto ) } );
this.Children.Add ( TheImage, 0, 0 ); // Add image first, so overlaid label will be visible
this.Children.Add ( TheLabel, 0, 0 );
}
public class BooleanToOpacityConverter : IValueConverter
{
public object Convert ( object value, Type targetType, object parameter, CultureInfo culture )
{
var isEnabled = ( value != null ) && (bool)value;
return isEnabled ? 1 : 0.5;
}
public object ConvertBack ( object value, Type targetType, object parameter, CultureInfo culture )
{
throw new NotImplementedException ();
}
}
}
public static class GridExtensions
{
// Grid extension methods
private static void AddTap ( this Grid grid, Action action )
// Allows Grid to be tappable
// action = method to call when Grid is tapped
// Example:
// Grid grid = new Grid ();
// grid.AddTap ( () => MyMethod () );
{
grid.GestureRecognizers.Add ( new TapGestureRecognizer
{
Command = new Command (action)
});
}
}
public interface IKeyboard
{
void HideKeyboard (); // Hide the keyboard
}
iOS:
[assembly: Xamarin.Forms.Dependency (typeof(Keyboard))]
namespace MyApp.iOS
{
public class Keyboard : MyApp.IKeyboard
{
public Keyboard () {}
public void HideKeyboard ()
// Hides the keyboard
{
UIApplication.SharedApplication.KeyWindow.EndEditing ( true );
}
}
}
Android (not tested yet):
[assembly: Xamarin.Forms.Dependency (typeof (Keyboard))]
namespace MyApp.Droid
{
public class Keyboard : MyApp.IKeyboard
{
public Keyboard () {}
public void HideKeyboard ()
// Hides the keyboard
{
var context = Forms.Context;
var inputMethodManager = context.GetSystemService ( Context.InputMethodService ) as InputMethodManager;
if ( inputMethodManager != null && context is Activity )
{
var activity = context as Activity;
var token = activity.CurrentFocus?.WindowToken;
inputMethodManager.HideSoftInputFromWindow ( token, HideSoftInputFlags.None );
activity.Window.DecorView.ClearFocus ();
}
}
}
}
Usage example:
public static ImageButton StandardImageButton ( string buttonText, EventHandler onClickedEventHandler = null, string imageResourceID = "MyApp.standardbutton.png", string imageSource = null,
Color textColour = default(Color), string fontFamily = null, double fontSize = 15D, FontAttributes fontAttributes = FontAttributes.Bold,
double heightRequest = 44D, double widthRequest = 200D, bool hideKeyboard = true )
// Returns tappable image serving as a button
// buttonText = text overlaid onbutton
// Image is sourced from embedded PCL file (Build Action = Embedded Resource) OR, if imageSourceID is non-null, from local platform file in platform-specific location
{
// Background image
Image image = new Image
{
Aspect = Aspect.Fill, // Stretch to fill
HeightRequest = heightRequest,
WidthRequest = widthRequest,
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.CenterAndExpand
};
if ( imageResourceID == null )
image.Source = ImageSource.FromFile ( imageSource );
else
image.Source = ImageSource.FromResource ( imageResourceID );
// Foreground label
Color colour;
if ( textColour == default(Color) )
colour = Color.Black;
else
colour = textColour;
Label label = new Label
{
Text = buttonText,
TextColor = colour,
FontFamily = fontFamily,
FontSize = fontSize,
FontAttributes = fontAttributes,
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center
};
ImageButton ret = new ImageButton ( image, label, hideKeyboard );
ret.Clicked += onClickedEventHandler;
return ret;
}
If you assign btn1.Image in code or xaml you could do this
btn1.ContentLayout = new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Bottom, 10);
That will give you a button with image at the bottom and text on top

Draw rectangle with text inside

I want to make an application in which the user could add rectangle with customizable text inside it. The rectangle also can have another rectangles inside. Just as you can see on these picture:
I read about DrawingVisual, Shapes etc. So far I did it using DrawingVisual + Host, which derivies from FrameworkElement. DrawingVisual has FormattedText field, and list of Children elements; Host maintain drawing all elements.
The main problem is that, everytime user changes text in any child element I need to calculate new coordinates, width, height of all child elements. Maybe there is any method to do that automatically?
Also, DrawingVisual doesn't have any mouse events. So how to make all elements selectable / hoverable? Or should I derive from some other class?
Later I will post some code...
EDIT:
public class VisualHost: FrameworkElement
{
private VisualCollection _children;
private List<MyElement> _list;
public VisualHost(List<MyElement> list)
{
_children = new VisualCollection(this);
_list = list;
}
protected override int VisualChildrenCount
{
get { return _children.Count; }
}
protected override Visual GetVisualChild(int index)
{
if (index < 0 || index >= _children.Count)
{
throw new ArgumentOutOfRangeException();
}
return _children[index];
}
private void CheckSize(MyElement element)
{
double sw = 0;
double mh = 0;
if (element.GetChildCount() > 0)
{
for (int i = 0; i < element.GetChildCount(); i++)
{
CheckSize(element.GetChild(i));
sw += element.GetChild(i).Width;
mh = Math.Max(mh, element.GetChild(i).Height);
}
}
element.Width = Math.Max(element.Formatted.Width, sw);
element.Height = element.Formatted.Height + mh;
}
private void DrawElement(double top, double left, MyElement element)
{
CheckSize(element);
var context = element.RenderOpen();
context.DrawRectangle( null, new Pen(Brushes.Black, 2d), new Rect(new Point(left, top), new Size(element.Width, element.Height)));
context.DrawText(element.Formatted, new Point(left, top));
top += element.Formatted.Height;
if (element.GetChildCount() > 0)
{
for (int i = 0; i < element.GetChildCount(); i++)
{
context.DrawRectangle(null, new Pen(Brushes.Black, 2d), new Rect(new Point(left, top), new Size(element.GetChild(i).Width, element.GetChild(i).Height)));
context.DrawText(element.GetChild(i).Formatted, new Point(left, top));
left += element.GetChild(i).Width;
}
}
context.Close();
_children.Add(element);
}
public void Redraw()
{
if (_list != null)
{
double top = 0, left = 0;
foreach (MyElement element in _list)
{
DrawElement(top, left, element);
top += element.Height + 10d;
}
}
}
}
public class MyElement: DrawingVisual
{
private string _text;
public string Text
{
get { return _text; }
set {
if (_text != value)
{
Typeface typeface = new Typeface(new FontFamily("Arial"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
Formatted = new FormattedText(value, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, 12, Brushes.Red);
_text = value;
}
}
}
public FormattedText Formatted { get; private set; }
public double Height { get; set; }
public double Width { get; set; }
private List<MyElement> _children;
public MyElement GetChild(int i)
{
if (i < 0 || i >= _children.Count)
{
throw new ArgumentOutOfRangeException();
}
return _children[i];
}
public int GetChildCount()
{
return _children.Count;
}
public void AddChild(MyElement child)
{
_children.Add(child);
}
public MyElement(string Text)
{
this.Text = Text;
this._children = new List<MyElement>();
}
}
MainWindow.xaml.cs
public MainWindow()
{
InitializeComponent();
_list = new List<MyElement>();
_list.Add(new MyElement("text"));
var e = new MyElement("text 2");
e.AddChild(new MyElement("a"));
e.AddChild(new MyElement("b"));
e.AddChild(new MyElement("c"));
_list.Add(e);
_host = new VisualHost(_list);
MyCanvas.Children.Add(_host);
_host.Redraw();
}
This is my code for now. I wrote it only to check if idea is correct.
well I'm not sure if you would like this approach but you can actually do it very simple... I'm thinking maybe you can use blend to create a user control and design a label and a listbox in a stackpanel and set 'em all on autosizing.
or design 2 stack panels set 1 to do vertical orientation and the other one to do horizontal and add textblocks or something to the horizontal one.

Gtk Expander in a scrolled window: The width of the scrolledwindow doesn't update

When using a Gtk ScrolledWindow with the horizontal Policy Never, I expect the scrolledwindow to adapt, if the horizontal size request of the child changes.
But that's not the case, for example when using an Expander: When I expand the expander, and the child is wider that the scrolled window, the scrolled window doesn't adapt it's size.
Minimum Example:
using System;
using Gtk;
namespace ExpanderIssue
{
class MainClass
{
static bool useExpander = true;
private static Widget createScrolledWindow(Widget child)
{
ScrolledWindow scrolledWindow = new ScrolledWindow();
scrolledWindow.SetPolicy(PolicyType.Never, PolicyType.Automatic);
scrolledWindow.AddWithViewport(child);
return scrolledWindow;
}
private static Widget createSingleExpaner(int index)
{
Button button = new Button(String.Format("ExampleButton {0}", index));
button.WidthRequest = 800;
if(useExpander) {
Expander expander = new Expander(String.Format("Expander {0}", index));
expander.Add(button);
return expander;
} else {
return button;
}
}
public static void Main(string[] args)
{
Application.Init();
createMainWindow();
Application.Run();
}
private static Window createMainWindow()
{
VBox vbox = new VBox();
vbox.Spacing = 4;
for(int i=0; i<32; ++i)
vbox.PackStart(createSingleExpaner(i), false, false, 0);
Window mainWindow = new Window("Expander Width Request issue");
mainWindow.SetDefaultSize(240, 160);
mainWindow.Add(createScrolledWindow(vbox));
mainWindow.ShowAll();
mainWindow.Destroyed += (sender, e) => Application.Quit();
return mainWindow;
}
}
}
Try to create the viewport for your scrollbar manually and adjust the Width Request from viewport when the SizeRequested Event from child is sent.
For your minimal example it should look like this:
using System;
using Gtk;
namespace ExpanderIssue
{
class MainClass
{
static bool useExpander = true;
private static Widget createScrolledWindow(Widget child)
{
ScrolledWindow scrolledWindow = new ScrolledWindow();
scrolledWindow.SetPolicy(PolicyType.Never, PolicyType.Automatic);
scrolledWindow.Add(doWorkaround(child));
return scrolledWindow;
}
private static Viewport doWorkaround(Widget child)
{
Viewport viewport = new Viewport();
viewport.Add(child);
child.SizeRequested += (o, args) =>
{
viewport.WidthRequest = viewport.Child.Requisition.Width;
};
return viewport;
}
private static Widget createSingleExpaner(int index)
{
Button button = new Button(String.Format("ExampleButton {0}", index));
button.WidthRequest = 800;
if(useExpander) {
Expander expander = new Expander(String.Format("Expander {0}", index));
expander.Add(button);
return expander;
} else {
return button;
}
}
public static void Main(string[] args)
{
Application.Init();
createMainWindow();
Application.Run();
}
private static Window createMainWindow()
{
VBox vbox = new VBox();
vbox.Spacing = 4;
for(int i=0; i<32; ++i)
vbox.PackStart(createSingleExpaner(i), false, false, 0);
Window mainWindow = new Window("Expander Width Request issue");
mainWindow.SetDefaultSize(240, 160);
mainWindow.Add(createScrolledWindow(vbox));
mainWindow.ShowAll();
mainWindow.Destroyed += (sender, e) => Application.Quit();
return mainWindow;
}
}
}

Categories