AvaloniaUI / Avalonia

Develop Desktop, Embedded, Mobile and WebAssembly apps with C# and XAML. The most popular .NET UI client technology
https://avaloniaui.net
MIT License
26.16k stars 2.27k forks source link

RelativePanel does not update Layout in some situations: How do I a Control to e.g. RelativePanel.LeftOf="" in ViewModel // How do I change alignement in code behind? #10360

Closed timunie closed 1 year ago

timunie commented 1 year ago

Discussed in https://github.com/AvaloniaUI/Avalonia/discussions/10330

Originally posted by **NoizeDaemon** February 13, 2023 Hi! I've recently started using AvaloniaUI & I am also still pretty new to MVVM in general... I'm stuck on two things atm: ### 1) Is there a way to bind the Name of Controls/bind a reference to a control by Name? I'm trying to change relative positions in a `RelativePanel` from my ViewModel (I know thats probably not the MVVM way, so there's question 2): ``` ``` Binding a string `"R1"` to `LeftOf` does not work (it binds the string, but looking at the debugger `RelativePanel.LeftOf` takes the actual control as value, not the name). So is there a way I could reference a control by it's name from ViewModel (maybe by means of a ValueConverter?). Alternatively, can you combine multiple Bindings? There's binding to controls like `$parent[1]` - if I could do sth like `{Binding $parent[{Binding ChildIndex}]}`, that would solve my problem too 😅 Can the relative position even be changed at runtime? ### 2) What would be the correct MVVM way to do this? Eventually I want to bind an `ItemsControl` (with a `RelativePanel` as `ItemsPanel`) to a list of classes containing amongst others the relative positions to other items. So I'd start with R1 in the center of the panel, then add R2 to the right of R1, R3 on above R2, etc. Any help, tips or good ressources to read would be highly appreciated! ### Update: Trying to do this in code behind: ``` public partial class MainView : UserControl { private ItemsControl itemsControl; private List visualNumberItems; public MainView() { InitializeComponent(); visualNumberItems = new List(); } void NumberItemsChanged(object? sender, NotifyCollectionChangedEventArgs e) { visualNumberItems = itemsControl .GetLogicalDescendants() .OfType() .OfType() .ToList(); if (visualNumberItems.Count == 1) { RelativePanel.SetAlignVerticalCenterWithPanel(visualNumberItems[0], true); RelativePanel.SetAlignHorizontalCenterWithPanel(visualNumberItems[0], true); } else if (visualNumberItems.Count > 1) { RelativePanel.SetRightOf(visualNumberItems[visualNumberItems.Count - 1], visualNumberItems[visualNumberItems.Count - 2]); } } void NumberItemsControlLoaded(object? sender, RoutedEventArgs e) { itemsControl = (ItemsControl)sender; ((INotifyCollectionChanged)itemsControl.Items).CollectionChanged += NumberItemsChanged; } } ``` The values for the first Rectangle change, but do not visually update. The values for the other Rectangles don't even change (see Debugger screenshots). All the Rectangles are stuck in the upper left corner. Here's my new XAML: ``` ``` If I could get that to work, I could potentially change their position based on the Tag I set in my ViewModel... ![image](https://user-images.githubusercontent.com/42150677/218546867-a7285f77-7c3a-4f1b-ad65-53510716c9b9.png) ![image](https://user-images.githubusercontent.com/42150677/218546890-e0366e8b-8c05-44ac-8f61-71f5d8b0c80c.png) Also is there a way to get only the last added descendant/visual item? I only found options for the first or, like i did here, all of them...
timunie commented 1 year ago

I think I found a solution for the Bindings to work. I also noticed that if I set the ViewModel to late, the initial value will also not work. so from my understanding this bug is not only related to MultiConverter.