Autor |
Beitrag |
Kasko
Beiträge: 126
Erhaltene Danke: 1
Win 10
C# C++ (VS 2017/19), (Java, PHP)
|
Verfasst: Di 28.07.20 15:37
Ich möchte eine einfache FileExplorer-Control für einen Videoplayer erstellen.
Hier ist der Code:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| namespace CustomControls { public interface IScrollable { float visiblePercent { get; set; } float ScrollSpeedMultiplier { get; set; } int scrollValue { get; set; }
CustomScrollBar scrollBar { get; set; } } } |
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131:
| namespace CustomControls { public partial class ScrollablePanel : UserControl, IScrollable { private int _scrollValue; private int _totalWheelDelta;
private int totalWheelDelta { get => _totalWheelDelta; set { SetTotalDelta(value); } }
public int Count => panelInner.Controls.Count;
public bool VisibleControls => panelInner.Controls.OfType<Panel>().All(p => p.Visible);
public float visiblePercent { get; set; }
public int scrollValue { get { return _scrollValue; } set { _scrollValue = value; if (scrollBar != null && scrollBar.value != _scrollValue) scrollBar.value = _scrollValue; SetTotalDeltaByScrollValue(value); ScrollThrough(); } }
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(0), Category("Behavior"), Description("Die dazugehörige Scrollbar")] public CustomScrollBar scrollBar { get; set; }
public float ScrollSpeedMultiplier { get; set; }
public ScrollablePanel() { InitializeComponent(); panelInner.MouseWheel += panelInner_MouseWheel; }
protected override ControlCollection CreateControlsInstance() { return new ScrollablePanelElementCollection(this, this.panelInner); }
private void ScrollablePanel_Load(object sender, EventArgs e) { OnControlsChanged(); }
private void panelInner_MouseWheel(object sender, MouseEventArgs e) { if (visiblePercent >= 1.0f) return;
totalWheelDelta += (int)(e.Delta * ScrollSpeedMultiplier);
scrollValue = (100 * SystemInformation.MouseWheelScrollLines * totalWheelDelta) / ((Height - panelInner.Height) * SystemData.scrollDeltaModifier);
if (scrollBar != null) scrollValue = scrollBar.value = (100 * SystemInformation.MouseWheelScrollLines * totalWheelDelta) / ((Height - panelInner.Height) * SystemData.scrollDeltaModifier); }
private void ScrollThrough() { panelInner.Location = new Point(0, (int)((Height - panelInner.Height) * (scrollValue / 100.0f))); }
private void panelInner_ControlAdded(object sender, ControlEventArgs e) { OnControlsChanged(); }
private void panelInner_ControlRemoved(object sender, ControlEventArgs e) { OnControlsChanged(); }
private void OnControlsChanged() { int height = int.MinValue;
foreach (Control control in panelInner.Controls) if (control.Visible) height = Math.Max(height, control.Bottom);
panelInner.Height = height;
ScrollablePanel_Resize(this, new EventArgs());
if (panelInner.Height > 0) visiblePercent = (float)Height / panelInner.Height; else visiblePercent = 1.0f;
if (scrollBar != null) scrollBar.largeChange = (int)(visiblePercent * 100); }
private void ScrollablePanel_Resize(object sender, EventArgs e) { panelInner.Width = Width; }
private void SetTotalDelta(int value) { int lines = SystemInformation.MouseWheelScrollLines * (value / SystemData.scrollDeltaModifier); int deltaHeight = Height - panelInner.Height;
if (lines > 0) _totalWheelDelta = 0; else if (lines < deltaHeight) _totalWheelDelta = (deltaHeight * SystemData.scrollDeltaModifier) / SystemInformation.MouseWheelScrollLines; else _totalWheelDelta = value; }
private void SetTotalDeltaByScrollValue(int value) { int deltaHeight = Height - panelInner.Height;
totalWheelDelta = (deltaHeight * SystemData.scrollDeltaModifier * scrollValue) / (100 * SystemInformation.MouseWheelScrollLines); }
public void Clear() { panelInner.Controls.Clear(); } }
public class ScrollablePanelElementCollection : Control.ControlCollection { private Control container;
public ScrollablePanelElementCollection(Control owner, Panel container) : base(owner) { this.container = container; }
public override void Add(Control value) { if (this.Count == 0) base.Add(value); else container.Controls.Add(value); } } } |
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141:
| namespace MagererPlayer { public partial class FileExplorer : UserControl, IScrollable { private string _directory;
public float visiblePercent { get => scrollablePanel.visiblePercent; set => scrollablePanel.visiblePercent = value; } public int scrollValue { get => scrollablePanel.scrollValue; set => scrollablePanel.scrollValue = value; } public CustomScrollBar scrollBar { get => scrollablePanel.scrollBar; set => scrollablePanel.scrollBar = value; }
public string Directory { get => this._directory; set { if (System.IO.Directory.Exists(value)) { this._directory = value; GetDirectory(); this.textBoxUrl.Text = this._directory; } } }
public float ScrollSpeedMultiplier { get; set; }
public EventHandler OnDirectoryChanged = null; public EventHandler<FileSelectedEventArgs> OnFileSelected = null;
public FileExplorer() { InitializeComponent(); }
private void FileExplorer_Load(object sender, EventArgs e) { AdjustSize(); }
private void FileExplorer_Resize(object sender, EventArgs e) { AdjustSize(); }
private void AdjustSize() {
}
private void GetDirectory() { scrollablePanel.Clear(); System.Diagnostics.Trace.WriteLine(this.Directory);
int offset = System.IO.Directory.GetParent(this.Directory) != null ? 1 : 0;
int colCount = scrollablePanel.Width / 145; string[] dirs = System.IO.Directory.GetDirectories(new string(this.Directory.Where(c => !char.IsControl(c)).ToArray())); Array.Sort(dirs);
if (offset == 1) { DirectoryInfo parent = System.IO.Directory.GetParent(this.Directory); scrollablePanel.Controls.Add(GetExplorerItem(parent.FullName, "..", new Point(0, 0))); }
for (int i = 0; i < dirs.Length; i++) scrollablePanel.Controls.Add(GetExplorerItem(dirs[i], new DirectoryInfo(dirs[i]).Name, new Point(((i + offset) % colCount) * 145, (i + offset) / colCount * 115 + 10)));
offset += dirs.Length;
dirs = System.IO.Directory.GetFiles(new string(this.Directory.Where(c => !char.IsControl(c)).ToArray()), "*.mp4", SearchOption.TopDirectoryOnly); Array.Sort(dirs);
for (int i = 0; i < dirs.Length; i++) scrollablePanel.Controls.Add(GetExplorerItem(dirs[i], new FileInfo(dirs[i]).Name, new Point(((i + offset) % colCount) * 145, (i + offset) / colCount * 115 + 10)));
System.Diagnostics.Trace.WriteLine(scrollablePanel.Count); System.Diagnostics.Trace.WriteLine(scrollablePanel.VisibleControls); this.Invalidate(); }
private Panel GetExplorerItem(string path, string text, Point location) { BunifuImageButton bunifuImageButton = new BunifuImageButton(); Label label = new Label(); Panel panel = new Panel();
if (System.IO.Directory.Exists(path)) { bunifuImageButton.Image = Properties.Resources.folder; bunifuImageButton.Click += delegate (object sender, EventArgs e) { this.Directory = path; }; } else if (System.IO.File.Exists(path)) { bunifuImageButton.Image = Properties.Resources.video_1; } bunifuImageButton.ImageActive = null; bunifuImageButton.Location = new System.Drawing.Point(10, 0); bunifuImageButton.Name = "bunifuImageButton"; bunifuImageButton.Size = new System.Drawing.Size(125, 70); bunifuImageButton.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; bunifuImageButton.TabStop = false; bunifuImageButton.Zoom = 5; bunifuImageButton.Cursor = Cursors.Hand;
label.Font = new System.Drawing.Font("Century Gothic", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0); label.ForeColor = System.Drawing.Color.FromArgb(224, 224, 224); label.Name = "label"; label.Dock = DockStyle.Bottom; label.Size = new Size(145, 40); label.Text = text; label.TextAlign = ContentAlignment.MiddleCenter; label.AutoEllipsis = true;
panel.Controls.Add(bunifuImageButton); panel.Controls.Add(label); panel.Location = location; panel.Name = "panel"; panel.Size = new System.Drawing.Size(145, 110);
return panel; }
private void textBoxUrl_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) this.Directory = this.textBoxUrl.Text; } }
public class FileSelectedEventArgs : EventArgs { public FileInfo File { get; }
public FileSelectedEventArgs(string path) { File = new FileInfo(path); }
public FileSelectedEventArgs(FileInfo info) { File = info; } } } |
Das ScrollablePanel enthält ein innerPanel, das nach oben und unten verschoben wird. Der FileExplorer enthält eine TextView für die URL, einen Button und ein ScrollablePanel.
Mein Problem ist, dass beim Ausführen der Anwendung alles einwandfrei funktioniert. Wenn ich zum übergeordneten Ordner gehe (WICHTIG, KEINE SUBDIR) und dann erneut den Ordner öffne, sind alle Steuerelemente, die vorhanden sein sollten, unsichtbar, wurden jedoch der ControlCollection des innerPanels hinzugefügt.
Dies ist das einzige Ordnerverzeichnis, in dem dieser Fehler auftritt: D:\Serien\Anime\Yu-Gi-Oh! Zexal
Ausgabe von System.Diagnostics aus FileExplorer.GetDirectory:
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| D:\Serien\Anime\Yu-Gi-Oh! Zexal 3 True D:\Serien\Anime 47 True D:\Serien\Anime\Yu-Gi-Oh! Zexal 3 True |
Screenshot bei Programmstart: ibb.co/2g2Fk1G
Screenshot nach erneut öffnen: ibb.co/J7zKp36
Moderiert von Th69: Code-Tags hinzugefügt
Moderiert von Th69: Titel geändert (war "Winforms: Controls not visible after added programmatically").
|
|
Th69
Beiträge: 4785
Erhaltene Danke: 1055
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Di 28.07.20 17:26
Hast du dir die relevanten Werte (Location, Visible) mal im Debugger angeschaut?
Durchläuft der Code auch beim 2. Mal den Code mit denselben Werten?
PS: Du solltest deinen Code mal aufräumen (der ist ziemlich unleserlich), z.B. überflüssige Namensbereiche entfernen (und stattdessen [tt]using[/tt]-Deklaration benutzen), Eigenschaften sollten mit einem Großbuchstaben beginnen, ...
|
|
Kasko
Beiträge: 126
Erhaltene Danke: 1
Win 10
C# C++ (VS 2017/19), (Java, PHP)
|
Verfasst: Di 28.07.20 17:34
Es sind immer die richtigen und die gleichen Werte.
Zum PS. Die Code-Schnipsel sind aus verschiedenen Projekten. CustomControls und MagererPlayer. CustomControls habe ich erstellt falls ich eigene Controls erstelle die halbwegs generisch nutzbar sind. Vllt kommt der FileExplorer auch eines Tages dort rein. ScrollablePanel ist schon uralt und wurde als eine der ersten Controls hinzugefügt. DAMALS habe ich mich nicht sonderlich um Namenskonventionen gekümmert. Deshalb sind unter anderem manche Properties klein geschrieben
|
|
Kasko
Beiträge: 126
Erhaltene Danke: 1
Win 10
C# C++ (VS 2017/19), (Java, PHP)
|
Verfasst: Di 28.07.20 23:42
Okay falsch. Nicht alle Werte sind gleich. Tatsächlich gibt die Visible-Property bei Programmstart false zurück, obwohl bei diesem Versuch die Controls ja sichtbar sind. Nach dem erneuten öffnen gibt sie dann true zurück, aber dann sind sie nicht sichtbar. Beim öffnen des übergeordneten Ordners gibt sie auch true zurück, da ist aber alles sichtbar.
Output: (Ohne den übergeordneten weil sonst zu viel)
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| Url: D:\Serien\Anime\Yu-Gi-Oh! Zexal Location: {X=0,Y=10} Bounds: {X=0,Y=10,Width=145,Height=110} Size: {Width=145, Height=110} Visible: False
Location: {X=145,Y=10} Bounds: {X=145,Y=10,Width=145,Height=110} Size: {Width=145, Height=110} Visible: False
Location: {X=290,Y=10} Bounds: {X=290,Y=10,Width=145,Height=110} Size: {Width=145, Height=110} Visible: False CollectionCount: 3
Url: D:\Serien\Anime\Yu-Gi-Oh! Zexal Location: {X=0,Y=10} Bounds: {X=0,Y=10,Width=145,Height=110} Size: {Width=145, Height=110} Visible: True
Location: {X=145,Y=10} Bounds: {X=145,Y=10,Width=145,Height=110} Size: {Width=145, Height=110} Visible: True
Location: {X=290,Y=10} Bounds: {X=290,Y=10,Width=145,Height=110} Size: {Width=145, Height=110} Visible: True CollectionCount: 3 |
|
|
Kasko
Beiträge: 126
Erhaltene Danke: 1
Win 10
C# C++ (VS 2017/19), (Java, PHP)
|
Verfasst: Mi 29.07.20 02:40
Okay Fehler gefunden.
Wenn ich den Ordner Ausgewählt habe, musste ich immer nach unten scrollen. Dadurch wurde das innerPanel nach oben geschoben (erste Zeile wurde abgeschnitten/verdeckt) nach dem löschen habe ich das panel nicht wieder zurück geschoben.
Habe Folgendes zur Methode ScrollablePanel.OnControlsChanged hinzugefügt:
C#-Quelltext 1: 2:
| if (panelInner.Bottom < this.Height) panelInner.Location = new Point(panelInner.Location.X, panelInner.Location.Y + Math.Min(Math.Abs(panelInner.Location.Y), this.Height - panelInner.Bottom)); |
|
|
|